检查字符串是否包含相同数量的相同字符

时间:2018-08-28 12:09:15

标签: c

这是我们必须检查两个字符串是否包含相同字符(无论顺序如何)的问题。例如s1=akash s2=ashka匹配。 我的程序为每个输入字符串显示NOs1s2是两个输入字符串 t是测试用例的数量 ->如果您能告诉我我是初学者的错误在哪里,这将非常有帮助

#include<stdio.h>
#include<string.h>
int main(){
int t,i,j;
scanf("%d",&t);
while(t>0){
    char s1[100],s2[100];
    scanf("%s ",s1);
    scanf("%s",s2);
    int count=0;
    int found[100];
    for(i=0;i<strlen(s1)-1;i++){
        for(j=0;j<strlen(s1);j++){
            if(s1[i]==s2[j]){
                found[i]=1;
                break;
            }


        }
    }
       for(i=0;i<strlen(s1);i++){
           if(found[i]!=1){
          count=1;
          break;

           }
       }
    if(count==1)
    printf("NO");
    else
    printf("YES");

 t--;
}



}

6 个答案:

答案 0 :(得分:3)

上面的一些好的答案建议先对字符串进行排序。

如果要在上面修改程序以完成此工作,则需要按照自己的想法进行修改。我对下面的操作提出了一个建议(用言语)-之后,有一个经过修改的代码可以正常工作,最后还有几个要点。

我猜两个字符串aaa根据您的定义是不相等的,但是您的程序会说它们是相等的,因为一旦找到一个字符,您就无话可说了它已经被用完了

我建议您更改found[]数组,以便它记录第二个字符串中的字符何时匹配。

我建议如下逻辑。

遍历所有S1字符

|遍历S2字符

| -如果找到匹配标记,则将S2字符标记为

| -如果您在S2循环结束前仍未找到匹配项,那么您就完成了-它们不相等

在S1循环结束时,如果您还没有提前完成,则每个字符都将匹配,但是您需要通过found[]数组来检查是否已找到S2中的每个字符。

工作代码在下面。...

注释

  • 您没有初始化found-它在下面的代码中初始化

  • 第一个循环需要具有< strlen(s1)而不是< strlen(s1)-1

  • 您应该去的第二个循环strlen(s2)

  • 逻辑如上所述进行了更改,以便找到的记录字符在s2中找到而不是在s1

  • 逻辑也已更改,因此,如果未找到s1中的字符,则循环会提前中断。有测试可以查看循环是否提前中断,以查看ij的值是否是我们在循环结束时所期望的。

下面经过编辑的代码(在代码下方的底部是一些额外的注释)

#include<stdio.h>
#include<string.h>
int main(){
int t,i,j;
scanf("%d",&t);
while(t>0){
    char s1[100],s2[100];
    scanf("%s ",s1);
    scanf("%s",s2);
    int count=0;
    int found[100]={ 0 };
    for(i=0;i<strlen(s1);i++){
        for(j=0;j<strlen(s2);j++){
            if(found[j]==1) continue; // character S2[j] already found
            if(s1[i]==s2[j]){
                found[j]=1;
                break;
            }
        }
        if (j==strlen(s2)) {
            break;   // we get here if we did not find a match for S1[i]
        }
    }
    if (i!=strlen(s1)) {
        printf("NO"); // we get here if we did not find a match for S1[i]       
    } 
    else {
      // matched all of S1 now check S2 all matched
       for(i=0;i<strlen(s2);i++){
           if(found[i]!=1){
          count=1;
          break;

           }
       }
    if(count==1) {
      printf("NO"); 
   }
    else {
      printf("YES");
     }
 }
 t--;
}
return 0;
}

另外两个要点使您的代码更高效。

  • 首先,如@chux所建议,在循环条件中不使用strlen(s2)可能会更快。相反,您可以拥有for (j=0;s2[j];j++)。之所以可行,是因为字符串末尾的最后一个字符将具有值0,并且在C中,0的值意味着false ..在for循环中在逻辑语句为true时运行,而当逻辑语句为false时,循环停止。加快在循环中不使用strlen[s2]的速度,是因为编译器可能会在每次循环时决定计算strlen[s2],这意味着如果l2会计算l2s2的长度-因此,当您必须经过两个循环l1*l2时,strlen可能会算上l1*l2*l2步。

  • 其次,可以通过检查两个字符串的长度是否不同,然后再检查它们是否包含相同数量的相同类型的字符来加快许多测试的速度。

答案 1 :(得分:2)

正如我的评论中所建议的那样,由于现在更加清晰了,比较两个以字符串表示的多重集的简单方法是:

  1. 对两个字符串进行排序(使用qsort()标准函数很容易)
  2. 比较结果(使用strcmp()标准函数)

这将起作用,因为在比较之前它将“ akash”和“ ashka”都映射到“ aahks”。

答案 2 :(得分:1)

使用冒泡排序或其他任何技术对两个字符串进行排序。您知道,然后只需使用strcmp()函数对两个字符串进行补偿。

答案 3 :(得分:1)

