【问题标题】:Finding the set of words that can be spelled with a given set of letters找到可以用给定字母集拼写的单词集
【发布时间】:2011-07-16 17:13:12
【问题描述】:

我面临的问题是创建一个有效的算法,该算法从一个固定的单词列表中返回单词列表,该列表可以通过使用一组特定的字母(这个集合是输入)来拼写,这个集合没有上限(或至少没有有用的上限)。

更具体地说,该算法需要为不断增加的输入提供实时解决方案,尽管只要前几个输出元素相对较快地出现,输出就可以慢慢流出。

**注意:输入的真正增强仅以添加到现有集合的形式发生。当一个单词被选中时,LetterStock 中的所有字母都会被耗尽,算法会再次从头开始运行。

可能的字符集是 26 个标准罗马字母。每个字母的存量可以是 0->infinity(用于所有密集目的)并且每个字母只能使用一次(例如 a,b,l 不会返回“ball”,尽管 a,bb,d,lll 会)

正在使用的单词列表是恒定的,因此如果任何预先计算的哈希解决方案对加速运行时性能有用,那么这是一个选项(尽管我想不出一个好的方法来做到这一点)。但是,单词列表很大(约 40,000 个元素)。

到目前为止,我设计的最佳算法涉及使用字母库数组的副本遍历整个单词集并逐个字母检查每个单词,耗尽副本库并查看是否有任何字母出现在下面0. 如果是,我继续,如果不是并且我到达单词的末尾,我将单词添加到解决方案集中。在浏览了整组单词之后,我从头开始寻找我现在可以拼写的单词,因为我的 LetterStock 中已经添加了 1 个或多个字符。

// Pass in the string and a copy of the LetterStock 26-entry array
bool canBeSpelled(string str, int *letterStock)
{
  for(int i=0; i<str.length; i++)
  {
    letterStock[str[i]-65]--; // deplete the letter stock for the given letter

    if(letterStock[str[i]-65] < 0)
      return false;

  }

  return true;
}

因此,我的问题是:这个实现是最优的吗?如果不是,那么什么是更好的?

【问题讨论】:

  • @Alexander “real-time” 在编程中的 specific meaning 与您的问题无关。我删除了该标签,因为它具有误导性。
  • 你只是在创建一个字谜生成器吗?
  • 似乎很奇怪,您只想生成一个随机的单词列表,可以使用一组字母创建,同时删除使用过的字母,但您没有最大化或最小化创建的单词数。
  • "每个字母的存量可以是 0->infinity" - 好吧,如果缺少限制会导致特定问题,那么您可以将其上限设置为任何字母出现的最大次数在您的字典中的一个单词中。这是一个严格的界限,因为它是您可以在不破坏任何东西的情况下全面应用的最小界限。
  • 这不是和this question类似吗?

标签: c# java c++ regex


【解决方案1】:

有点开箱即用,但您是否考虑过使用 Sqlite 之类的东西进行文字存储/查询?可能会解决你所有的问题

【讨论】:

  • +1 :我在想什么,但也可以使用 LINQ to XML 或类似方法来提供功能,而无需向系统添加数据库
【解决方案2】:

我认为directed acyclic word graph(或 DAWG)是您所需要的。 25 年前,我在一个 Scrabble 程序中第一次使用了这种结构(我们从 WordPerfect for DOS 中窃取了字典)。如果您发现很难从您的单词列表中构建 DAWG,请不要放弃——这是一项非常令人满意的成就。

【讨论】:

    【解决方案3】:

    略微优化,但如果您知道您的字母数为 5,单词中的字母数为 6,则您不必检查单词。

    【讨论】:

      【解决方案4】:

      您需要多快的解决方案?即使在检查所有字符的最坏情况下,您的示例也只需要大约几毫秒(在我的基本测试中为 2 毫秒)来检查 40,000 个单词(总共 338,000 个字母)中的所有字母。因此,您可以在一秒钟内用完 1.7 亿个字符。

      如果它满足我的需求,我通常更喜欢一种更简单的算法,而不是花时间/精力寻找“最好”的算法,最终可能只会稍微好一点。

      【讨论】:

        【解决方案5】:

        一些预处理可能有助于为用户加快处理速度。

        在字母类中有一本字典:

        public Dictionary<char, int> count = new Dictionary<char, int> { {'a', 0}, {'b', 0}, etc
        

        在您让用户将您的单词列表处理成字典之前,该字典由带有值的单词键入,并设置一个字母类:

            List<string> strings = new List<string>{ "johnny", "happy", "people" };
            Dictionary< string, letters> processedWordList;
        
            void processList()
            {
                foreach (string s in strings)
                {
                    //there should probably be a constructor in letters which does some of this 
                    string lowered = s.ToLower();
                    Letters letters;
                    foreach (char c in lowered)
                    {
                        ++letters.count[c];
                    }
                    processedWordList.Add(s, letters);
                }
            }
        

        然后您可以覆盖字母类中的 >= 运算符,以查看是否可以拼写单词:

            public static bool operator >=(LetterCount c1, LetterCount c2)
            {
                foreach( KeyValuePair<char, int> letter in c1.count )
                {
                    if (letter.Value < c2.count[letter.Key])
                        return false;
                }
                return true;
            }
        

        并以类似的方式覆盖 operator- 以从您的输入中删除字母。那么您的主要功能如下所示:

                foreach( string s in strings )
                {
                    if (input >= processedWordList[s])
                    {
                        input = input - processedWordList[s];
                    }
                }
        

        当然都是未经测试的。

        【讨论】:

          【解决方案6】:

          可用字符集可能有多大?如果它很大,我的意思是,如果你经常有 15 个或更多的字母,那么你的字典中很大一部分单词可能会适合,并且蛮力地逐个检查可能是最有效的算法。另一方面,如果您的列表是 mall ,如果您通常只有 4 或 5 个字母在池中,那么大多数单词都不会质量,并且有一种方法可以放大候选单词是有意义的。

          一种明显的方法是将字典放在索引表中。依次从池中取出每个独特的字母,并查找以该字母开头的单词。例如,如果池包含 a、b、b、r、o,则查找以 a 开头的单词,然后是 b,然后是 r,然后是 o。除了这类事情之外,我不确定您是否会通过更复杂的数据结构或搜索方案获得太多收益。

          【讨论】:

            猜你喜欢
            • 2020-01-28
            • 1970-01-01
            • 2015-05-09
            • 1970-01-01
            • 1970-01-01
            • 2011-10-25
            • 2017-02-17
            • 2014-04-30
            • 1970-01-01
            相关资源
            最近更新 更多