[英]Resolving equal XOR values for different strings for anagram detection
最近,我遇到一個采訪問題,我必須編寫一個包含兩個字符串的函數,如果它們是彼此的字謎,它將返回1
,否則將返回0
。 為簡化起見,兩個字符串的長度相同,非空,並且僅包含小寫字母和數字字符。
我實現了一個函數,該函數獨立地累加每個字符串的每個字符的XOR值,然后比較每個字符串的最終XOR值以查看它們是否相等。 如果是,則返回1
,否則返回0
。
我的功能:
int isAnagram(char* str1, char* str2){
int xor_acc_1 = 0;
int xor_acc_2 = 0;
for(int i = 0; i<strlen(str1); i++){
xor_acc_1 ^= str1[i] - '0';
xor_acc_2 ^= str2[i] - '0';
}
return xor_acc_1 == xor_acc_2;
}
除一個測試用例外,我的功能適用於所有情況。
char* str1 = "123";
char* str2 = "303";
令我驚訝的是,即使這兩個字符串不是彼此的字詞,它們都返回48
作為其XOR值。
我的問題是:通過修改XOR背后的數學運算,是否仍可以在線性時間內使用XOR來解決問題,而無需使用數據結構(例如Map)?
純粹的xor
解決方案將不起作用,因為在此過程中會丟失信息(此問題也可能以其他形式的有損計算形式存在,例如散列)。 在這種情況下丟失的信息是用於比較的實際字符。
例如,考慮兩個字符串ae
和bf
(以ASCII表示):
a: 0110 0001 b: 0110 0010
e: 0110 0101 f: 0110 0110
---- ---- ---- ----
xor: 0000 0100 0000 0100
您可以看到兩個字符串的xor
或結果是相同的, 盡管它們完全不同。
一旦意識到與自己進行xor
任何值均為零,這可能變得更加明顯,這意味着在您的方案下,所有字符串(例如aa
, bb
, cc
, xx
等)都將被視為字謎。
因此,現在您已經將該方法確定為不合適的方法,因此您會想到很多選擇。
首先是簡單地對兩個字符串進行排序並進行比較。 一旦排序,它們將在每個字符的基礎上相同。 這將起作用,但是由於您幾乎肯定會使用比較樣式排序,因此不太可能提供您所請求的O(n)
時間復雜度。
第二個仍然允許您通過使用通常的交易時間“技巧”來滿足該要求。 您只需設置每個字符的計數(所有初始都為零),然后為第一個字符串中的每個字符增加其計數。
之后,對於第二個字符串中的每個字符, 減少其計數。
這是線性時間復雜度,如果在處理后將每個字符計數都設置為零,則字符串可以視為字謎。 僅當一個字符在一個字符串中的出現次數比另一字符串中的出現次數更多時,才會出現任何非零計數。
這實際上是一種計數排序 ,是一種非比較排序,這意味着它們不受這些排序的正常最小O(n log n)
時間復雜度的限制。
這種野獸的偽代碼是:
def isAnagram(str1, str2):
if len(str1) != len(str2): # Can also handle different lengths.
return false
dim count[0..255] = {0} # Init all counts to zero.
for each code in str1: # Increase for each char in string 1.
count[code]++
for each code in str2: # Decrease for each char in string 2.
count[code]--
for each code in 0..255:
if count[code] != 0: # Any non-zero means non-anagram.
return false
return true # All zero means anagram.
順便說一下,這里是一個完整的C測試程序,它說明了這個概念,盡管可以對#if
部分進行簡單的更改即可添加更多的寬度,但它能夠處理8位字符的寬度:
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <stdbool.h>
#if CHAR_BIT == 8
#define ARRSZ 256
#else
#error Need to adjust for unexpected CHAR_BIT.
#endif
static bool isAnagram(unsigned char *str1, unsigned char *str2) {
// Ensure strings are same size.
size_t len = strlen(str1);
if (len != strlen(str2))
return false;
// Initialise all counts to zero.
int count[ARRSZ];
for (size_t i = 0; i < sizeof(count) / sizeof(*count); ++i)
count[i] = 0;
// Increment for string 1, decrement for string 2.
for (size_t i = 0; i < len; ++i) {
count[str1[i]]++;
count[str2[i]]--;
}
// Any count non-zero means non-anagram.
for (size_t i = 0; i < sizeof(count) / sizeof(*count); ++i)
if (count[i] != 0)
return false;
// All counts zero means anagram.
return true;
}
int main(int argc, char *argv[]) {
if ((argc - 1) % 2 != 0) {
puts("Usage: check_anagrams [<string1> <string2>] ...");
return 1;
}
for (size_t i = 1; i < argc; i += 2) {
printf("%s: '%s' '%s'\n",
isAnagram(argv[i], argv[i + 1]) ? "Yes" : " No",
argv[i], argv[i + 1]);
}
return 0;
}
在一些合適的測試數據上運行它可以顯示出實際效果:
pax$ ./check_anagrams ' paxdiablo ' 'a plaid box' paxdiablo PaxDiablo \
one two aa bb aa aa '' '' paxdiablo pax.diablo
Yes: ' paxdiablo ' 'a plaid box'
No: 'paxdiablo' 'PaxDiablo'
No: 'one' 'two'
No: 'aa' 'bb'
Yes: 'aa' 'aa'
Yes: '' ''
No: 'paxdiablo' 'pax.diablo'
為什么首先需要進行XOR?
最簡單,最快的方法是按字符對字符串進行排序,然后比較兩者是否相等。 在這種情況下,如果您需要更快的排序算法,則可以使用計數排序來實現線性時間。
另一種方法是,您可以簡單地計算每個字符串中的字符數,然后檢查這些計數是否相等。
基於XOR的解決方案在正確性方面是不正確的。 最多可以對一個數字進行異或運算,不止一個字符組合,兩個不同字符串的字符/ ASCII碼的異或運算可能不會一直產生。 因此,對於相同的字符串,輸出將始終正確。 但是對於不同的字符串,輸出可能不一定總是正確的(錯誤肯定)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.