首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >通配符拼字机

通配符拼字机
EN

Stack Overflow用户
提问于 2011-09-14 15:25:01
回答 3查看 4.4K关注 0票数 6

我遇到了一个问题,在我之前似乎也有过类似的问题,但是我还没有找到一个可行的解决方案。

我目前正在使用C#、MySQL、HTML5和Javascript构建一个移动web应用程序。该应用程序将用于帮助用户在玩拼字游戏时找到可能的单词。

我遇到的问题是:如何从包含字典的MySQL数据库中从用户字母输入中获得正确的单词?

更多细节:-用户可以输入任意数量的字母,也可以使用通配符(代表任何字母)。-如果用户输入“TEST”,结果不能包含大于1E和S的单词,以及超过2T的单词,那么使用“测试器”的结果将是不好的。-结果不能包含比输入更多字母的单词。

更新:正如Eric here所建议的那样,Trie是解决我的问题的方法。

问题是我是C#和MySQL的初学者,下面是一些后续问题:

  1. 如何从我的MySQL字典中创建Trie?(400k+ words )
  2. 如何存储Trie以便快速和将来访问?
  3. 如何访问Trie并使用C#从其中提取单词?

非常感谢您的帮助!

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-09-14 15:32:08

如何从包含字典的MySQL数据库中从用户字母输入中获得正确的单词?

没有。关系数据库表并不是解决这个问题所需要的合适的数据结构。

相反,您要做的是从字典中构建一个数据结构(或者,如果您真的很喜欢的话,您可以构建一个 --一个有向无圈字图--这是一种压缩的trie)。

一旦您有一个trie/dawg,它变得非常便宜的测试,在字典中的每一个词在给定的货架,因为你可以“剪出”整个大分支的字典,架不可能匹配。

