无论顺序如何,检查两个字符串是否包含相同的字符

时间:2017-05-02 22:11:35

标签: c arrays string

假设两个字符串的长度相等,是否可以使用C来了解它们共有多少个字符? 例如,如果我们输入FABBOL和LABTIF,程序应输出4.如果我们输入FABBOL和LABBIF,程序应输出5.

3 个答案:

答案 0 :(得分:1)

计算每个角色并进行检查。 像这样:

#include <stdio.h>
#include <string.h>

unsigned number_of_common(const char *s1, const char *s2){
    unsigned count[256] = {0};
    //Make it unsigned for use as subscript.
    const unsigned char *s = (const unsigned char*)s1;
    while(*s)
        ++count[*s++];

    unsigned common = 0;
    for(s = (const unsigned char*)s2; *s; ++s){
        if(count[*s]){
            ++common;
            --count[*s];
        }
    }
    return common;
}

int main(void){
    unsigned count[256];
    char string1[256], string2[256];

    printf("input string #1>");fflush(stdout);
    fgets(string1, sizeof string1, stdin);
    string1[strcspn(string1, "\n")] = 0;//chomp newline

    printf("input string #2>");fflush(stdout);
    fgets(string2, sizeof string2, stdin);
    string2[strcspn(string2, "\n")] = 0;
    printf("number of common character is %u\n", number_of_common(string1, string2));

    return 0;
}

答案 1 :(得分:1)

有很多方法。这是三个:

当被要求手工计算字符时,一种方法是模仿许多人(在他们的头上或纸上)做的事情。我们调用字符串s1s2。无论哪个都无关紧要,无论如何都会得到相同的结果。

Set Count = 0
For each character c in s1:
    If s2 contains c:
        Strike out the character in s2
        Set Count = Count + 1
End for
Return Count

请注意,s2之上的其中一个字符串已被修改 - 以避免在s2中多次出现同一字符(如果它在s1中出现多次)。这通常意味着您使用s2的临时副本,因此原始s2不会被破坏(并且可以是例如字符串文字;它们不能被修改)。 C有一个函数strchr(),可用于定位字符串是否包含特定字符;如果宽字符串包含特定的宽字符,则为函数wcschr()

算法方面,这具有 O(NM)时间复杂度,以及 O(N)空间复杂度,其中 N M 是两个字符串的长度。

对于普通(窄)字符串,另一种方法是创建两个字符计数数组 - 即带有CHAR_MAX - CHAR_MIN + 1元素的无符号整数数组 - 并计算每个字符的出现次数。结果是所有字符的总和,使用每个字符的较小计数。

如果字符串长度为 N M ,并且有 L 可能的字符,则此方法具有 O(max( N,M,L))时间复杂度,以及 O(L)空间复杂度。

您可以对每个字符串中的字符进行排序。订单本身并不重要,只要两者都相同。

从每个排序字符串中的第一个字符开始,并在每个排序字符串中的一个字符上保留一个索引(一个手指!)。从计数零开始,然后:

  • 如果一个字符在另一个字符之前,则跳过前一个字符,将该索引(手指)移动到下一个字符。

  • 如果一个或两个索引(手指)到达各自字符串的末尾,我们就完成了;返回计数。

  • 如果两个排序字符串中的索引指向相似的字符,则增加计数,并推进两个索引(手指)

这的时间复杂度为 O(max(N log N,M log M)),因为排序通常是通过比较排序完成的,并且最多只有时间复杂度 O(N log N)。如果你不想使原始字符串混乱,你可能需要 O(N + M)额外的空间。

可以使用基数排序来获得 O(max(N,M))时间复杂度(因为存在严格有限数量的唯一字符,并且基数排序不是比较基于排序),但除非字符串非常长,否则它将比实际中许多基于比较的排序慢。此外,基数排序通常需要相当多的额外空间(具体取决于实现的多少)。

这非常类似于删除已经考虑的字符,除了我们首先对字符重新排序,并通过移动相应的索引(手指)来“敲击”它们。

答案 2 :(得分:-1)

对字符串中的字符进行排序。然后......

Sudocode(这些日子对我来说c是一种只读语言):

int str1Idx = 0;
int str2Idx = 0;
int hitCount = 0;

while ( str1Idx < strlen( string1 ) )
{
    while ( str2Idx < strlen( string2 ) )
    {
        if ( string1[ str1Idx ] == string2[ str2Idx ] )
        {
            ++hitCount;
            ++str2Idx;
            break;
        }

        if ( string1[ str1Idx ] < string2[ str2Idx ] )
        {
            break;
        }

        ++str2Idx;       
    }

    ++str1Idx;
}

显然,我正在简化事情,因为这是c和排序甚至字符比较等事情比更现代的语言更多的工作,但这是它的要点。

你走在正确的轨道上;首先对字符进行排序,其余部分应该落实到位。