【问题标题】:how do I correct this code to check for anagrams?如何更正此代码以检查字谜?
【发布时间】:2017-10-27 23:14:52
【问题描述】:
#include <stdio.h>

main()
{
    char *a = "stack";
    char *b = "cats";
    int l = 0;  // for length of string b 
    clrscr();
    while (*b != NULL) 
        {
            l++;
            b++;
        }
    b--; // now b points to last char of the string 
    // printf("%d\n", l);
    while ((*a - *b == 32) || (*a == *b))
        {
            printf("%c %c\n", *a, *b);
            a++;
            b--;
            l--;
            if (l == 0)
                break;
        }
    l == 0 ? printf("anagrams") : printf("not anagrams");
    getch();
}

我编写了代码来检查两个字符串 a 和 b 是否是字谜。

b的长度比a短并且是a的子串时,代码显示误报

例如。 b 是 "cats" 反过来是 "stac" 而 a 是 "stack" 代码将 a 和 b 显示为字谜

【问题讨论】:

  • 检查它们是否具有相同的strlen?
  • 这不是检查字谜,它只是检查子串,对吧?如果字母的顺序不同,它就行不通。检查长度的差异,就像 kaylum 说的那样,然后你可以用于字谜的一个技巧是按字母顺序对两个字符串进行排序,然后比较它们。如果它们是字谜,它们将是相等的。
  • 检查字谜的简单方法是使用一对组成 subject 的字符频率数组(例如,[a-zA-Z0-9] 需要 62-元素数组)并出现在建议的 anagram 中。如果 subject 的频率数组与建议的 anagram 的频率数组相同,那么您就有一个实际的 anagram 填充每个频率数组后,它是if (memcmp (subfreq, anafreq, nelem * sizeof *subfreq) == 0) {...it's an anagram...} 的简单问题,这允许您跳过空格等。例如nag a ram 是主题词anagram 的变位词。

标签: c string pointers c-strings anagram


【解决方案1】:

一些用于检查两个字符串是否是彼此的字谜的伪代码(使用您的变量名):

if (strlen(a) != strlen(b))
    // Not an anagram
    return

char *a_sorted = sort_chars(a)
char *b_sorted = sort_chars(b)

// Once the characters in each word are re-arranged in alphabetical
// order, we can just test for equality. Anagrams will be equal
// (Note that this will not work on multi-word strings with differing
// numbers of whitespace characters)
if (strcmp(a_sorted, b_sorted) == 0)
    // Anagram!
else
    // Not an anagram

这里真正的工作是在sort_chars(in) 函数中,它按字母顺序对in 字符串中的字符进行排序,并返回一个指向包含已排序字符的新字符串的指针。使用字符的数字 ASCII 值(它们已经按字母顺序排列,是的,有人正在做某事!),像 bubble sort (或任何其他你想使用的排序算法)应该可以正常工作。

【讨论】:

    【解决方案2】:

    首先,您正在编写的代码看起来更像是在尝试检查两个单词是否为回文。如果这是您的意图,您将获取较小字符串的长度,使 l 在看到 a 的最后一个字符之前达到 0。

    如果您不想检查回文,我想您真的在寻找检查a 是否是b 的排列的代码,因为该代码与检查字谜相同如果你只有一个字。

    不要按照别人的建议去做,对字符串进行排序和比较。范围从比三个简单的线性遍历差得多,尽管空间折衷很小,并且字符串中可能出现的字符数量有限。

    逻辑是这样的:制作一个从字符到出现值的映射,指示a 中存在哪些字符以及它们出现了多少次。然后,通过b 确保每个字符都存在,减少出现次数。然后,再次遍历 b,确保所有出现次数为零。

    这里:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stdint.h>
    
    // Only works for single words, but you get the idea.
    int palindrome(const char* a, const char* b) {
        ssize_t len_a = (ssize_t)strlen(a);
        ssize_t len_b = (ssize_t)strlen(b);
        if (len_a != len_b) return 0;
    
        b += (len_b - 1);
        while (len_a--) if (*a++ != *b--) return 0;
        return 1;
    }
    
     // Really checks for a case-sensitive permutations.
    int anagram(const char* a, const char* b) {
        size_t len_a = strlen(a);
        size_t len_b = strlen(b);
        if (len_a != len_b) return 0;
    
        uint16_t occurrences[256] = {0};
    
        for (; *a; occurrences[(int)*a]++, a++);
        for (; *b; occurrences[(int)*b]--, b++) 
            if (!occurrences[(int)*b]) return 0;
    
        b -= len_b;
        for (; *b; b++) if (occurrences[(int)*b]) return 0;
    
        return 1;
    }
    
     int main(void) {
        const char *a = "stack";
        const char *b = "kcats";
        printf("anagram: %d\n", anagram(a, b));
    
        b = "cats";
        printf("anagram: %d\n", anagram(a, b));
    
        b = "kcbts";
        printf("anagram: %d\n", anagram(a, b));
    
        a = "aabbcdddd";
        b = "aaddddbbc";
        printf("anagram: %d\n", anagram(a, b));
    
        a = "aabbcddcd";
        b = "aadddddbc";
        printf("anagram: %d\n", anagram(a, b));
    
        return EXIT_SUCCESS;
    }
    

    请注意,当您执行任何此类算法时,如果字符串的长度不同,则会出现早期的微不足道的错误条件。

    此外,为简单起见,此处的代码区分大小写,但很容易更改。

    输出:

    anagram: 1
    anagram: 0
    anagram: 0
    anagram: 1
    anagram: 0
    

    【讨论】:

    • 一个字谜不仅有相同的字母,它还具有相同的每个字母的出现次数。这是最纯粹意义上的重新安排。如果您认为检查长度可以确保这一点,请再想一想。您可以有两个长度相同但多次出现的字母不同的单词。您的代码可以通过更智能地使用计数数组来解决所有这些问题。
    【解决方案3】:

    继续我的评论,您可以使用一个简单的频率数组(记录主题的每个字符出现的次数)并对建议的anagram 然后简单地比较两个频率数组来确定 proposed anagram 是否实际上是 subject 的一个anagram。

    例如,您可以执行类似以下的操作:

    #include <stdio.h>
    #include <string.h>
    
    #define MAXF 62
    
    int main (int argc, char **argv) {
    
        char *sub = argc > 1 ? argv[1] : "anagram",
             *ana = argc > 2 ? argv[2] : "nag a ram",
             *sp = sub, *ap = ana;
    
        int subf[MAXF] = {0},   /* subject frequency array */
            anaf[MAXF] = {0};   /* anagram frequency array */
    
        while (*sp) {   /* fill subject frequency array */
            if ('a' <= *sp && *sp <= 'z')
                subf[*sp - 'a']++;
            else if ('A' <= *sp && *sp <= 'Z')
                subf[*sp - 'A' + 26]++;
            else if ('0' <= *sp && *sp <= '9')
                subf[*sp - '0' + 52]++;
            sp++;
        }
    
        while (*ap) {   /* fill anagram frequency array */
            if ('a' <= *ap && *ap <= 'z')
                anaf[*ap - 'a']++;
            else if ('A' <= *ap && *ap <= 'Z')
                anaf[*ap - 'A' + 26]++;
            else if ('0' <= *ap && *ap <= '9')
                anaf[*ap - '0' + 52]++;
            ap++;
        }
    
        /* if character frequency arrays are equal - it's an anagram */
        if (memcmp (subf, anaf, MAXF * sizeof *subf) == 0)
            printf ("'%s' is an anagram of '%s'\n", ana, sub);
        else
            printf ("'%s' is NOT an anagram of '%s'\n", ana, sub);
    
        return 0;
    }
    

    使用/输出示例

    检查anagramnag a ram的默认值

    $ ./bin/anagram
    'nag a ram' is an anagram of 'anagram'
    

    检查nag a rim是否是主题词anagram的变位词

    $ ./bin/anagram anagram "nag a rim"
    'nag a rim' is NOT an anagram of 'anagram'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-13
      • 2013-07-02
      • 1970-01-01
      • 2012-12-03
      • 2016-04-14
      • 2012-11-12
      相关资源
      最近更新 更多