Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;-如何有效地找出向量中的任何字符串是否可以由一组字母组合而成_C++_Algorithm_Optimization - Fatal编程技术网

C++ C++;-如何有效地找出向量中的任何字符串是否可以由一组字母组合而成

C++ C++;-如何有效地找出向量中的任何字符串是否可以由一组字母组合而成,c++,algorithm,optimization,C++,Algorithm,Optimization,我正在为一个大学项目实施一个基于文本的拼字游戏版本 我有一个包含大约400K个字符串的向量(我的字典),在每一个回合的某个时候,我都必须检查字典中是否还有一个单词可以由玩家手中的片段组成。我正在检查玩家是否有任何左移。。。如果不是的话,这场比赛就结束了 我唯一的解决办法是一个接一个地遍历字符串,并使用一个子例程检查所讨论的字符串是否可以由播放器的片段组成。如果用户有元音,我将实现一个quickfail检查,但效率仍然很低 包含字典的文本文件已按字母顺序排列,因此向量已排序 有什么建议吗 在下面

我正在为一个大学项目实施一个基于文本的拼字游戏版本

我有一个包含大约400K个字符串的向量(我的字典),在每一个回合的某个时候,我都必须检查字典中是否还有一个单词可以由玩家手中的片段组成。我正在检查玩家是否有任何左移。。。如果不是的话,这场比赛就结束了

我唯一的解决办法是一个接一个地遍历字符串,并使用一个子例程检查所讨论的字符串是否可以由播放器的片段组成。如果用户有元音,我将实现一个quickfail检查,但效率仍然很低

包含字典的文本文件已按字母顺序排列,因此向量已排序

有什么建议吗



在下面的评论中提出了一个问题:关于如何把已经写在板上的字母考虑进去?

不给你任何特定的代码(因为这毕竟是家庭作业),一个一般的考虑方法是从单词中的排序字母映射到实际的合法词。 也就是说,如果字典文件中只有单词
ape
gum
mug
,则数据结构如下所示:

aep -> ape
gmu -> gum, mug

然后,您可以简单地通过玩家字母的排列,快速确定该键是否存在于地图中


在启动时设置字典需要花费一点处理时间,但只需执行一些快速查找,而不是每次都遍历整个列表。

您还可以将按字母顺序排序的字符串存储到std::集合中,然后将玩家的字母按相同的顺序排序,并在地图上搜索玩家字母的每个子字符串。

如何保留成对的字母{字典中的单词,由相同字母组成的字符串,但按升序(排序)}


然后根据第二个字符串对这些对的向量进行排序,并使用二进制搜索与一个由玩家手上的已排序字母组成的字符串进行比较。

听起来像是子集和问题的一种变体:


也许所描述的一些算法会对你有所帮助。

这个网站上有很多关于拼字游戏的论文和问题

也有许多可用的策略

你的词典的表述不充分,有很多巧妙的方法可用。例如,检查维基百科上的Trie是什么

使用此方法,您可以实现回溯算法,以快速确定可以形成哪些单词

{'as', 'ape', 'gum'}

Trie:

void -a-> (n) -p-> (n) -e-> (y)
              -s-> (y)
     -g-> (n) -u-> (n) -m-> (y)
其中‘n’表示它不构成单词,y表示它构成单词

现在,你只需要走在特里亚,记住哪些字母是可用的

假设你有{'a','p','g','m','u'}:

 1. I have a 'a' (but 'a' is not a word)
 2. I have a 'p' (but 'ap' is not a word)
 3. I don't have any 'e' so I can't go further, let's backtrack
 4. I don't have any 's' so...
 5. I have a 'g', but it's not a word
 6. I have a 'u', but 'gu' is not a word
 7. I have a 'm' and 'gum' is a word, I store it somewhere, I can't go further
关键是要维护一组可用的字母,当您使用-a->分支时,从该集合中删除“a”,然后当您使用-a->反向(回溯时)时,将其添加回集合中

  • 这种结构更节省空间,它实际上模拟了一个有限自动机,该自动机可以识别词典的语言,而不是盲目地保存所有单词
  • 运行时也应该快得多,因为您永远不会深入到树结构中(您只有7个字母可用)
  • 这当然不是我会做的,因为它没有考虑董事会:p

“”字母表示您可以选择任何可用的分支。如果你有所需的字母,你不需要使用空格。

这里已经有一些很好的答案,我认为trie可能是正确的方法,但这是一个有趣的问题,所以我将投入我的两分钱

天真的方法是生成可用字母和所有不同子集的所有排列,然后在字典中搜索每个潜在单词。问题是,虽然这并不难做到,但潜在的单词数量惊人地多,而且大多数都是无效的

从积极的方面来看,通过二进制搜索或类似的方法可以加快查字典的速度。消极的一面是,你这么做的次数太多了,以至于程序会因为一长串的信件而停止运行

我们确实需要对字典进行预处理,使其更有用,而我们真正需要的是找到一种方法来快速排除大多数潜在匹配,即使该方法偶尔会出现误报

一种方法是表示单词在位图中使用的字母。换句话说,为字典中的每个单词预先计算一个32位的数字,如果字母表的对应字母在单词中至少使用一次,则每个位都被设置。这将允许你通过对字典进行线性扫描并只保留那些只使用你现有字母的单词来找到所有可能的单词。我怀疑,只要稍微聪明一点,建立索引,你就能比线性的做得更好

在你找到的候选人中,有些人需要的信件实例比你现有的要多,所以这些都是误报。这意味着您需要对生成的所有候选项进行最后检查,以消除几乎命中的结果。有很多方法可以做到这一点,但最简单的方法之一是浏览你的字母列表,用破折号替换潜在单词中第一个出现的字母。完成后,如果潜在的单词没有破折号,那就是失败。一个更优雅的解决方案,虽然不一定更快,将是生成一个字母频率数组并进行比较

同样,我认为尝试可能是一条路,但我希望这些想法对你有用

编辑

让我举一个例子来说明你是如何