我最近被要求设计一个算法来检查两个字符串是否是另一个的字谜。我的目标是尽量减少空间和时间的复杂性,所以我想出了这个算法:最小复杂度的字谜算法
- 创建一个26个元素的数组,每个元素初始化为零。
- 遍历第一个字符串,并为每个字符增加与该字符对应的数组元素。
- 遍历第二个字符串,并为每个字符递减与该字符对应的数组元素。
- 扫描阵列。如果所有元素均为0,则这两个字符串是字形。
但是,这个算法的时间复杂度是O(n),我不能想出一个复杂度较低的算法。有人知道吗?
我最近被要求设计一个算法来检查两个字符串是否是另一个的字谜。我的目标是尽量减少空间和时间的复杂性,所以我想出了这个算法:最小复杂度的字谜算法
但是,这个算法的时间复杂度是O(n),我不能想出一个复杂度较低的算法。有人知道吗?
你的算法是渐近最优的。不可能在比Ω(n)更好的时间内解决这个问题。为了看到这一点,假设存在一个可以在o(n)时间内解决问题的算法A(注意这里n是小数)。那么对于任何1>ε > 0时,存在一些n,使得对于至少为n的任何大小的输入,该算法必须在最多的n个步骤中终止。设置ε = 1/3,并考虑对于这个ε的前述n,长度至少为n的算法的任何输入。由于该算法可以查看两个字符串中的大多数字符的1/3,因此该函数必须有两个不同的输入,一个是一对字符,另一个不是,从而该算法查看每个输入字符的相同子集。然后该功能必须在每种情况下产生相同的输出,并且因此在至少一个输入上是错误的。我们已经达成矛盾,所以不存在这样的算法。
为了确保字符串是字符串,您需要比较整个字符串 - 那么它怎么会比o(n)更快?
好的......太空......我们可以以某种方式减少它吗? – garima 2011-03-29 09:01:32
不,对两个字符串使用一个数组似乎都需要最小的空间。 – MacGucky 2011-03-29 09:04:47
搞笑 - 我谷歌搜索和发现 - [stackoverflow](http://stackoverflow.com/questions/4236906/finding-if-two-words-are-anagrams-of-each-other)。找到的最佳解决方案与您提出的方法相同。 – MacGucky 2011-03-29 09:06:36
您可以在早期退出时改善平均表现。在扫描第二个字符串时,如果在递减之前count [char]为0,那么您没有anagram,可以停止扫描。
另外,如果字符串比26个字符短,那么在最后一步中,只检查第一个字符串中的字符为零。
这不会改变大O,但它可以将您的平均运行时间更改为低于建议解决方案的2N + 26的水平,具体取决于您的数据。
int anagram (char a[], char b[]) {
char chars[26];
int ana = 0;
int i =0;
for (i=0; i<26;i++)
chars[i] = 0;
if (strlen(a) != strlen(b))
return -1;
i = 0;
while ((a[i] != '\0') || (b[i] != '\0')) {
chars[a[i] - 'a']++;
chars[b[i] - 'a']--;
i++;
}
for (i=0; i<26;i++)
ana += chars[i];
return ana;
}
void main() {
char *a = "chimmy\0";
char *b = "yimmch\0";
printf ("Anagram result is %d.\n", anagram(a,b));
}
如果任何字符串包含字符“a..z”外的字符或者如果小写字母在执行字符集中不连续(对于ASCII为OK,但对于EBCDIC错误),则为未定义的行为。 – chqrlie 2017-08-08 16:51:25
测试'while((a [i]!='\ 0')||(b [i]!='\ 0'))'既冗余又不正确。你已经检查过,'a'和'b'具有相同的长度,如果'a [i]'是'''0',那么对字符[a [i] - 'a']'进行索引是不正确的,即使'b [i]'不是。 – chqrlie 2017-08-08 16:53:11
最后一个循环不验证所有字母都有零计数......事实上,数组元素的总和总是为0。 – chqrlie 2017-08-08 16:54:21
我不是这方面的专家,但是不是O(n)对于像这样的东西已经非常高效了吗?我看到的唯一缺陷是你将难以处理“über”和“rübe”,因为你仅限于拉丁字符(但如果这是一个先决条件,那么没关系)。 – DarkDust 2011-03-29 09:01:39