Php 求最长字谜的算法

Php 求最长字谜的算法,php,mysql,algorithm,anagram,Php,Mysql,Algorithm,Anagram,假设我们有一本大约25万字的字典。算法应该将12个字母作为数组或字符串,并从字典中找到匹配最长单词的变体 当然,人们总是可以用蛮力来对付它,但我想知道,做这件事最优雅的方式是什么 如果不使用任何特定于语言的函数作为解决主要问题的快捷方式,则使用PHP以外语言的答案也将被接受 注意:单词存储在数据库中,但为了提高速度,我可以将它们拉入内存。虽然我不确定PHP的索引是否比MySQL数据库的索引更好?如果您要查找最长的匹配单词,我会首先尝试按单词长度对词典进行排序,这样您就可以将最大的精力集中在最长的

假设我们有一本大约25万字的字典。算法应该将12个字母作为数组或字符串,并从字典中找到匹配最长单词的变体

当然,人们总是可以用蛮力来对付它,但我想知道,做这件事最优雅的方式是什么

如果不使用任何特定于语言的函数作为解决主要问题的快捷方式,则使用PHP以外语言的答案也将被接受


注意:单词存储在数据库中,但为了提高速度,我可以将它们拉入内存。虽然我不确定PHP的索引是否比MySQL数据库的索引更好?

如果您要查找最长的匹配单词,我会首先尝试按单词长度对词典进行排序,这样您就可以将最大的精力集中在最长的单词上

我的想法:

伪代码:

int_32 letter_mask
int_32 permutation_match_mask
if(((letter_mask XOR permutation_match_mask) AND letter_mask)  == 0)
        YOU_HAVE_HIT;
当你在letemask中有非重复字母时,这是可行的,但是如果你有更多的字母,你可能无法扩展leter和permutationmatchmask

编辑

另一个想法

按字母顺序对词汇表中的单词进行排序

如果有12个字母,它们都是不同的,那么就有4095个可能的组合,只需对字母ABCD求和i=1->12个二进制数,就有ABCD、ABC、ABD、ACD、BCD、AB、AC、AD、BC、BD、CD、A、B、C、D,正如我所说的,12个不同的字母中有4095个,如果某些字母相同,则更少

复杂度4095*log225000约等于75000。嗯,值得一试


对每个组合进行精确搜索。

我会选择对答案稍加修改的版本

对于字典中的每个单词,按字母顺序排序。所以foobar变成了abfoor

从按字母顺序排列的完整输入开始。如果未找到,请删除一个字母,然后再次搜索。每封信都要这样做。然后删除两个字母。。。等等

最糟糕的情况:根本找不到“字谜”。您必须测试所有可能的输入组合,这将为您提供大约2^n个查找,其中n是示例中的输入字符数:12
但是,算法的速度并不取决于运行时字典的大小,当然,按字母顺序排序单词是最重要的。你应该计算每个单词的签名,只需计算一次,然后将其与单词一起保存到数据库中

表格应该是这样的:

   word varchar(12), 
   a int,
   b int, 
   c int,
    ...
   w int,
   z int;
select word, length(word) as wordlen
from dictionary
where
a <= 4 and
b <= 0 and
c <= 1 and
d <= 2 and
e <= 0 and
f <= 0 and
 ....
z <= 0
order by wordlen desc;
从a到z的字段必须包含单词中包含的字母数, 例如,字谜将有如下记录:

word,    a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z
anagram, 3,0,0,0,0,0,1,0,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0
一旦你有了十二个字母,你就必须计算出集合的签名并使用它 要创建如下所示的选择:

   word varchar(12), 
   a int,
   b int, 
   c int,
    ...
   w int,
   z int;
select word, length(word) as wordlen
from dictionary
where
a <= 4 and
b <= 0 and
c <= 1 and
d <= 2 and
e <= 0 and
f <= 0 and
 ....
z <= 0
order by wordlen desc;
以便使用您拥有的字母集创建所有单词

没有排列,没有组合,尽管词典的编纂工作已经完成 只有一次和离线


另一个提示是,从数据库中删除所有长度超过12个字符的单词

埃里克·利珀特(Eric Lippert)写了一篇关于字谜搜索的信息性文章。这些示例都使用c语言,但这些技术在任何语言中都是可用的

有效地在字典中搜索字谜的诀窍是认识到所有字谜都有相同的字母,只是顺序不同。如果您规范化每个单词,使其字母为大写字母并按字母顺序排列,那么检查一个单词是否是另一个单词的拼字就如同比较它们的规范形式一样简单


使用此技术,您可以轻松地从哈希表或平衡树中查找字谜。

是否需要更详细地解释?这是一种暴力算法,需要分别检查每个单词以找到命中率。例如:你有字母ABFR,字典里有两个单词FOO,BAR用11000000000100000000000000二进制表示,我们有一个at 1,2处的B和18处的R arbf具有110001000000000000000000000000000二进制,当您执行上层逻辑求值时,这需要在本例中只需要几条指令,这会让您命中,但正如我所说的,这只是快速暴力实现。我喜欢这一点,尽管在搜索最长单词时似乎需要扫描整个集合。我希望有一种算法可以让我使用索引。你可以为每个a-z字段建立索引。虽然这可能会占用很多空间,但你能不能将使用的字符和数量粉碎到另一个名为hash的列中,并对其进行索引。对于anagram,您将有一个散列a3g1m1n1r1,或者您也可以进行aaagmnr散列。如果您将单词aaegmnr的签名/散列用于manager,则无法轻松检索子单词,例如,game o gamer,仅使用sql查询键,我明白了。。。这就是为什么你有。。。a可能是打字错误,但只是想核实一下:你是指“acfoor”还是abfoor?我实际上是从原始答案中复制了这一部分,但你当然是对的,你应该仔细阅读。这不是最重要的吗
与HerdplattenToni的答案相同?这当然是相似的,但博客文章包含了许多实用的调整建议,值得一提。