簡體   English   中英

檢查兩個數字是否相互排列?

[英]Checking whether two numbers are permutation of each other?

給定兩個數字 a, b 使得 1 <= a , b <= 10000000000 (10^10)。 我的問題是檢查它們中的數字是否相互排列。 最快的方法是什么? 我想過使用散列,但找不到任何合適的散列函數。 有什么建議?

例如 - 123 是 312 的有效排列

另外我不想對數字中的數字進行排序。

如果你的意思是數字的字符(例如1927和9721),那么(至少)有兩種方法。

如果允許排序,一種方法是簡單地將它們sprintf到兩個緩沖區,對緩沖區中的字符進行排序,然后查看字符串是否相等。

然而,考慮到您的願望,數字排序,另一種選擇是設立一個十元數組,初始設置為零的所有元素,然后處理在第一個號碼每個數字,增加相關的元素。

然后使用第二個數字執行相同操作但遞減。

如果,最后,它仍然全部為零,則數字是彼此的排列。

這是有效的,因為它是O(n)算法,其中n是兩個數字中的位數。 這種野獸的偽代碼如下:

def arePermutations (num1, num2):
    create array count, ten elements, all zero.
    for each digit in num1:
        increment count[digit]
    for each digit in num2:
        decrement count[digit]
    for each item in count:
        if item is non-zero:
            return false
    return true

在C中,以下完整程序說明了如何完成此操作:

#include <stdio.h>
#include <stdlib.h>

#define FALSE (1==0)
#define TRUE  (1==1)

int hasSameDigits (long num1, long num2) {
    int digits[10];
    int i;

    for (i = 0; i < 10; i++)      // Init all counts to zero.
        digits[i] = 0;

    while (num1 != 0) {           // Process all digits.
        digits[num1%10]++;        // Increment for least significant digit.
        num1 /= 10;               // Get next digit in sequence.
    }

    while (num2 != 0) {           // Same for num2 except decrement.
        digits[num2%10]--;
        num2 /= 10;
    }

    for (i = 0; i < 10; i++)
        if (digits[i] != 0)       // Any count different, not a permutation.
            return FALSE;

    return TRUE;                  // All count identical, was a permutation.
}

int main (int c, char *v[]) {
    long v1, v2;

    if (c != 3) {
        printf ("Usage: %s <number1> <number2>\n", v[0]);
        return 1;
    }

    v1 = atol (v[1]);
    v2 = atol (v[2]);
    if (hasSameDigits (v1, v2)) {
        printf ("%d and %d are permutations\n", v1, v2);
    } else {
        printf ("%d and %d are not permutations\n", v1, v2);
    }

    return 0;
}

簡單地傳遞兩個(正數)數字,假設它們適合long ,它會告訴你它們是否具有相同的數字計數。

a和b是anagrams,如果它們具有相同數量的每個數字。 所以基本上最快的方式似乎是,計算a和b的數字:

int c[10]={0,0,0,0,0,0,0,0,0,0}

while (a) { c[a%10]++; a/=10; }
while (b) { c[b%10]--; b/=10; }

int res=1;
for (int i=0;i<10;i++) res &= c[i]==0;
printf(res?"yes":"no");

是作業嗎?

計算每個數字的出現次數並進行比較,如果它們相同則可以使用排列將一個數字轉換為其他數字。

我在rossetacode.org上找到了這個相當有效的解決方案。 我希望你能原諒我用Java編寫它(我對C不滿意)但語法應該或多或少相同。

代碼首先檢查數字是否具有相同的位數,然后通過將它們轉換為總數來對數字求和。 除了移位距離乘以因子6.這使得較小的數字不可能與較大的數字組成相同的值。 例如,一個'9'將需要64次'8'來匹配其值,這顯然是不可能的。

此代碼假定為非負輸入。

