【问题标题】:Count the Number of Consistent Strings in C计算 C 中一致字符串的数量
【发布时间】:2021-02-17 23:41:28
【问题描述】:

所以这是 leetcode 的一个问题,我遇到了一些问题。我已经看到解决这个问题的代码发布到 leetcode 的讨论部分,但我想知道是否有人可以帮助我解决它我已经写了一些代码..这是问题所在:

给你一个字符串allowed,由不同的字符和 字符串数组words。如果字符串中的所有字符都是一致的 该字符串出现在字符串allowed 中。返回数量 数组单词中的一致字符串。

示例:
输入:allowed = "ab"words => ["ad","bd","aaab","baa","badab"]

输出:2

解释:字符串“aaab”和“baa”是一致的,因为它们只 包含字符“a”和“b”。

到目前为止,这是我的代码:

注意:允许包含单个字符串

#include <string.h>

int countConsistentStrings(char * allowed, char ** words, int wordsSize){
    
    int real_count = 0;
    for(int i = 0; i < wordsSize; i++)
    {
        for(int j = 0; j < strlen(allowed); j++)
        {
            for(int k = 0; k < strlen(words[i]); k++)
            {
                if(words[i][k] != allowed[j])
                {
                    // stuff goes here?
                }
            }

        }
    }


    return real_count;
}

我能够逐个字符地遍历数组中的字符串,并将它们与允许的字符进行比较......但我真的不知道从那里去哪里。我尝试过记录东西并使用比较,但后来我遇到了 words[i] 是否小于 strlen(allowed) 或反之亦然的问题..

我知道可能有更简单的方法来解决这个问题(正如我在 leetcode 的讨论部分中看到的那样),但我想知道是否有任何方法可以使用我已经完成的方法来解决它?

感谢任何可以帮助我解决这个问题的人......我觉得我“几乎”解决了这个问题,但我也被困了很长一段时间,所以我准备好接受任何解释我可以得到。

【问题讨论】:

  • allowed单个字吗?或者,它可以有 多个 单词用空格分隔吗?你能用strcmp等吗? 旁注: for(int j = 0; j &lt; strlen(allowed); j++)(例如)非常慢(O(n^2) 而不是 O(n))。更好的做法:for(int j = 0, len = strlen(allowed); j &lt; len; j++)
  • allowed 由一个字符串组成。我会编辑这个问题,这样就清楚了。我的循环是否会是 n^2,因为它每次都必须遍历 strlen(allowed) 才能获得值?
  • 如果allowed 中只有 一个 字[并且我假设它有 no 其他空格],你只能返回一个 [ boolean] 值:(例如)1=match, 0=nomatch ???这假设给定字符串 onlywords 中一次(即words 条目是唯一的)。如果words 可以 重复一个字符串,则返回匹配words 条目数的count。如果它们是唯一的,如果你找到第一个匹配项,你可以break 退出循环(即它更快——对于像 leetcode 这样的网站来说总是一件好事)。否则,您必须遍历 all words 条目?你要哪个?

标签: arrays c string


【解决方案1】:

这是一个 O(N) 的解决方案。因此,您不必为每个字符重新扫描allowed,只需使用查找表即可。很容易,因为字符通常是 8 位的,并且包含 256 个真值/值的数组很容易。

int countConsistentStrings(char * allowed, char ** words, int wordsSize) {

    // put all the allowed chars into a table of booleans

    unsigned int table[256] = {0}; // 256 assumes 8-bit char
    int real_count = 0;
    const char* ptr = allowed;

    while (*ptr)
    {
        char c = *ptr;
        table[(unsigned char)c)] = 1;   // table[c] = 1 to indicate "is allowed"
        ptr++;
    }

    // evaluate each word and see if each char in word
    // is in the allowed list of chars
    
    for(int i = 0; i < wordsSize; i++)
    {
        char* word = words[i];
        int consistent = 1;
        while (*word && consistent)
        {
            char c = *word;
            consistent = table[(unsigned char)c]; // lookup to see if this char is allowed
            word++;
        }
        real_count += consistent;
    }

    return real_count;
}

【讨论】:

  • 我自己正在考虑使用表格方法。我认为table 可以更快,如果它是char
  • 好的,让我看看我是否可以按照这个...您创建了一个名为 table 的数组并将等于允许的字符的各个 asci 值的索引设置为 1。然后您使用此表比较 words[i] 的字符?
  • 为什么要写[256] = {0}; // 256 assumes 8-bit char,故意构建一个不必要的先决条件?使用[UCHAR_MAX+1u] = {0};
  • @EricPostpischil - 为了教新人编码,只使用几乎普遍适用的硬编码默认值可能是最好的。
  • @CraigEstey:如果允许的字符总是小写字母(或者最多跨越 32 或 64 个代码点),我们甚至可以在 uint32_t(或 uint_fast32_t )。根据机器的不同,c - ='a'/if (c &gt;= 26) break;/if(allowed &amp; (1&lt;&lt;c)) 或类似的东西可能与字节加载一样好,并避免构建数组。 (如果您可以放弃范围检查,则特别好)。例如在 x86 sub eax, 'a' / (cmp eax, 25 / jae nope) / bt edx, eax / jnc nope。 ARM 还可以将转换构建到其他指令中。但是,是的,对于大输入内存的概率。最好的。
