为了编写您链接的字谜求解器,您请求的算法不是必需的。它也非常昂贵。
让我们看一个 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')吐出为字谜(它们确实如此,但其中大多数也是胡言乱语)。我猜你有一本合法的英语单词词典,你只想检查这些单词中的任何一个是否是查询词的变位词,并且可以选择不使用所有字母。
如果是这样,那么问题就很简单了。
要确定 2 个单词是否是彼此的字谜,您需要做的就是计算每个字母使用了多少次,然后比较这些数字!
让我们将自己限制为仅 26 个字母 AZ,不区分大小写。您需要做的是编写一个函数,该函数countLetters
接受一个单词并返回一个由 26 个数字组成的数组。数组中的第一个数字对应A
于单词中字母的计数,第二个数字对应于 的计数B
,依此类推。
然后,两个单词W1
andW2
是精确的字谜,如果countLetters(W1)[i] == countLetters(W2)[i]
对于每个i
!也就是说,每个单词使用每个字母的次数完全相同!
对于我所说的子字谜(MONEY
是 的子字谜MONKEY
),W1
是W2
if countLetters(W1)[i] <= countLetters(W2)[i]
for each 的子字谜i
!也就是说,子字谜可能会使用更少的某些字母,但不会更多!
(注:MONKEY
也是 的子变位词MONKEY
)。
这应该为您提供足够快的算法,在给定查询字符串的情况下,您需要做的就是通过字典读取一次,将每个单词的字母计数数组与查询词的字母计数数组进行比较。你可以做一些小的优化,但这应该足够好了。
或者,如果您想要最大的性能,您可以预处理字典(这是预先知道的)并创建子字谜关系的有向无环图。
以下是此类图表的一部分用于说明:
D=1,G=1,O=1 ----------> D=1,O=1
{dog,god} \ {do,od}
\
\-------> G=1,O=1
{go}
基本上,每个节点都是具有相同字母计数数组的所有单词的存储桶(即它们是精确的字谜)。然后有一个节点 from N1
to N2
ifN2
的数组是<=
(如上定义)N1
的数组(您可以执行传递缩减以存储最少数量的边)。
然后要列出一个单词的所有子变位词,您所要做的就是找到与其字母计数数组对应的节点,并递归地探索从该节点可到达的所有节点。他们所有的桶都将包含子字谜。