如何计算两个字符串之间共有的不同字符的数量?

时间:2018-07-28 14:51:44

标签: c

程序如何计算两个字符串之间共有的不同字符数?

例如,如果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

}

程序将两个字符串作为输入并显示这些字符串中的公共字符数。请让我知道这段代码有什么问题。

3 个答案:

答案 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()的返回值,看看它是否为1scanf()返回其成功分配的次数。

或使用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 1Answer 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
}