DFS
详细介绍
秉承不撞南墙不回头的道理,标记当前节点,从当前节点出发采用递归的方式访问相邻的节点,一直到底。
递归出口:1.已经访问完从当前节点一直相邻的所有节点为止、2.超出边界、此当前节点已经被访问。
当前节点已遍历结束,对下一个未被标记的节点进行同样的上述操作。
实例
1. 剑指offer13机器人的运动范围
解题思路
深度优先遍历走所有的格子
判断 超出方格边界、走到之前访问的格子、数位之和超过k 则直接返回 return 0
否则 一直向下或者向右遍历,且递归一次成功的个数+1
class Solution:
def movingCount(self, m: int, n: int, k: int) -> int:
# 计算位之和
def wei(x):
sum = 0
while x:
sum += x%10
x = x // 10
return sum
# 深度优先遍历
def dfs(i,j):
# 超出方格边界
if i >= m or j >= n:
return 0
# 走到之前访问过的位置
if (i, j) in res:
return 0
# 障碍物,位数之和大于k
weii, weij = wei(i), wei(j)
if weii + weij > k:
return 0
# 成功格子的下标
res.add((i,j))
# 向下或者向右移动,成功个数+1
return 1 + dfs(i+1, j) + dfs(i, j+1)
res = set()
count = dfs(0, 0)
return count #return len(count)也可以
2. 695岛屿的最大面积
解题思路
深度优先,当单元格为1时传入DFS,然后递归前后左右,同时在走过的格子标为0避免重复计算,递归一圈长度+1
class Solution:
def maxAreaOfIsland(self, grid: List[List[int]]) -> int:
# 典型深度优先,当单元格为1时传入DFS,然后递归前后左右,同时在走过的格子标为0避免重复计算,递归一圈长度+1
m, n = len(grid),len(grid[0])
def dfs(i, j):
# 递归出口:i、j超出边界、单元格不等于1
if i < 0 or i >= m or j < 0 or j >= n or grid[i][j]==0:
return 0
grid[i][j] = 0
# 递归当前单元格的上下左右
return 1 + dfs(i+1, j) + dfs(i-1, j) + dfs(i, j+1) + dfs(i, j-1)
res = 0
for i in range(m):
for j in range(n):
if grid[i][j]==1:
res = max(res, dfs(i, j))
return res
3. 200. 岛屿数量
解题思路
当找到一个岛屿,递归周围的所有相邻岛屿,并将岛屿制为0,count+=1,然后找下一堆岛屿
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
m, n = len(grid), len(grid[0])
def dfs(i, j):
# 递归出口:超过边界、不是岛屿
if i < 0 or i >= m or j < 0 or j >= n or grid[i][j]=='0':
return 0
# 将岛屿制为0避免重复搜索
grid[i][j] = '0'
# 递归当前岛屿的上下左右
dfs(i + 1, j)
dfs(i, j + 1)
dfs(i - 1, j)
dfs(i, j - 1)
count = 0
for i in range(m):
for j in range(n):
if grid[i][j] == '1':
dfs(i, j)
count += 1
return count
4. 剑指 Offer 12. 矩阵中的路径
解题思路
DFS+回溯,与以往DFS不同的是,一轮中把走过的点清除但是到下一轮循环之前要恢复原来的值即回溯
class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
m,n = len(board),len(board[0])
def dfs(i,j,k):
# 递归出口:超出边界、当前值不同
if i < 0 or i >= m or j < 0 or j >= n or board[i][j] != word[k]:
return False
if k == len(word) - 1:
return True
board[i][j] = '' # 把这轮走过的点清除避免重复
# 递归上下左右,并且连续正确的长度+1,res代表是否成功的标记
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] = word[k]
return res
for i in range(m):
for j in range(n):
# 如果dfs返回true则存在,k表示连续正确的长度
if dfs(i,j,0):
return True
return False
题目来源:https://leetcode.cn/problemset/all/
解题来源:作者的leetcode题解
同时参考了很多大佬的答案解析,得到了很多比较棒的思路
自己做笔记记录使用