首先,请注意,found从未初始化。其中的值未知。应该在每次相等性测试之前通过将每个元素设置为零来初始化它。 (或者,如果不是每个元素,则每个元素最多为strlen(s1)-1,因为将要使用这些元素。)

found一旦初始化,就会出现另一个问题。

i上的第一个循环使用for(i=0;i<strlen(s1)-1;i++)。如果找到与found[i]的匹配项,则在其中设置s1[i]。请注意,i永远不会到达循环strlen(s1)-1,因为循环会在循环结束时终止。

i上的第二个循环使用for(i=0;i<strlen(s1);i++)。在此循环内,测试found[i]是否已设置。请注意,i确实到达了strlen(s1)-1,因为循环仅在i到达strlen(s1)时才终止。但是,found[strlen(s1)-1]永远不会被第一个循环设置,因为i从未在第一个循环中到达strlen(s1)-1。因此,第二个循环将始终报告失败。

此外,不清楚并且仅当两个字符串是字谜(是否可以将一个字符重新排列以形成另一个字符串,而无需添加或删除任何字符)时,还是如果其中的每个字符,才应将两个字符串视为相等?在另一个字符串中至少找到一个字符串(“ aaabbc”等于“ abbccc”,因为两个字符串都包含a,b和c)。

按照所写,已修复初始化和循环错误,程序将测试第一个字符串中的每个字符是否出现在第二个字符串中。这不是等效关系,因为它不是自反的:它不会测试第二个字符串中的每个字符是否出现在第一个字符串中。因此,您需要更多地考虑要测试的属性以及如何对其进行测试。

答案 4 :(得分:1)

for(i=0;i<strlen(s1)-1;i++){
    for(j=0;j<strlen(s1);j++){
        if(s1[i]==s2[j]){
            found[i]=1;
            break;
        }


    }
}

我无法理解您为什么使用j<strlen(s1)是第二循环。

我认为简单的解决方案是按字母顺序对字符进行排序,然后在单个循环中一一比较。

答案 5 :(得分:0)

我作为培训做过的复杂解决方案。下面的一个宏控制着两个实现。
第一个实现循环遍历字符串中的每个字符,计算它在第一个字符串和第二个字符串中的计数,然后比较值。
第二种实现为每个字符串分配并创建一个带有计数的字符映射,然后比较这些映射。

#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include <stdlib.h>
#include <errno.h>

// configuration
#define STRCHARSETCNTCMP_METHOD_FOREACH  0
#define STRCHARSETCNTCMP_METHOD_MAP      1
// eof configuration

//#define dbgln(fmt, ...)  fprintf(stderr, "%s:%d: " fmt "\n", __func__, __LINE__, ##__VA_ARGS__)
#define dbgln(...)  ((void)0)


/**
 * STRing CHARacter SET CouNT CoMPare
 * compare the count of set of characters in strings
 * @param first string
 * @param the other string
 * @ret true if each character in s1 is used as many times in s2
 */
bool strcharsetcntcmp(const char s1[], const char s2[]);


// Count how many times the character is in the string
size_t strcharsetcntcmp_count(const char s[], char c)
{
    assert(s != NULL);
    size_t ret = 0;
    while (*s != '\0') {
        if (*s == c) {
            ++ret;
        }
        *s++;
    }
    return ret;
}

// foreach method implementation
bool strcharsetcntcmp_method_foreach(const char s1[], const char s2[])
{
    const size_t s1len = strlen(s1);
    const size_t s2len = strlen(s2);
    if (s1len != s2len) {
        return false;
    }
    for (size_t i = 0; i < s1len; ++i) {
        const char c = s1[i];
        const size_t cnt1 = strcharsetcntcmp_count(s1, c);
        const size_t cnt2 = strcharsetcntcmp_count(s2, c);
        // printf("'%s','%s' -> '%c' -> %zu %zu\n", s1, s2, c, cnt1, cnt2);
        if (cnt1 != cnt2) {
            return false;
        }
    }
    return true;
}


// array of map elements
struct strcharsetcntcmp_map_s {
    size_t cnt;
    struct strcharsetcntcmp_map_cnt_s {
        char c;
        size_t cnt;
    } *map;
};

// initialize empty map
void strcharsetcntcmp_map_init(struct strcharsetcntcmp_map_s *t)
{
    assert(t != NULL);
    dbgln("%p", t);
    t->map = 0;
    t->cnt = 0;
}

// free map memory
void strcharsetcntcmp_map_fini(struct strcharsetcntcmp_map_s *t)
{
    assert(t != NULL);
    dbgln("%p %p", t, t->map);
    free(t->map);
    t->map = 0;
    t->cnt = 0;
}

// get the map element for character from map
struct strcharsetcntcmp_map_cnt_s *strcharsetcntcmp_map_get(const struct strcharsetcntcmp_map_s *t, char c)
{
    assert(t != NULL);
    for (size_t i = 0; i < t->cnt; ++i) {
        if (t->map[i].c == c) {
            return &t->map[i];
        }
    }
    return NULL;
}

