[212][困难][DFS] 单词搜索 II
题目描述
给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。
示例:
输入:
words = ["oath","pea","eat","rain"] and board =
[
['o','a','a','n'],
['e','t','a','e'],
['i','h','k','r'],
['i','f','l','v']
]
输出: ["eat","oath"]
说明:
你可以假设所有输入都由小写字母 a-z 组成。
提示:
你需要优化回溯算法以通过更大数据量的测试。你能否早点停止回溯?
如果当前单词不存在于所有单词的前缀中,则可以立即停止回溯。什么样的数据结构可以有效地执行这样的操作?散列表是否可行?为什么? 前缀树如何?如果你想学习如何实现一个基本的前缀树,请先查看这个问题:实现Trie(前缀树)。
解题思路
DFS + Trie树
[[剑指Offer-12][中等][DFS] 矩阵中的路径的扩展版. 搜索是否包含多个单词, 使用前缀Trie树减少遍历次数. DFS的思路与前面题目中的一样, 只是剪枝条件变了:
索引超越边界, 剪枝
当前前缀不在树中, 剪枝
搜索到单词就添加到结果中, 但不能停止, 因为可能是另一个单词的前缀.
class Trie:
def __init__(self):
self.root = dict()
def insert(self, word):
root = self.root
for c in word + '&':
if c not in root:
root[c] = dict()
root = root[c]
@lru_cache(None)
def search(self, word):
root = self.root
for c in word:
if c not in root:
return False
root = root[c]
return True if '&' in root else False
@lru_cache(None)
def startwith(self, prefix):
root = self.root
for c in prefix:
if c not in root:
return False
root = root[c]
return True
class Solution:
def findWords(self, board: List[List[str]], words: List[str]) -> List[str]:
n, m = len(board), len(board[0])
trie = Trie()
for w in words:
trie.insert(w)
res = set()
def dfs(i, j, prefix):
if not 0 <= i < n or not 0 <= j < m:
return False
new_prefix = prefix + board[i][j]
if not trie.startwith(new_prefix):
return False
if trie.search(new_prefix):
res.add(new_prefix)
tmp, board[i][j] = board[i][j], '/'
t = dfs(i + 1, j, new_prefix) or dfs(i - 1, j, new_prefix) or dfs(i, j + 1, new_prefix) or dfs(i, j - 1, new_prefix)
board[i][j] = tmp
return t
for i in range(n):
for j in range(m):
dfs(i, j, '')
return list(res)
最后更新于
这有帮助吗?