在两个字符串中查找常见字符

时间:2014-02-09 09:45:29

标签: c++ c string

我正在编码我们需要计算两个字符串中常见字符数的问题。计数的主要部分就像这样

for(i=0; i < strlen(s1); i++) {
    for(j = 0; j < strlen(s2); j++) {
        if(s1[i] == s2[j]) {
            count++;
            s2[j] = '*';
            break;
        }
    }
}

这与O(n ^ 2)逻辑有关。但是,我想不出比这更好的解决方案。任何人都可以用O(n)逻辑帮助我编码。

13 个答案:

答案 0 :(得分:9)

这很简单。取两个int数组freq1freq2。将其所有元素初始化为0。然后读取您的字符串并将字符的频率存储到这些数组中。然后比较数组freq1freq2以找到常见字符。

答案 1 :(得分:5)

可以在O(n)时间内以恒定的空间完成。

伪代码如下:

int map1[26], map2[26];
int common_chars = 0;

for c1 in string1:
    map1[c1]++;

for c2 in string2:
    map2[c2]++;

for i in 1 to 26:
    common_chars += min(map1[i], map2[i]);

答案 2 :(得分:3)

由于O(n)strlen s,您当前的代码为O(n ^ 3)并产生不正确的结果,例如“aa”,“aa”(您的代码将返回4)。

此代码在O(n)中计算共同的字母(每个字母最多计算一次)。

int common(const char *a, const char *b) {
    int table[256] = {0};
    int result = 0;
    for (; *a; a++)table[*a]++;
    for (; *b; b++)result += (table[*b]-- > 0);
    return result;
}

根据您如何定义“共同字母”,您可能有不同的逻辑。这里是我正在使用的定义的一些测试用例(这是multiset交集的大小)。

int main(int argc, char *argv[]) {
    struct { const char *a, *b; int want; } cases[] = {
        {"a", "a", 1},
        {"a", "b", 0},
        {"a", "aa", 1},
        {"aa", "a", 1},
        {"ccc", "cccc", 3},
        {"aaa", "aaa", 3},
        {"abc", "cba", 3},
        {"aasa", "asad", 3},
    };
    int fail = 0;
    for (int i = 0; i < sizeof(cases) / sizeof(*cases); i++) {
        int got = common(cases[i].a, cases[i].b);
        if (got != cases[i].want) {
            fail = 1;
            printf("common(%s, %s) = %d, want %d\n",
                   cases[i].a, cases[i].b, got, cases[i].want);
        }
    }
    return fail;
}

答案 3 :(得分:1)

你可以用2n:

来做
int i,j, len1 = strlen(s1), len2 = strlen(s2);
unsigned char allChars[256] = { 0 };
int count = 0;

for( i=0; i<len1; i++ )
{
    allChars[ (unsigned char) s1[i] ] = 1;
}

for( i=0; i<len2; i++ )
{
    if( allChars[ (unsigned char) s1[i] ] == 1 )
    {
        allChars[ (unsigned char) s2[i] ] = 2;
    }
}

for( i=0; i<256; i++ )
{
    if( allChars[i] == 2 )
    {
        cout << allChars[i] << endl;
        count++;
    }
}

答案 4 :(得分:1)

以下代码仅遍历每个sting一次。所以复杂性是O(n)。其中一个假设是上下案例被认为是相同的。

 #include<stdio.h>

int main() {
    char a[] = "Hello world";
    char b[] = "woowrd";
    int x[26] = {0};
    int i;
    int index;

    for (i = 0; a[i] != '\0'; i++) {
        index = a[i] - 'a';
        if (index > 26) {
            //capital char
            index = a[i] - 'A';
        }
        x[index]++;
    }

    for (i = 0; b[i] != '\0'; i++) {
        index = b[i] - 'a';
        if (index > 26) {
            //capital char
            index = b[i] - 'A';
        }

        if (x[index] > 0)
            x[index] = -1;
    }

    printf("Common characters in '%s' and '%s' are ", a, b);
    for (i = 0; i < 26; i++) {
        if (x[i] < 0)
            printf("%c", 'a'+i);
    }
    printf("\n");
}

答案 5 :(得分:1)

int count(string a, string b) 
{

   int i,c[26]={0},c1[26]={};

   for(i=0;i<a.length();i++)
   {
        if(97<=a[i]&&a[i]<=123)
        c[a[i]-97]++;
   }
   for(i=0;i<b.length();i++)
   {
       if(97<=b[i]&&b[i]<=123)
        c1[b[i]-97]++;
    } 
    int s=0;
    for(i=0;i<26;i++)
    {
        s=s+abs(c[i]+c1[i]-(c[i]-c1[i]));

    }   

    return (s);  
}