让我们看一个小例子。假设您有字典OP、OPS、OPT、OPTS、POT、POT、SOP、SOPS、STOP、STOP“,”您可以构建这个trie:(带有$的节点是标记为"word可以在这里结束“的节点。

代码语言:javascript
运行
复制
           ^root^
           /  |  \
         O    P    S
         |    |   / \
         P$   O  O   T   
        / \   |  |   |
       T$  S$ T$ P$  O
       |      |  |   |
       S$     S$ S$  P$
                     |
                     S$

你有机架“老年退休金”--你是做什么的?

首先你说:“我能从O支部下来吗?”可以,停那儿吧。因此,现在的问题是将"PS“与O分支相匹配。你能沿着P支行走吗?是。它有字尾标记吗?是的,所以OP是匹配的。现在的问题是将"S“与OP分支匹配。你能沿着T支行走吗?不是的。你能沿着S支行走吗?是。现在,您有了空的机架,您必须将它与老年退休金分支相匹配。它有字尾标记吗?是!所以老年退休金也匹配。现在追溯到根部。

你能沿着P支行走吗?是。现在的问题是如何将OS与P分支相匹配。沿着PO分支,匹配S --失败了。回溯到根。

再说一遍,你看这是怎么回事。最后,我们沿着SOP分支,在SOP上找到了一个单词的结尾,所以"SOP“与这个支架相匹配。我们不去ST支行,因为我们没有T。

我们试过字典中的每一个可能的单词,发现OP、OPS和SOP都匹配。但我们从来不需要调查选择,盆栽,停止或停止,因为我们没有一个T。

你知道这种数据结构是如何使它非常高效的吗?一旦你确定你没有在架子上的字母来做一个单词的开头,你就不需要去调查任何从这个开始开始的字典单词。如果你有PO,但没有T,你就不必去调查陶片、土豆、钾肥、土豆或便宜货;所有那些昂贵而毫无结果的搜索都会很快消失。

调整系统以处理“野生”块是非常简单的;如果您有OPS?,那么只需运行26次搜索算法,在OPSA,OPSB,OPSC上.它应该足够快,这样做26次是便宜的(或26次,如果你有两个空白)。

这是专业拼字AI程序使用的基本算法,当然,它们也必须处理诸如板子位置、机架管理等问题,这使算法变得有些复杂。这个简单版本的算法将足够快,以生成所有可能的字架上。

当然,如果字典没有随时间变化,你只需要计算trie/dawg一次。从字典中构建trie可能很费时,所以您可能需要这样做一次,然后想出某种方法将trie存储在磁盘上,以便能够快速地从磁盘重新构建它。

您可以通过从trie中构建一个DAWG来优化内存使用。注意很多重复,因为在英语中,很多单词的结尾都是一样的,就像很多单词的开头一样。trie在一开始就很好地共享节点,但在最后共享节点却是一项糟糕的工作。例如,您可以注意到"S$ with子“模式非常常见,并将trie转换为:

代码语言:javascript
运行
复制
           ^root^
          / |  \
        O   P    S
        |   |   / \
        P$  O  O   T   
       /  \ |  |   |
      T$  | T$ P$  O
      |    \ | |   |
       \    \| /   P$
        \    |/    |
         \   |    /
          \  |   /  
           \ |  /
            \| /  
             |/
             |       
             S$

节省了一整堆节点。然后您可能会注意到,两个单词现在以O$-S$结尾,两个单词以T$-S$结尾,所以您可以进一步压缩它:

代码语言:javascript
运行
复制
           ^root^
           / | \
          O  P  S
          |  | / \
          P$ O \  T   
         /  \|  \ |
         |   |   \|
         |   |    O
         |   T$   |
          \  |    P$
           \ |   /
            \|  /  
             | /
             |/   
             S$

现在我们有了这本字典的最小道格。

进一步读:

http://dl.acm.org/citation.cfm?id=42420

http://archive.msdn.microsoft.com/dawg1

http://www.gtoal.com/wordgames/scrabble.html

票数 23
EN

Stack Overflow用户

发布于 2011-09-14 15:57:53

下面是我如何解决这个问题的方法(当然,假设您控制了DB,并且可以修改表/添加表,甚至可以控制DB的原始负载)。

我的解决方案是使用两个表,->,一个表将是字典中每一个可能的字母组合的列表,并按字母顺序排列组件字母。(即测试将是ESTT,测试人员将是ERSTT,DAD将添加)。

第二个表将包含每个单词,并引用表1的键。

表一- LetterInWord

代码语言:javascript
运行
复制
Index Letters
1     ESTT
2     ESTTER
3     EST
4     ADD
5     APST

在表一中,您按字母顺序插入单词- test变成estt。

表二-字

代码语言:javascript
运行
复制
Index LetterInWordIndex  Word
1     1                  TEST
2     2                  TESTER
3     3                  SET
4     4                  ADD
5     4                  DAD
6     5                  SPAT
7     5                  PAST               

在表2中插入带有适当单词和索引引用的单词。

这将是一个一对多的关系->表中的一个条目可能在Word表中有多个条目

非通配符查找:假设我的输入字母设置为字母排序。

然后在查找中,从LetterInWord中选择所有的“字母”,其中Letters = value并连接表单词--在一个查询中,您的输出是一个只包含这些字母的所有单词的列表。

现在对于通配符:假设我的输入字母是EST*请记住长度-4划出通配符-您得到了EST (确保按字母顺序排序)现在查找所有字母包含EST和字母长度<= 4的情况,这些字母连接在Word表上。

返回测试、休息、设置等

我不确定这是否是最有效的方法,但它有效。我过去曾使用它从字典中查找单词,它具有合理的性能和最小的复杂性。

票数 0
EN

Stack Overflow用户

发布于 2011-09-14 15:31:18

如果你只有字典的话,这将是非常困难的。如果您有能力创建一个新表或新列,我会:

创建一个包含单词列的表,再加上26列(每个字母一列),运行存储的proc/后端进程,计算单词中每个字母的出现情况,并将它们放入适当的列中。

然后(忽略通配符)你可以做到

从字典中选择单词,其中tcount <=2和ecount <=1和scount <=1

对于通配符,您可以这样做和长度<= number_of_letters

实际上,始终使用length子句,因为这样您就能够对其进行索引以提高性能。

在查询过程中,其他任何事情都将异常缓慢。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7418910

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档