【解决方案2】:

您可以使用strchr 函数来帮助检测allowed 中是否存在字符。该函数的工作原理如下:

   char *strchr(const char *s, int c);
   The strchr() function returns a pointer to the first occurrence
   of the character c in the string s.
   The strchr() and strrchr() functions return a pointer to the
   matched character or NULL if the character is not found.

因此,对 NULL 的测试可以让您检查是否在 allowed 中找到了相关字符。使用此功能,您可以删除其中一个循环,只需遍历给定单词中的每个字符以查找匹配项。考虑到这一点,我认为假设所有单词 do 匹配然后减去不匹配的单词会更容易。

这里有一些代码说明了我的意思。我创建了一个调用 countConsistentStrings 的主函数,其中包含一些我用来验证行为的测试数据。

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

int countConsistentStrings(char *allowed, char **words, int wordsSize)
{
    int real_count = wordsSize;
    for(int i = 0; i < wordsSize; i++)
    {
        for(int k = 0; k < strlen(words[i]); k++)
        {
            // if character is not found, then it's not a consistent string
            // so we can just lower the count and exit the loop right now
            if(strchr(allowed, words[i][k]) == NULL)
            {
                real_count--;
                break;
            }
        }
    }

    return real_count;
}

int main()
{
    char *allowed = "abcde";
    char *words[] =
    {
       "abcde",
       "fghji",
       "d",
       "l",
       "abcdef"
    };
    int wordcount = sizeof(words)/sizeof(words[0]);
    int count;

    printf("Finding consistent strings among %d words\n", wordcount);
    
    count = countConsistentStrings(allowed, words, wordcount);
    
    printf("Consistent string count: %d\n", count);

    return 0;
}

【讨论】:

  • strchr 在这方面效率低下,“leetcode”问题和其他竞赛问题的解决方案应该以效率为目标,特别是当它很容易获得时。其中一些问题是定时的,并且测试用例旨在导致效率低下的解决方案无法满足时间要求。
  • 虽然有更有效的方法来解决问题,但 OP 写道:“我知道可能有更简单的方法来解决这个问题(正如我在 leetcode 的讨论部分看到的那样),但我'我想知道是否有办法用我已经做过的事情来解决它?”因此,他更感兴趣的是理解可能解决方案的逻辑,而不是从运行时性能中挤出每个周期。这就是我提供的动机。
  • 人们认为他们想要更快的马并不意味着你不应该给他们一辆车。
  • 您在for 循环条件表达式中的strlen 调用中留下了,因此至少可以修复。
【解决方案3】:

假设标准 C 库函数是允许的,下面使用 size_t strspn(const char *dest, const char *src),它“返回由 dest 指向的空终止字节字符串的最大初始段(跨度)的长度,包括仅在 src 指向的以空字符结尾的字节字符串中找到的字符。"。

#include <string.h>

int countConsistentStrings(char *allowed, char **words, int wordsSize)
{
    int count = 0;
    for(int i = 0; i < wordsSize; i++)
    {
        char *word = words[i];
        if(word[strspn(word, allowed)] == '\0')
            count++;
    }
    return count;
}

【讨论】:

  • strspn 对此效率低下(可以实现它以便每次调用都高效,但问题规范要求将相同的允许字符集应用于多个字符串),以及解决“ leetcode”问题和其他竞赛问题应该以效率为目标,特别是当它很容易获得时。其中一些问题是定时的,并且测试用例旨在导致效率低下的解决方案无法满足时间要求。
  • @EricPostpischil strspn 在这种情况下,如果它返回一个指向第一个不匹配字符的指针,而不是匹配字符的计数,它的效率可能会稍微高一些。这将节省每个要检查的单词的指针索引,尽管实际上这可能会被 strspn 的库优化所抵消,而不是手工循环。也就是说,我从未声称上述内容会提供终极性能,因此请随意发布您认为“最佳”的版本。
  • 我不参加比赛。我正在努力提高答案的质量。应该劝阻低效的答案。 Selbie’s answer 有正确答案,所以我或其他人无需输入新答案,尽管我希望看到它有所改进。
  • strspn 必须 [在内部] 在 each 调用 [至少对于 glibc] 上从 accept 字符串构建/重建 256 个元素的表,所以它[可能]花费更多的时间来做这比实际查找/匹配
  • @EricPostpischil “正确”的答案取决于关于字符串的数量和大小、预期的字符分布以及strspn 的内部实现的无数假设。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-07
  • 2014-07-08
  • 2017-10-20
  • 1970-01-01
  • 2021-09-28
相关资源
最近更新 更多