为了编写像你提供的链接一样的字谜求解器,你所请求的算法并非必要,并且非常昂贵。
以一个6个字母的单词"MONKEY"为例。该单词的6个字母都不同,因此您需要创建:
- 6*5*4*3*2*1 种不同的6个字母单词
- 6*5*4*3*2 种不同的5个字母单词
- 6*5*4*3 种不同的4个字母单词
- 6*5*4 种不同的3个字母单词
- 6*5 种不同的2个字母单词
- 总计1950个单词
现在,假设您不想将所有1950个单词(例如 "OEYKMN")作为字谜输出(尽管它们确实是字谜,但其中大多数也是无意义的)。我猜您拥有一个合法的英语单词字典,只需检查这些单词是否与查询词的字谜匹配,还可以选择不使用所有字母。
如果是这种情况,那么问题就很简单。
要确定两个单词是否为字谜,您只需要计算每个字母使用次数的数量,并比较这些数字!
让我们仅限于26个字母A-Z,大小写不敏感。您需要编写一个名为"countLetters"的函数,该函数接受一个单词并返回一个包含26个数字的数组。数组中的第一个数字对应于单词中字母"A"的计数,第二个数字对应于字母"B"的计数等等。
然后,当且仅当每个i都满足"countLetters(W1)[i] == countLetters(W2)[i]"时,两个单词W1和W2是完全的字谜!也就是说,每个单词使用每个字母的数量完全相同!
对于我所说的子字谜(例如"MONEY"是"MONKEY"的一个子字谜),当且仅当每个i都满足"countLetters(W1)[i] <= countLetters(W2)[i]"时,W1是W2的子字谜!也就是说,子字谜可以少用某些字母,但不可以多用!
(注意:"MONKEY"也是"MONKEY"的一个子字谜)。
这将为您提供足够快的算法,当给定一个查询字符串时,您只需阅读一次字典,将每个单词的字母计数数组与查询单词的字母计数数组进行比较。您可以进行一些小优化,但这应该已经足够了。
如果您想要最大的性能,可以预处理字典(提前知道的),并创建子异序词关系的有向无环图。
以下是这样一个图的一部分,以供说明:
D=1,G=1,O=1 ----------> D=1,O=1
{dog,god} \ {do,od}
\
\-------> G=1,O=1
{go}
基本上,每个节点都是一个桶,用于存放所有具有相同字母计数数组的单词(即它们是精确的字谜)。然后如果
N2
的数组是
<=
(如上所定义)
N1
的数组,则从
N1
到
N2
存在一个节点(您可以执行可达性缩减以存储最少量的边)。
然后要列出单词的所有子谜题,您只需找到与其字母计数数组对应的节点,并递归地探索从该节点可访问的所有节点。它们的桶将包含子谜题。