// check if the count for character c was already added into the map
bool strcharsetcntcmp_map_exists(const struct strcharsetcntcmp_map_s *t, char c)
{
    return strcharsetcntcmp_map_get(t, c) != NULL;
}

// map element into map, without checking if it exists (only assertion)
int strcharsetcntcmp_map_add(struct strcharsetcntcmp_map_s *t, char c, size_t cnt)
{
    assert(t != NULL);
    assert(strcharsetcntcmp_map_exists(t, c) == false);
    dbgln("%p %p %zu %c %zu", t, t->map, t->cnt, c, cnt);
    void *pnt = realloc(t->map, sizeof(t->map[0]) * (t->cnt + 1));
    if (pnt == NULL) {
        return -errno;
    }
    t->map = pnt;
    t->map[t->cnt].c = c;
    t->map[t->cnt].cnt = cnt;
    t->cnt++;
    return 0;
}

// create map from string, map needs to be initialized by init and needs to be freed with fini
int strcharsetcntcmp_map_parsestring(struct strcharsetcntcmp_map_s *t, const char s[])
{
    assert(t != NULL);
    assert(s != NULL);
    int ret = 0;
    while (*s != '\0') {
        const char c = *s;
        if (!strcharsetcntcmp_map_exists(t, c)) {
            const size_t cnt = strcharsetcntcmp_count(s, c);
            ret = strcharsetcntcmp_map_add(t, c, cnt);
            if (ret != 0) {
                break;
            }
        }
        ++s;
    }
    return ret;
}

// compare two maps if they have same sets of characters and counts
bool strcharsetcntcmp_cmp(const struct strcharsetcntcmp_map_s *t, const struct strcharsetcntcmp_map_s *o) 
{
    assert(t != NULL);
    assert(o != NULL);
    if (t->cnt != o->cnt) {
        return false;
    }
    for (size_t i = 0; i < t->cnt; ++i) {
        const char c = t->map[i].c;
        const size_t t_cnt = t->map[i].cnt;
        struct strcharsetcntcmp_map_cnt_s *o_map_cnt = strcharsetcntcmp_map_get(o, c);
        if (o_map_cnt == NULL) {
            dbgln("%p(%zu) %p(%zu) %c not found", t, t->cnt, o, o->cnt, c);
            return false;
        }
        const size_t o_cnt = o_map_cnt->cnt;
        if (t_cnt != o_cnt) {
            dbgln("%p(%zu) %p(%zu) %c %zu != %zu", t, t->cnt, o, o->cnt, c, t_cnt, o_cnt);
            return false;
        }
        dbgln("%p(%zu) %p(%zu) %c %zu", t, t->cnt, o, o->cnt, c, t_cnt);
    }
    return true;
}

// map method implementation
bool strcharsetcntcmp_method_map(const char s1[], const char s2[])
{
    struct strcharsetcntcmp_map_s map1;
    strcharsetcntcmp_map_init(&map1);
    if (strcharsetcntcmp_map_parsestring(&map1, s1) != 0) {
        abort(); // <insert good error handler here>
    }

    struct strcharsetcntcmp_map_s map2;
    strcharsetcntcmp_map_init(&map2);
    if (strcharsetcntcmp_map_parsestring(&map2, s2) != 0) {
        abort(); // <insert good error handler here>
    }

    const bool ret = strcharsetcntcmp_cmp(&map1, &map2);

    strcharsetcntcmp_map_fini(&map1);
    strcharsetcntcmp_map_fini(&map2);

    return ret;
}

bool strcharsetcntcmp(const char s1[], const char s2[])
{
    assert(s1 != NULL);
    assert(s2 != NULL);
#if STRCHARSETCNTCMP_METHOD_FOREACH
    return strcharsetcntcmp_method_foreach(s1, s2);
#elif STRCHARSETCNTCMP_METHOD_MAP
    return strcharsetcntcmp_method_map(s1, s2);
#endif
}

// unittests. Should return 0
int strcharsetcntcmp_unittest(void)
{
    struct {
        const char *str1;
        const char *str2;
        bool eq;
    } const tests[] = {
        { "", "", true, },
        { "a", "b", false, },
        { "abc", "bca", true, },
        { "aab", "abb", false, },
        { "aabbbc", "cbabab", true, },
        { "123456789012345678901234567890qwertyuiopqwertyuiopasdfghjklasdfghjklzxcvbnmzxcvbnm,./;", "123456789012345678901234567890qwertyuiopqwertyuiopasdfghjklasdfghjklzxcvbnmzxcvbnm,./;", true },
    { "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", true },
    { "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678900", false },
    };
    int ret = 0;
    for (size_t i = 0; i < sizeof(tests)/sizeof(tests[0]); ++i) {
        const bool is = strcharsetcntcmp(tests[i].str1, tests[i].str2);
        if (is != tests[i].eq) {
            fprintf(stderr, 
            "Error: strings '%s' and '%s' returned %d should be %d\n", 
            tests[i].str1, tests[i].str2, is, tests[i].eq);
            ret = -1;
        }
    }
    return ret;
}

int main()
{
    return strcharsetcntcmp_unittest();
}