如何检查2个数字是否有相同的数字和长度?

时间:2017-12-13 16:43:33

标签: algorithm optimization numbers

以下是我编写的2种算法,以确定2个数字是否具有相同的数字和长度。例如:

  • 12& 21具有相同的数字和相同的长度,因此输出将为真
  • 12& 121具有相同的数字但不是相同的长度,因此输出将为假

如果有任何不明确的地方,请发表评论,我会添加更多细节。

问题是:有没有更好的方法来进行此项检查?在任何方面都更好:效率(时间和/或空间),代码可读性,角落案件处理等。例如,第一种方法存在整数溢出的风险,但只要数字不大,可能是一种正常的方法,因为时间 - 复杂性是线性的。 感谢您的反馈。

  1. 哈希与素数:

    • 在这种方法中,我们使用前10个素数的静态数组作为辅助结构
    • 然后我们使用素数数组
    • 计算两个输入数的哈希数
    • 如果两个散列的值相同,则表示数字具有相同的数字和长度

      public static boolean haveSameDigitsAndLengthPrimes(int a, int b) { int[] primes = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29}; int hashA=1, hashB=1; while (a > 0) { hashA *= primes[a%10]; a /= 10; } while (b > 0) { hashB *= primes[b%10]; b /= 10; } return (hashA == hashB); }

  2. 计数数字方法:

    • 在这种方法中,我们使用大小为10的辅助数组(每个元素的初始值= 0)
    • 然后我们迭代这两个数字;这样做时,将第一个数字的数字增加1,第二个数字减1,
    • 在迭代后,如果任何一个数字仍然不为零,暗示它们的长度不一样
    • 如果辅助数组中的任何值不等于0,则表示2个数字不满足所需条件

      public static boolean haveSameDigitsAndLength(int a, int b) { int[] digits = new int[10]; for (int i=a; i>0; i=i/10) { ++digits[i%10]; } for (int i=b; i>0; i=i/10) { --digits[i%10]; } for (int digit : digits) { if (digit != 0) { return false; } } return true; }

    2.b中。计数数字方法:实施改进:

    public static boolean haveSameDigitsAndLength(int a, int b) { if ((a == 0 || b == 0) && a != b) { return false; } int[] digits = new int[10]; int i=a, j=b; for (; i>0 && j>0; i/=10, j/=10) { ++digits[i%10]; --digits[j%10]; } if (i != 0 || j != 0) { return false; } for (int digit : digits) { if (digit != 0) { return false; } } return true; }

  3. 测试案例:

    • 12,12 =>真
    • 12,21 =>真
    • 123,132 =>真
    • 123,1234 =>假
    • 10,1 =>假

4 个答案:

答案 0 :(得分:1)

我说的是第二种方法。您可以通过合并前两个循环来删除一个循环。

bool TestEqual(int a, int b) {
    int cnts[10] = {0}, i = a, j = b;
    for (; i && j; i /= 10, j /= 10) {
        cnts[i % 10]++;
        cnts[j % 10]--;
    }
    return !i && !j; 
    for (i = 0; i < 10; ++i) {
        if (cnts[i] != 0) break;
    }
    return i == 10;
}

我的C ++代码,但你理解逻辑。您的方法至少有两个好处。

  1. 您将仅迭代两个int s的最小长度。
  2. 如果长度不匹配,则不应检查counts位数。
  3. 删除一个循环。

答案 1 :(得分:1)

我可以建议其他一些次要优化,以改善空间,时间...可读性很简单。假设基数为10(十进制)!

1)首先检查数字计数。具有相同数字长度的两个随机数的机会很小。如果您有快速的DigitCheck方法,则不会浪费时间。 2)取消使用数组。我使用两个变量作为位字段。我使用简单的移位方法对每个数字中每个数字[0,..,9]的频率进行编码。 3)由于仅使用2个位域,因此我只需要进行一次比较即可确认所有频率相同或不相同!在伪代码中:

ulong encode += 1 << (LeastSignificantDigit(number) * 6)    // number % 10

我选择了6乘法器,因为6位可以安全地保存ulong中任何数字的最大频率。

public static bool IsDigitAnagram( this ulong a, ulong b )
{
    // CHECK equality of digit counts.
    if( Digits( a ) == Digits( b ) )
    {
        // CALCULATE the frequency of digits in each number.
        ulong encodeA = 0;
        ulong encodeB = 0;
        while( a != 0 )
        {
            encodeA += 1UL << ( ( int )LeastSignificantDigit( a ) * 6 );  // a % 10;
            a = ShiftRight( a );                                          // a /= 10;
            encodeB += 1UL << ( ( int )LeastSignificantDigit( b ) * 6 ); 
            b = ShiftRight( b );
        }
        // CONFIRM if the digit frequencies are identical in which case they are anagrams of each other.
        return ( encodeA == encodeB );
    }
    return ( false );
}

答案 2 :(得分:0)

在Python中,您可以:

bucket-owner-full-control

答案 3 :(得分:0)

我使用 Javascript 做了同样的事情。如果是线性时间,请检查并让我反馈您是否可以改进?

function sameFrequency(num1, num2) {
    let digits1 = num1.toString().split('');
    let digits2 = num2.toString().split('');

    if (digits1.length !== digits2.length) {
        return false;
    }

    let obj1 = {};
    let obj2 = {};

    for (const n of digits1) {
        obj1[n] = (obj1[n] || 0 ) + 1;
    }

    for (const n of digits2) {
        obj2[n] = (obj2[n] || 0 ) + 1;
    }

    for (const val in obj1) {
        if (!(val in obj2)) {
            return false
        }

        if (obj1[val] !== obj2[val]) {
            return false;
        }
    }

    return true
    
};

console.log(sameFrequency(181, 811));
console.log(sameFrequency(34, 14));
console.log(sameFrequency(182, 281));
console.log(sameFrequency(3589578, 5879385));
console.log(sameFrequency(22, 222));