可能重复:
What is an easy way to tell if a list of words are anagrams of each other?
finding if two words are anagrams of each other
我写了下面的C代码来检查两个给定的字符串是否是彼此的字谜。 我知道这在复杂性/效率方面是最糟糕的,并且有很多更好的方法可以做到这一点。
#include "stdio.h"
main()
{
char s1[]="mist";
char s2[]="mitt";
int i,j,isanag=0;
if(strlen(s1)!=strlen(s2))
printf("Not anagrams\n");
for(i=0;i<strlen(s1);i++)
{
isanag=0;
for(j=0;j<strlen(s2);j++)
{
if(s1[i]==s2[j])
{
isanag = 1;
break;
}
}
if(isanag == 0)
{
printf("Not anagrams\n");
getch();
exit(0);
}
}
printf("Yes Anagrams\n");
getch();
}
这样可以正常工作并打印Not Anagrams,这是正确的 如果我交换两个字符串的名称,如下所示,它给出了错误的答案
char s1[]="mitt";
char s2[]="mist";
我知道2 for循环的编码方式很明显。
如何改进此代码并解决这个问题?
答案 0 :(得分:6)
只考虑小写字母,你可以制作2个长度为26的向量。
在它们两个中将所有位置设置为0,在第一个字符串(s1)中创建一个循环并增加向量中的位置:
int v1[26], v2[26], i;
for( i = 0; i < 26; i++)
v1[i] = v2[i] = 0;
for(i = 0; i < strlen(s1); i++)
v1[s1[i] - 'a']++; // 'a' would be on position 0, 'b' on position 1 and so on
for(i = 0; i < strlen(s2); i++)
v2[s2[i] - 'a']++;
在它之后你只需循环向量并查看字母数量是否不同
for(i = 0; i < 26; i++)
if(v1[i] != v2[i])
{
printf("Not anagrams");
exit(0);
}
printf("Anagrams");
但是如果你使用大写你可以制作4个向量,而对于新的向量减去'A'或者制作一个更大的向量并在你的代码中添加一些if ...我会让你尝试那个;)< / p>
答案 1 :(得分:3)
基于vmp的解决方案,您可以使用一个char数组[26]。
编辑:添加了一些代码(手头没有编译器,但概念应该没问题)
//lower case only
int isAnagram( char* left, char* right)
{
char theAlphabet[26];
memset( theAlphabet, 0, sizeof theAlphabet );
int length = strlen( left );
for( int i=0; ++i; i < length )
{
if ( 0 == right[i] )
{ //mismatching length
return 0;
}
++theAlphabet[ left[i] - 'a' ];
--theAlphabet[ right[ i ] - 'a' ];
}
if ( left[length] != 0
|| right[length] != 0 )
{
return 0;
}
for( int j=0; ++j; j < 26 )
{
if ( 0 != theAlphabet[j] )
{
return 0;
}
}
return 1; //yes it is an anagram
}
答案 2 :(得分:3)
@Goldenmean,这是另一个解决方案,它对两个字符串进行排序,然后对它们进行比较。像其他人讨论的字符计数会更有效,但这更有趣: - )
qsort
是一个标准库排序函数,它将函数comp
作为参数,并在重新排序列表时使用它来比较列表的元素(在本例中为字符串)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
static int comp(const void *a, const void *b)
{
const char *pa = a;
const char *pb = b;
return
(*pa > *pb) ? 1 :
(*pa < *pb) ? -1 :
0;
}
int main(int argc, char ** argv)
{
char s1[]="mits";
char s2[]="mist";
qsort(s1, strlen(s1), 1, comp);
qsort(s2, strlen(s2), 1, comp);
printf("%s : %s - %s\n", s1, s2, strcmp(s1, s2) ? "No" : "Yes");
return 0;
}
答案 3 :(得分:2)
您尚未编码重复字母的可能性。
取这两个字符串:
char s1[]="mitt";
char s2[]="mist";
对于第一个字符串中的每个字母,您的代码会检查第二个字符串中的每个字母,以查看是否有相同的字母。因此,让我们浏览第一个字符串并检查第二个字符串中的第一个相同的字母(这是您的代码所做的):
s1[0] ('m'): yes, at s2[0]
s1[1] ('i'): yes, at s2[1]
s1[2] ('t'): yes, at s2[3]
s1[3] ('t'): yes, at s2[3]
正如您所看到的,代码认为两个字符串是字谜,因为它将第一个字符串中的两个字母与第二个字母中的仅一个字母相匹配!
解决方案是在切入下一个字母之前“剪掉”你已经匹配过的字母;我会留给你代码!祝你好运。
编辑:当然,我忘了:如果代码成功地通过字符串1完成,从字符串2中删除字母,字符串2中还有字母,这意味着它们不是字谜! (在上面的示例中,'s'将保留在字符串2中。)
答案 4 :(得分:1)
很抱歉,但您的实施存在缺陷。这段代码:
for(j=0;j<strlen(s2);j++)
{
if(s1[i]==s2[j])
{
isanag = 1;
break;
}
只要求第二个字符串中的任何字符出现在第一个字符串中。
因为“mitt”的字母都在“mits”中,并且长度相同,所以它报告它们是字谜。反之则不然。
即使你在另一个方向重复检查,这仍然无效。
所以例如
mitttsson
missstton
将出现为anagrams,因为它们具有相同的长度,并且都由集合{m,i,t,s,o,n}生成。
您不仅要检查字符是否相等,还要检查它们在字符串中出现的次数。
这是一种(低效率,因为它计算重复重复的字母)变化:
for (i = 0; i < strlen(s1); i++)
{
int c = 0;
// How many times does character s1[i] occur in s1?
for (j = 0; j < strlen(s1); j++)
{
if (s1[i] = s1[j])
{
// Improvement: if j < i, it means we already checked this letter.
// so we might break here...
c++;
}
}
// improvement: if c is 0 here, it means we can 'continue' for this letter
// has been already checked before.
// Subtract how many times it occurs in s2.
for (j = 0; j < strlen(s2); j++)
{
if (s1[i] = s2[j])
c--;
}
// If occurrences are the same we expect difference to be 0.
if (c)
{
printf("Not anagrams\n");
break;
}
}
更新:最好的解决方案是完全改变算法,按照vmp或(甚至更好)马里奥的勺子。