给定一个单词列表,例如
words = set(line.strip().lower() for line in open('/usr/share/dict/words'))
您可以构建和索引“通配符”单词,在其中将单词的每个字符替换为通配符(例如“?”),以便例如“gat”和“fat”都被索引为“?at ":
def wildcard(s, idx):
return s[:idx] + '?' + s[idx+1:]
def wildcarded(s):
for idx in xrange(len(s)):
yield wildcard(s, idx)
# list(wildcarded('cat')) returns ['?at', 'c?t', 'ca?']
from collections import defaultdict
index = defaultdict(list)
for word in words:
for w in wildcarded(word):
index[w].append(word)
现在,如果您要查找与“cat”相差一个字母的所有单词,只需查找“?at”、“c?t”和“ca?”并连接结果:
def near_words(word):
ret = []
for w in wildcarded(word):
ret += index[w]
return ret
print near_words('cat')
# outputs ['cat', 'bat', 'zat', 'jat', 'kat', 'rat', 'sat', 'pat', 'hat', 'oat', 'gat', 'vat', 'nat', 'fat', 'lat', 'wat', 'eat', 'yat', 'mat', 'tat', 'cat', 'cut', 'cot', 'cit', 'cay', 'car', 'cap', 'caw', 'cat', 'can', 'cam', 'cal', 'cad', 'cab', 'cag']
print near_words('stack')
# outputs ['stack', 'stack', 'smack', 'spack', 'slack', 'snack', 'shack', 'swack', 'stuck', 'stack', 'stick', 'stock', 'stank', 'stack', 'stark', 'stauk', 'stalk', 'stack']
如果最大字长为L,字数为N,则索引由O(NL)指针组成,而查找算法及时运行O(L + number of results)。
如果你想查找所有与K 字母而不是1 不同的单词,这种方法不能很好地概括,但它是一个非常难以完全概括的问题(这是寻找邻居的问题在汉明空间)。