加快 Trie 中的单词搜索
Speeding up word search in a Trie
我需要找到所有可以使用用户指定的字母组成的单词。用户可以使用“?” - 作为通配符(最多 2 个通配符)。最大输入为 15 个字符,包括那些通配符。输入示例:"abcdefghijklm??".
目前我有 2_700_000 个单词存储在 Trie 中。我是这样查的:
def search_word(node, wildcards, alphabet, tiles, output)
output.push(node.full_state) if node.terminal? # append output if its a word
unless tiles.empty? && wildcards.zero?
tiles.uniq.each do |tile|
unless node.walk(tile).nil? # choose only those letters that could possibly make a word
next_node = node.walk(tile)
remaining_tiles = take_away(tiles, tile)
search_word(next_node, wildcards, alphabet, remaining_tiles, output)
end
end
end
if wildcards > 0
other_letters = take_away(alphabet, tiles.uniq) # letters that weren't used in previous loop
other_letters.each do |tile|
unless node.walk(tile).nil? # only those that could make a word
next_node = node.walk(tile)
remaining_tiles = take_away(tiles, tile)
remaining_wildcards = wildcards - 1
search_word(next_node, remaining_wildcards, alphabet, tiles, output)
end
end
end
end
它的作用可以描述为:
def searchword(trie, wildcards, tiles, output):
if trie is word:
output.append(trie.word) # or send current letters as arguments to this function
for each unique tile in tiles:
if trie has tile:
searchword(trie[tile], wildcards, (tiles - tile), output)
if wildcards > 0:
for each key in trie that has not already been searched in previous loop:
searchword(trie[key], (wildcards - 1), tiles, output)
速度测试:
15 个字母输入,无通配符:0.45 秒
15 个字母输入,一个通配符:3,54 秒
15个字母输入,两个通配符:15,59s
网上有很多拼字游戏求解器,可以在 1 秒内完成此类任务。
问题
如何加快这个过程,让我每次花费不到 1 秒?我正在考虑:
a) 用 C 编写搜索方法
b) 重新组织 Trie,以便单词按字母顺序存储(例如 fast -> afst)——这将减少搜索次数
如果您知道完成此特定任务的更好方法,我愿意倾听。
c) 将我的 Trie 切换为哈希 table?
您应该选择选项 b,按字母顺序存储所有字谜。不重温信件是一个巨大的胜利。
除非不按字母顺序排序。按以下顺序对字母进行排序:etaoinshrdlcumwfgypbvkjxqz
。从最频繁到最不频繁。这个想法是只看最常见的字母最少次数,而不是一遍又一遍。
我需要找到所有可以使用用户指定的字母组成的单词。用户可以使用“?” - 作为通配符(最多 2 个通配符)。最大输入为 15 个字符,包括那些通配符。输入示例:"abcdefghijklm??".
目前我有 2_700_000 个单词存储在 Trie 中。我是这样查的:
def search_word(node, wildcards, alphabet, tiles, output)
output.push(node.full_state) if node.terminal? # append output if its a word
unless tiles.empty? && wildcards.zero?
tiles.uniq.each do |tile|
unless node.walk(tile).nil? # choose only those letters that could possibly make a word
next_node = node.walk(tile)
remaining_tiles = take_away(tiles, tile)
search_word(next_node, wildcards, alphabet, remaining_tiles, output)
end
end
end
if wildcards > 0
other_letters = take_away(alphabet, tiles.uniq) # letters that weren't used in previous loop
other_letters.each do |tile|
unless node.walk(tile).nil? # only those that could make a word
next_node = node.walk(tile)
remaining_tiles = take_away(tiles, tile)
remaining_wildcards = wildcards - 1
search_word(next_node, remaining_wildcards, alphabet, tiles, output)
end
end
end
end
它的作用可以描述为:
def searchword(trie, wildcards, tiles, output):
if trie is word:
output.append(trie.word) # or send current letters as arguments to this function
for each unique tile in tiles:
if trie has tile:
searchword(trie[tile], wildcards, (tiles - tile), output)
if wildcards > 0:
for each key in trie that has not already been searched in previous loop:
searchword(trie[key], (wildcards - 1), tiles, output)
速度测试: 15 个字母输入,无通配符:0.45 秒 15 个字母输入,一个通配符:3,54 秒 15个字母输入,两个通配符:15,59s
网上有很多拼字游戏求解器,可以在 1 秒内完成此类任务。
问题 如何加快这个过程,让我每次花费不到 1 秒?我正在考虑: a) 用 C 编写搜索方法 b) 重新组织 Trie,以便单词按字母顺序存储(例如 fast -> afst)——这将减少搜索次数 如果您知道完成此特定任务的更好方法,我愿意倾听。 c) 将我的 Trie 切换为哈希 table?
您应该选择选项 b,按字母顺序存储所有字谜。不重温信件是一个巨大的胜利。
除非不按字母顺序排序。按以下顺序对字母进行排序:etaoinshrdlcumwfgypbvkjxqz
。从最频繁到最不频繁。这个想法是只看最常见的字母最少次数,而不是一遍又一遍。