LeetCode 热题 100 79. 单词搜索
LeetCode 热题 100 | 79. 单词搜索
大家好,今天我们来解决一道经典的算法题——单词搜索。这道题在 LeetCode 上被标记为中等难度,要求判断一个字符串 word
是否存在于一个二维字符网格 board
中。单词必须通过相邻单元格内的字母构成,相邻单元格可以是水平或垂直方向的,且同一个单元格内的字母不能被重复使用。
问题描述
给定一个 m x n
的二维字符网格 board
和一个字符串 word
,判断 word
是否存在于网格中。
示例 1:
输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
输出:true
示例 2:
输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "SEE"
输出:true
示例 3:
输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCB"
输出:false
提示:
1 <= m, n <= 6
1 <= word.length <= 15
board
和word
仅由大小写英文字母组成。
解题思路
核心思想
-
深度优先搜索(DFS):
- 从网格的每个单元格开始,尝试匹配单词的第一个字符。
- 如果匹配成功,递归地搜索相邻单元格,匹配单词的下一个字符。
-
避免重复访问:
- 使用一个临时标记(如
''
或'0'
)将已访问的单元格标记为不可用,搜索完成后恢复其值。
- 使用一个临时标记(如
-
剪枝优化:
- 如果当前路径无法匹配单词,立即回溯,避免无效搜索。
- 提前检查单词中的字符是否在网格中出现足够的次数,如果不足,直接返回
false
。
-
优化搜索方向:
- 如果单词的最后一个字符在网格中出现次数较少,可以将单词反转后再搜索,减少搜索路径。
Python代码实现
class Solution:def exist(self, board, word):""":type board: List[List[str]]:type word: str:rtype: bool"""def dfs(i, j, k):# 如果超出边界或当前单元格不匹配,返回 Falseif not (0 <= i < len(board) and 0 <= j < len(board[0])) or board[i][j] != word[k]:return False# 如果匹配到单词的最后一个字符,返回 Trueif k == len(word) - 1:return True# 标记当前单元格为已访问temp, board[i][j] = board[i][j], ''# 搜索上下左右四个方向res = dfs(i + 1, j, k + 1) or dfs(i - 1, j, k + 1) or dfs(i, j + 1, k + 1) or dfs(i, j - 1, k + 1)# 恢复当前单元格的值board[i][j] = tempreturn res# 预剪枝:检查单词中的字符是否在网格中出现足够的次数from collections import Counterboard_chars = Counter(ch for row in board for ch in row)word_chars = Counter(word)if any(board_chars[ch] < word_chars[ch] for ch in word_chars):return False# 如果单词的最后一个字符在网格中出现次数较少,反转单词if board_chars[word[-1]] < board_chars[word[0]]:word = word[::-1]# 遍历网格的每个单元格,尝试匹配单词for i in range(len(board)):for j in range(len(board[0])):if dfs(i, j, 0):return Truereturn False
代码解析
-
DFS 函数:
dfs(i, j, k)
表示从网格的(i, j)
位置开始,匹配单词的第k
个字符。- 如果当前单元格超出边界或不匹配,返回
False
。 - 如果匹配到单词的最后一个字符,返回
True
。 - 使用临时标记避免重复访问,搜索完成后恢复单元格的值。
-
剪枝优化:
- 在开始搜索前,检查单词中的每个字符是否在网格中出现足够的次数。如果不足,直接返回
false
。
- 在开始搜索前,检查单词中的每个字符是否在网格中出现足够的次数。如果不足,直接返回
-
优化搜索方向:
- 如果单词的最后一个字符在网格中出现次数较少,可以将单词反转后再搜索,减少搜索路径。
-
遍历网格:
- 从网格的每个单元格开始,调用
dfs
函数尝试匹配单词。
- 从网格的每个单元格开始,调用
复杂度分析
- 时间复杂度:O(M × N × 4^L),其中
M
和N
是网格的行数和列数,L
是单词的长度。 - 空间复杂度:O(L),递归的深度最大为单词的长度。
示例运行
示例 1
输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
输出:true
示例 2
输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "SEE"
输出:true
示例 3
输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCB"
输出:false
总结
通过深度优先搜索(DFS)和剪枝优化,我们可以高效地解决单词搜索问题。这种方法在网格较大时也能快速返回结果,避免不必要的搜索。希望这篇题解对大家有所帮助,如果有任何问题,欢迎在评论区留言讨论!
关注我,获取更多算法题解和编程技巧!