这是更容易和更好的解决方案

答案 6 :(得分:0)

for (std::vector<char>::iterator i = s1.begin(); i != s1.end(); ++i)
{
    if (std::find(s2.begin(), s2.end(), *i) != s2.end())
   {
    dest.push_back(*i);
   }
}

取自here

答案 7 :(得分:0)

C实现在O(n)时间和常量空间中运行。

var update = require('react-addons-update');

this.setState(function(previousState, currentProps) {
    var newState = update(previousState,{
        order: {
            brand: {
                $set: 'some new value'
            }
        }
    });

    return newState;
});

}

答案 8 :(得分:0)

首先,你的代码不能在O(n ^ 2)中运行,它在O(nm)中运行,其中n和m是每个字符串的长度。

你可以在O(n + m)中完成,但不是更好,因为你必须经历每个字符串,至少一次,看看两个字符是否同时存在。

C ++中的一个例子,假设:

  • ASCII字符
  • 包括所有字符(字母,数字,特殊,空格等......)
  • 区分大小写

std::vector<char> strIntersect(std::string const&s1, std::string const&s2){

    std::vector<bool> presents(256, false);  //Assuming ASCII
    std::vector<char> intersection;

    for (auto c : s1) {
        presents[c] = true;
    }
    for (auto c : s2) {
        if (presents[c]){
            intersection.push_back(c);
            presents[c] = false;
        }
    }
    return intersection;
}

int main() {
    std::vector<char> result; 
    std::string s1 = "El perro de San Roque no tiene rabo, porque Ramon Rodriguez se lo ha cortado";
    std::string s2 = "Saint Roque's dog has no tail, because Ramon Rodriguez chopped it off";

    //Expected: "S a i n t   R o q u e s d g h l , b c m r z p"

    result = strIntersect(s1, s2);
    for (auto c : result) {
         std::cout << c << " ";
    }
    std::cout << std::endl;

    return 0;
}

答案 9 :(得分:0)

它们是c ++中更好的版本: C ++位集及其应用 位集是布尔数组,但是每个布尔值都没有单独存储,而是通过位空间优化空间,使得每个布尔仅占用1位空间,因此位集bs占用的空间小于布尔bs [N]和向量bs( N)。但是,位集的限制是,在编译时必须知道N,即常量(矢量和动态数组没有此限制)

由于位集以压缩方式存储相同的信息,因此对位集的操作比对数组和向量的操作要快。我们可以借助数组索引运算符[]来单独访问位集的每个位,即bs [3]就像简单数组一样显示位集bs的索引3处的位。请记住,bitset开始向后索引,即10110,0位于第0和第3个索引,而1位于第1第2和第4索引。 我们可以通过构造函数使用整数和二进制字符串构造一个位集,如下面的代码所示。位集的大小在编译时是固定的,即无法在运行时更改。 有关位集的更多信息,请访问网站:https://www.geeksforgeeks.org/c-bitset-and-its-application

代码如下:

    // considering the strings to be of lower case.

    int main()
    {
        string s1,s2;
        cin>>s1>>s2;

        //Declaration for bitset type variables
        bitset<26> b_s1,b_s2;

        // setting the bits in b_s1 for the encountered characters of string s1 
        for(auto& i : s1)
        {
          if(!b_s1[i-'a'])
            b_s1[i-'a'] = 1;
        }

        // setting the bits in b_s2 for the encountered characters of string s2 
        for(auto& i : s2)
        {
          if(!b_s2[i-'a'])
            b_s2[i-'a'] = 1;
        }

       // counting the number of set bits by the "Logical AND"  operation
       // between b_s1 and b_s2
       cout<<(b_s1&b_s2).count(); 

     }

答案 10 :(得分:0)

无需初始化并保留26个元素的数组(字母中每个字母的数字)。只需执行以下操作:

  1. 使用HashMap存储字母作为键,而整数则将计数作为值。
  2. 创建一组字符。
  3. 遍历每个字符串字符,从步骤2开始添加到Set中。如果add()方法返回false(表示Set中已经存在相同字符),则将该字符添加到映射中并增加值。 / li>

这些步骤是在考虑Java编程语言的情况下编写的。

答案 11 :(得分:0)

Python代码:

    >>>s1='abbc'    
    >>>s2='abde'
    >>>p=list(set(s1).intersection(set(s2)))
    >>print(p)
    ['a','b']

希望这对您有帮助,快乐编码!

答案 12 :(得分:-1)

可以使用“捕获”的概念轻松完成,这是一种散列的子算法。