程序如何计算两个字符串之间共有的不同字符数?
例如,如果s1="connect"
和s2="rectangle"
,则计数显示为5,但正确答案为4;重复字符只能计数一次。
如何修改此代码以使计数正确?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int i,j,count=0;
char s1[100],s2[100];
scanf("%s",s1);//string 1 is inputted
scanf("%s",s2);//string 2 is taken as input
for(i=1;i<strlen(s1);i++)
{
for(j=1;j<strlen(s2);j++)
{
if(s1[i]==s2[j])//compare each char of both the strings to find common letters
{
count++;//count the common letters
break;
}
}
}
printf("%d",count);//display the count
}
程序将两个字符串作为输入并显示这些字符串中的公共字符数。请让我知道这段代码有什么问题。
答案 0 :(得分:2)
如果必须忽略重复字符,则程序必须“记住”已经遇到的字符。您可以通过将已处理的字符存储到一个字符数组中,然后在处理其他字符时查阅该数组来做到这一点。
您可以使用计数器变量来跟踪常见字符的数量,例如
int ctr=0;
char s1[100]="connect", s2[100]="rectangle", t[100]="";
在这里,t
是将存储检查的字符的字符数组。使其大小与其他2个字符数组中最大的字符大小相同。
现在使用像这样的循环
for(int i=0; s1[i]; ++i)
{
if(strchr(t, s1[i])==NULL && strchr(s2, s1[i])!=NULL)
{
t[ctr++]=s1[i];
t[ctr]=0;
}
}
t
最初是一个空字符串。通过循环的主体将先前在t
中不存在的字符添加到循环中,只有当要检查的字符(即s1[i]
)不在t
中但只有出现在另一个字符串(即s2
)中。
strchr()
是带有原型的函数
char *strchr( const char *str, int c );
strchr()
在str
指向的字符串中找到c的第一个匹配项。如果NULL
中不存在c
,则返回str
。
您使用scanf()
可能会引起麻烦。
使用
scanf("%99s",s1);
(其中99比数组s1
的大小小1)而不是
scanf("%s",s1);
以防止溢出问题。然后检查scanf()
的返回值,看看它是否为1
。 scanf()
返回其成功分配的次数。
或使用fgets()
读取字符串。
阅读this帖子以了解有关此内容的更多信息。
请注意,数组索引从0
开始。因此,在循环中,不会检查字符串的第一个字符。
所以应该是这样的
for(i=0;i<strlen(s1);i++)
代替
for(i=1;i<strlen(s1);i++)
答案 1 :(得分:1)
这是一种避免二次O(N²)或三次O(N³)时间算法的解决方案-它是线性时间,需要对每个输入字符串中的每个字符进行一次访问。该代码使用一对常量字符串,而不要求用户输入。另一种选择是从命令行获取两个参数并进行比较。
#include <limits.h>
#include <stdio.h>
int main(void)
{
int count = 0;
char bytes[UCHAR_MAX + 1] = { 0 };
char s1[100] = "connect";
char s2[100] = "rectangle";
for (int i = 0; s1[i] != '\0'; i++)
bytes[(unsigned char)s1[i]] = 1;
for (int j = 0; s2[j] != '\0'; j++)
{
int k = (unsigned char)s2[j];
if (bytes[k] == 1)
{
bytes[k] = 0;
count++;
}
}
printf("%d\n",count);
return 0;
}
第一个循环通过将s1
数组的适当元素设置为bytes
来记录1
中存在哪些字符。字符串中是否有重复的字符都没关系。
第二个循环检测s2
中的某个字符何时位于s1
中,而之前从未在s2
中看到该字符,然后都递增count
并将该字符标记为通过将bytes
中的条目设置回0
,“不再相关”。
最后,它显示计数— 4
(末尾带有换行符)。
如果平台上的普通(unsigned char)
类型是带符号类型并且输入字符串中的任何字节在0x80..0xFF范围内(等效),则必须使用char
强制转换(如果已签名-128..-1
类型,则为char
)。使用否定下标不会带来幸福。该代码还假定您使用的是单字节代码集,而不是多字节代码集(例如UTF-8)。如果您要处理多字节字符,则计数将关闭。
问题中的代码至少是二次算法,因为对于s1
中的每个字符,它可能会逐步遍历s2
中的所有字符,只是发现它没有发生。仅此一项就需要O(N²)时间。这两个循环还使用基于strlen(s1)
或strlen(s2)
的条件,如果优化器无法识别每次返回的值相同,则代码可以在每个循环的每次迭代中扫描每个字符串
类似地,由于我输入的其他两个答案(Answer 1和Answer 2)中的代码,由于它们的循环结构,它们的平方也是二次或更差的。
在每个字符串100个字符的范围内,您可能不会轻易发现差异,尤其是在单次计数迭代中。如果字符串更大(数千个或数百万个字节)并且重复执行计数,那么线性算法和二次(或更差)算法之间的差异将更大并且更易于检测。
我也曾用Big-O表示法玩得很快。我假设N是字符串的大小,并且它们的大小足够类似于将N₁(s1
的长度)近似等于N 2(s2
的长度)不会是一个大问题。 “二次”算法可能更正式地表示为O(N₁•N 2),而线性算法为O(N₁+ N 2)。
答案 2 :(得分:0)
根据您期望的输出,您应该跟踪第二个字符串中使用的字符。您可以按照以下步骤实现:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int i, j, count = 0, skeep;
char s1[100], s2[100], s2Used[100]{0};
scanf("%s", s1); //string 1 is inputted
scanf("%s", s2); //string 2 is taken as input
for (i = 0; i<strlen(s1); i++)
{
skeep = 0;
for (j = 0; j < i; j++)
{
if (s1[j] == s1[i])
{
skeep = 1;
break;
}
}
if (skeep)
continue;
for (j = 0; j<strlen(s2); j++)
{
if (s1[i] == s2[j] && s2Used[j] == 0) //compare each char of both the strings to find common letters
{
//printf("%c\n", s1[i]);
s2Used[j] = 1;
count++;//count the common letters
break;
}
}
}
printf("%d", count);//display the count
}