Word Hunt游戏DFS算法无法找到最优解的技术问题排查
Word Hunt DFS算法问题排查与优化方案
问题排查
- 输出顺序逻辑错误:你在获取按长度降序排列的单词列表后调用了
longest_words.reverse(),导致输出顺序变为从短到长,所以前100个结果全是短单词,这是代码逻辑失误,并非算法找不到长单词。 - DFS路径复制效率低下:每次递归都复制
path集合,带来大量不必要的内存开销和时间消耗,对于较长的单词路径,可能因性能问题无法完成遍历,进而遗漏长单词。 - 无前缀剪枝:当前DFS会遍历所有可能的字母组合,即使当前前缀不在任何有效单词的开头,这会浪费大量时间在无效路径上,降低算法效率,甚至可能错过长单词的遍历。
- 单词列表验证缺失:需确认目标长单词(如
adulterations、unforgivingness)是否存在于你的单词列表中,若词库未包含这些单词,算法自然无法识别。
优化方案
1. 修复输出顺序
移除longest_words.reverse()调用,直接输出按长度降序排列的结果,最长单词会优先显示。
2. 优化DFS回溯方式
将路径复制改为原地修改+回溯,避免每次递归复制集合,大幅提升效率:
- 递归前将当前坐标加入
path - 递归完成后从
path中移除该坐标 - 直接传递原
path引用,无需复制
3. 实现前缀树(Trie)进行剪枝
将单词列表转换为前缀树,在DFS过程中实时检查当前前缀是否存在于Trie中:
- 如果当前前缀不是任何单词的前缀,直接终止该分支的递归
- 如果当前前缀是有效单词,加入结果集合
- 这种剪枝能减少90%以上的无效递归,显著提升遍历速度,确保找到所有可能的长单词
修改后的完整代码
import os import time class TrieNode: def __init__(self): self.children = {} self.is_end_of_word = False class Trie: def __init__(self): self.root = TrieNode() def insert(self, word): node = self.root for char in word: if char not in node.children: node.children[char] = TrieNode() node = node.children[char] node.is_end_of_word = True def search(self, word): node = self.root for char in word: if char not in node.children: return False node = node.children[char] return node.is_end_of_word def read_grid(): grid = [] for i in range(4): row = input(f"Enter row {i+1} (4 letters): ").strip().lower() if len(row) != 4 or not row.isalpha(): raise ValueError("Each row must contain exactly 4 letters.") grid.append(list(row)) return grid def read_word_list(file_path): file_path = os.path.expanduser("~/Self Projects/Word Hunt/word_list.txt") trie = Trie() word_set = set() with open(file_path, 'r') as file: for line in file: word = line.strip().lower() if len(word) >=3: trie.insert(word) word_set.add(word) return trie, word_set def find_words(grid, trie, word_set): directions = [(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)] found_words = set() rows, cols = len(grid), len(grid[0]) def dfs(x, y, path, current_word, node): if not (0 <= x < rows and 0 <= y < cols): return if (x, y) in path: return char = grid[x][y] if char not in node.children: return # 前缀不存在,剪枝 current_word += char current_node = node.children[char] # 如果当前是有效单词,加入结果 if current_node.is_end_of_word and current_word in word_set: found_words.add(current_word) # 回溯:加入路径 path.add((x, y)) for dx, dy in directions: dfs(x + dx, y + dy, path, current_word, current_node) # 回溯:移除路径 path.remove((x, y)) for i in range(rows): for j in range(cols): dfs(i, j, set(), "", trie.root) return found_words def word_hunt_solver(grid, trie, word_set): possible_words = find_words(grid, trie, word_set) # 按长度降序,长度相同按字母顺序升序排列 sorted_words = sorted(possible_words, key=lambda word: (-len(word), word)) return sorted_words[:100] if __name__ == "__main__": grid = read_grid() start_time = time.time() trie, word_set = read_word_list('word_list.txt') longest_words = word_hunt_solver(grid, trie, word_set) # 直接输出最长的单词在前 for word in longest_words: print(word) print(f"\nProgram Execution Time: {time.time() - start_time:.4f} seconds")
优化说明
- 前缀树剪枝:通过Trie节点遍历实现前缀检查,避免无效路径遍历,大幅提升效率。
- 回溯优化:采用原地修改路径的回溯方式,减少内存消耗和时间开销。
- 输出逻辑修复:移除反转操作,直接输出按长度降序的结果,确保最长单词优先显示。
- 单词集合验证:保留单词集合用于快速验证完整单词,避免Trie遍历的额外开销。
额外建议
- 检查你的单词列表,确认
adulterations、unforgivingness等目标单词是否存在,若不存在需补充词库。 - 4x4网格的最长单词长度为16,优化后的算法能高效遍历所有可能的长路径,确保不会遗漏有效单词。
内容的提问来源于stack exchange,提问作者Siddd
相关产品推荐
相关产品推荐