boolean haveSameDigits(long n1, long n2) {
    long nn1 = n1, nn2 = n2;
    while (nn1 > 0 && nn2 > 0) {
        nn1 /= 10;
        nn2 /= 10;
    }
    if (nn2 != nn1) // not the same length
        return false;

    long total1 = 0, total2 = 0;
    while (n1 != 0) {
        total1 += 1L << ((n1 % 10) * 6);
        total2 += 1L << ((n2 % 10) * 6);
        n1 /= 10;
        n2 /= 10;
    }
    return total1 == total2;
}

創建一個數組:

int digitOccurances[2][10];

digitOccruances[X][N]存儲數字N出現在數字X中的次數。 因此,如果您將8675309與9568733進行比較,則陣列最終會如下所示:

{ { 1, 0, 0, 1, 0, 1, 1, 1, 1, 1 } , { 0, 0, 0, 2, 0, 1, 1, 1, 1, 1 } }

如果兩個數組相等,那么數字就是排列。

這是一個O(n)算法,所以漸漸地說這是最有效的算法(如果不至少檢查一次所有數字,你就無法解決這個問題。

如果數字具有不同的長度,則可以立即返回false,因此假設兩者的長度均為n。 填充數組需要2n次操作,然后完成10次比較才能讀取數組。 2n + 10是O(n)。

好吧,如果你可以構建一個80GB的表,你可以隨時做:

int64 table[10000000000] = {0, blah blah..., 9999999999};

if (table[a] == table[b]) ...

如果我從你的問題中正確理解了一個排列是元素的組合,這些元素不再重復。 因此,如果123是312的有效排列,那么也是如此

123,
213,
132,
321,
213, 

等等。

所以基於這個假設,假設你有兩個整數123456789和129837456.(為簡單起見,我也假設兩個數字的長度相等)。 如果您理解了這一點,那么您也可以檢查不同的排列和組合。

為此,您需要做的就是從給定數字中獲取單位的整數,例如:

Number 123456789 is
1 * 100000000 + 
2 * 10000000  +
3 * 1000000   +
4 * 100000    +
5 * 10000     +
6 * 1000      +
7 * 100       +
8 * 10        +
9 

要么

1 * power(10, 8) +
2 * power(10, 7) +
3 * power(10, 6) +
4 * power(10, 5) +
5 * power(10, 4) +
6 * power(10, 3) +
7 * power(10, 2) +
8 * power(10, 1) +
9 * power(10, 0) 

我實際上已經給你算法提示如何做到這一點,所以這很容易做到。 一旦完成,您將最終得到單獨的整數(更好地將這些值保存在數組中)

1, 2, 3, 4, 5, 6, 7, 8, 9

現在

對另一個給定的整數做同樣的事情,這樣你最終得到另一個整數數組

1, 2, 9, 8, 3, 7, 4, 5, 6

所以現在你需要檢查的是,如果第二個數組的所有整數都存在於第一個整數數組中,如果是,則它們是第一個數組或第一個數字的整數的排列。

我希望這有幫助。

您可以簡單地計算數字的平方和: 123 = (1 * 1) + (2 * 2) + (3 * 3)並將它們放在一起比較。 如果它們的平方和相同,則它們是彼此的有效排列。

{已編輯添加額外測試)

假設你在數字領域,那怎么樣

if 
(
    ('1' ^ '2' ^ '3' == '3' ^ '1' ^ '2') &&
    ('1' + '2' + '3' == '3' + '1' + '2')
)
{
    cout << "Yes\n";
}
else
{
    cout << "No\n";
}

不確定為什么你不想排序,除非這是你的家庭作業的條件。 對於那些在這個問題上磕磕絆絆的人來說,只是尋找最快(最pythonic!)的方法來測試兩個整數是否是Python中的排列

def arePermutations(a, b):
    return sorted([d for d in str(a)]) == sorted([d for d in str(b)])

這個解決方案在Python中的運行速度稍快,當然,依賴於測試的數字是相對較小的整數。 它對Project Euler問題52非常有效。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM