【问题标题】:Finding anagram寻找字谜
【发布时间】:2019-07-25 02:29:26
【问题描述】:
if (strlen(a) != strlen(b)) {
    printf("Not anagram");
} else {
    for (int i = 0; i < strlen(a); i++) {
        for (int j = 0; j < strlen(b); j++) {
            if (a[i] == b[j]) {
                len++;
            }
        }
    }
    if (len != strlen(a))
        printf("Not anagram");
    else
        printf("Anagram");
}
return 0;

这是一个代码 sn-p 来检查 2 个字符串是否是字谜。这里如何处理重复字符?另外,这个程序可以更优化吗?这段代码的运行时复杂度是多少?

【问题讨论】:

  • 这真的是Objective-C吗?看起来更像是纯 C。
  • 对不起,我会编辑标签。
  • 我认为更好的算法是按字母顺序对两个单词中的字母进行排序,然后比较它们是否相等。
  • 您的方法通常是 O(n^2),其中 n 是每个字符串的长度。但是,您的实现是 O(n^3),因为您在 each 迭代中重新计算 strlen。如果你采用排序方法,你可以做到 O(n log n) 或 O(n) 时间。

标签: c string anagram


【解决方案1】:

最佳解决方案可能是基于计算每个字符串中的字符数,然后比较两个计数。理想情况下,我们应该使用 Dictionary 数据结构,但为简单起见,我将在数组上演示该算法:

char *word1 = "word1";
char *word2 = "ordw1";

// C strings can have only 256 possible characters, therefore let's store counts in an array with 256 items.
int* letterCounts1 = calloc(256, sizeof(int));
int* letterCounts2 = calloc(256, sizeof(int));
size_t length1 = strlen(word1);
size_t length2 = strlen(word2);

for (size_t i = 0; i < length1; i++) {
    int letterIndex = word1[i] & 0xFF;
    letterCounts1[letterIndex] += 1;
}

for (size_t i = 0; i < length2; i++) {
    int letterIndex = word2[i] & 0xFF;
    letterCounts2[letterIndex] += 1;
}

bool isAnagram = true;

for (size_t i = 0; i < 256; i++) {
    if (letterCounts1[i] != letterCounts2[i]) {
        isAnagram = false;
        break;
    }
}

free(letterCounts1);
free(letterCounts2);

if (isAnagram) {
    printf("Anagram");
} else {
    printf("Not anagram");
}

此算法具有线性 (O(n)) 复杂度(对“字典”的迭代可以视为常数)。

您的原始解决方案具有二次复杂性,但是,您还必须确保将 strlen 的结果存储到变量中,因为对 strlen 的每次调用都必须遍历整个字符串,从而将复杂性增加到三次。

【讨论】:

  • letterCounts1letterCounts2 应该是 size_t * 以解决带有重复字符的病态长字符串。
  • @chqrlie 你可能是对的,但这些小问题可能对 OP 来说并不重要。无论如何,我只有基本的 C 知识。从 C 的角度来看,您的解决方案会更好。
【解决方案2】:

首先,这不是正确的解决方案。想想这两个字符串:“aabc”和“aade” a[0] == b[0]、a[0] == b[1]、a[1] == b[0] 和 a[1] == b[1]。 len 将是 4,但它们不是字谜。复杂度是 O(n^2) 是字符串的长度。

正如@Sulthan 回答的那样,更好的方法是对复杂度为 O(n*log(n)) 的字符串进行排序,然后一次性比较两个字符串 O(n)。

要以 O(n * log(n)) 对字符串进行排序,您不能使用冒泡方法,但可以使用此处所述的合并排序:https://www.geeksforgeeks.org/merge-sort/

更好的方法是创建一个整数数组,在其中计算第一个字符串中每个字符的出现次数,然后减去第二个数组中每个字符出现的次数。最后辅助数组的所有位置都必须为0。

【讨论】:

    【解决方案3】:

    这里有一些答案:

    • 您的算法不能处理重复的字母,它可能会返回误报。
    • 不清楚是否正确,因为您没有发布包含所有声明和定义的完整函数定义,尤其是 len 是否初始化为 0
    • 如果编译器有 O(N2) 时间复杂度甚至 O(N3)无法优化对strlen() 的大量冗余调用。

    以下是具有线性复杂度的 8 位字符系统的简单解决方案:

    #include <stdio.h>
    #include <string.h>
    
    int check_anagrams(const char *a, const char *b) {
        size_t counters[256];
        size_t len = strlen(a);
        size_t i;
    
        if (len != strlen(b)) {
            printf("Not anagrams\n");
            return 0;
        }
        for (i = 0; i < 256; i++) {
            counters[i] = 0;
        }
        for (i = 0; i < len; i++) {
            int c = (unsigned char)a[i];
            counters[c] += 1;
        }
        for (i = 0; i < len; i++) {
            int c = (unsigned char)b[i];
            if (counters[c] == 0) {
                printf("Not anagrams\n");
                return 0;
            }
            counters[c] -= 1;
        }
        printf("Anagrams\n");
        return 1;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-11-01
      • 2013-01-11
      • 2016-03-18
      • 2011-12-07
      • 2022-01-21
      • 2019-07-07
      • 2011-02-07
      相关资源
      最近更新 更多