递归问题总结——单词搜索
总结:
- 递归问题一般是搜索一个可行解,而非从很多解中找到最优解(动态规划)
- 递归是向前的试探搜索,试探搜索过程中有记录状态的变量时,如果当前步not return true,记得记录状态变量的复原
- 递归中的return true,只有n=1时,才return true;其他时候满足条件时,则继续搜索,否则进行剪枝,return false。
题目
给定一个二维网格和一个单词,找出该单词是否存在于网格中。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
示例:
board =
[
['A','B','C','E'],
['S','F','C','S'],
['A','D','E','E']
]
给定 word = "ABCCED", 返回 true.
给定 word = "SEE", 返回 true.
给定 word = "ABCB", 返回 false.
代码
class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
# 1. 需要记录已经走过的位置
# 2. 判断一步,移动一步
# 3. 找到初始位置
if len(word) == 0:
return True
self.dir = [[-1,0],[0,-1],[1,0],[0,1]]
self.row = len(board)
self.col = len(board[0])
visited = [[0] * self.col for _ in range(self.row)]
# 第一层循环找开始点
for i in range(self.row):
for j in range(self.col):
if board[i][j] == word[0]:
visited = [[0] * self.col for _ in range(self.row)]
if self.dfs(word, board, visited, i, j):
return True
return False
# 递归函数
def dfs(self, word, board, visited, i, j):
if len(word) == 0: # 递归的结束条件
return True
if len(word) == 1 and word[0] == board[i][j]:
return True
if word[0] == board[i][j]: # 如何通过则继续搜索
visited[i][j] = 1
# return True # 千万不能return true,这只是中间一步满足要求
else:
return False # 剪支
for k in range(4):
nextx, nexty = i + self.dir[k][0], j + self.dir[k][1] # 移动一步
if self.legal(nextx, nexty, visited):
if self.dfs(word[1:], board, visited, nextx, nexty):
return True
else:
visited[nextx][nexty] = 0 # 恢复现场,因为递归是试探性的,所以要恢复一些变量
return False
def legal(self, x, y, visited):
# 每移动一步的合法性判断
if 0 <= x < self.row and 0 <= y < self.col and visited[x][y] != 1:
# if self.visited[x][y] == 0:
return True
else:
return False
总体流程和注意的细节具体可以看代码注释