深度优先算法-DFS(Deep-first Search)
- 用到了递归的思想
- DFS: 从root节点开始,尽可能深的搜索一个分支,把一个分支搜索结束之后再进行下一个分支
- DFS主要应用:二叉树搜索+图搜索
- DFS和回溯算法的区别:回溯算法 = DFS + 剪枝
二叉树的遍历
144-前序遍历
- 前序遍历:根节点-左子树-右子树
- 递归+广度优先搜索
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def preorderTraversal(self, root: TreeNode) -> List[int]:
def preorder(root:TreeNode):
# 递归的终止条件:节点上没有值
if root == None:
return
res.append(root.val)
preorder(root.left)
preorder(root.right)
res = []
preorder(root)
return res
- 栈+深度优先搜索
class Solution:
def preorderTraversal(self, root: TreeNode) -> List[int]:
stack = []
res = []
node = root
if root == None:
return res
while stack or node:
while node:
res.append(node.val)
stack.append(node)
node = node.left
node = stack.pop() # 向上寻找根节点
node = node.right # 遍历右子树
return res
94-中序遍历
- 中序遍历:左子树-根-右子树
- 递归+广度优先搜索
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
def inorder(root:TreeNode):
if root == None:
return
inorder(root.left)
res.append(root.val)
inorder(root.right)
res = []
inorder(root)
return res
- 栈+深度优先搜索
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
stack = [root]
res = []
while stack: # 栈不为空就循环
# 左子树中所有最左边的孩子进栈
while root.left:
stack.append(root.left)
root = root.left
cur = stack.pop() # 弹出一个左孩子记为当前节点,看它有没有右孩子
res.append(cur.val) # 每弹出一次记得记录一下
if cur.right: # 如果当前节点有右孩子的话,右孩子进栈,把这个右孩子当作新的根节点
stack.append(cur.right)
root = cur.right
return res
145-后序遍历
- 后序遍历:左子树-右子树-根
- 递归+广度优先搜索
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def postorderTraversal(self, root: TreeNode) -> List[int]:
def posterorder(root:TreeNode):
if root == None:
return
posterorder(root.left)
posterorder(root.right)
res.append(root.val)
res = []
posterorder(root)
return res
- 栈+深度优先搜索
class Solution:
def postorderTraversal(self, root: TreeNode) -> List[int]:
res = []
stack = []
prev = None
if root == None:
return res
while root or stack:
# 遍历最左子树的的节点
while root:
stack.append(root)
root = root.left
root = stack.pop()
if not root.right or root.right == prev:
res.append(root.val)
prev = root
root = None
else:
stack.append(root)
root = root.right
return res
102-层序遍历
- 队列+广度优先搜索
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
res = []
deque = []
if root == None:
return res
deque.append(root)
while deque:
size = len(deque) # size控制遍历的层数
list = []
while size > 0:
cur = deque.pop(0)
list.append(cur.val)
if cur.left:
deque.append(cur.left)
if cur.right:
deque.append(cur.right)
size -= 1
res.append(list)
return res
- 方法2:深度优先搜索:一条路走到黑
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
result = []
if root is None:
return result
self.dfs(root, result, 0) # 从第零层开始
return result
def dfs(self, node, result, level):
'''
node: 当前的节点
level:当前的层数
'''
# 递归终止条件
if node is None:
return
if level > len(result)-1: # 当前的层数大于result数组的长度-1时(0>-1)
result.append([]) # 添加一个空数组,保证可以添加该层的元素
result[level].append(node.val) # 添加元素到指定的层
if node.left is not None:
self.dfs(node.left, result, level+1)
if node.right is not None:
self.dfs(node.right, result, level+1)
617-合并二叉树
- 基本思想:使用 前序遍历
- 递归+深度优先搜索
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def mergeTrees(self, root1: TreeNode, root2: TreeNode) -> TreeNode:
def dfs(r1, r2):
if not r1:
return r2
if not r2:
return r1
r1.val = r1.val + r2.val # 在r1上进行合并
r1.left = dfs(r1.left, r2.left)
r1.right = dfs(r1.right, r2.right)
return r1
return dfs(root1, root2)
- 栈+广度优先搜索
class Solution:
def mergeTrees(self, root1: TreeNode, root2: TreeNode) -> TreeNode:
if not root1:
return root2
if not root2:
return root1
stack = [(root1, root2)]
while stack:
r1, r2 = stack.pop(0)
r1.val += r2.val
# 如果r1和r2的左子树都不为空,就放到队列中
# 如果r1的左子树为空,就把r2的左子树挂到r1的左子树上
if r1.left and r2.left:
stack.append((r1.left, r2.left))
elif r1.left == None:
r1.left = r2.left
if r1.right and r2.right:
stack.append((r1.right, r2.right))
elif r1.right == None:
r1.right = r2.right
return root1
938-二叉搜索树的范围和
输入:root = [10, 5, 15, 3, 7, null, 18], low=7, high=15
输出:32
解释:返回值为位于[low, high]之间的所有结点的和
class Solution:
def rangeSumBST(self, root: TreeNode, low: int, high: int) -> int:
# 递归法
result = 0
if root is None: # 递归的终止条件
return 0
leftSum = self.rangeSumBST(root.left, low, high) # 左子树符合条件的和
rightSum = self.rangeSumBST(root.right, low, high) # 右子树符合条件的和
result = leftSum + rightSum
if root.val >= low and root.val <= high: # 条件符合的值
result += root.val
return result
10 | ||||
5 | 15 | |||
3 | 7 | null | 18 |
大树满足条件的和 等于 每个子树满足条件的数的和之和
2) DFS方法
class Solution:
def rangeSumBST(self, root: TreeNode, low: int, high: int) -> int:
# dfs法
result = 0
queue = [] # 辅助队列
queue.append(root)
while len(queue) > 0: # 队列不为空
size = len(queue)
while size > 0:
cur = queue.pop()
if cur.val >= low and cur.val <= high:
result += cur.val
if cur.left is not None: # 存在左子树
queue.append(cur.left)
if cur.right is not None: # 存在右子树
queue.append(cur.right)
size -= 1 # size控制每一层遍历
return result
栈的长度 | ||||||
---|---|---|---|---|---|---|
1 | 10 | |||||
2 | 15 | 5 | ||||
2 | 7 | 3 | ||||
3 | 18 | 7 | 3 |
result = 0 + 10 + 15 + 18
200. 岛屿数量
输入:grid = [
["1","1","0","0","0"],
["1","1","0","0","0"],
["0","0","1","0","0"],
["0","0","0","1","1"]
]
输出:3
解释:
["1","1"] ; "1"
["1","1"] ; "1","1"
方法1:DFS
深度优先搜索必然会使用到递归
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
if grid is None or len(grid) == 0:
return 0
result = 0
row = len(grid) # 行数
col = len(grid[0]) # 列数
# 找岛屿,同化
for i in range(row):
for j in range(col):
if grid[i][j] == '1':
result += 1
self.dfs(grid, i, j, row, col) # 同化:把 1 变为 0
return result
def dfs(self, grid, x, y, row, col):
# 递归的终止条件
if x < 0 or y < 0 or x >= row or y >= col or grid[x][y] == '0':
return
grid[x][y] = '0' # 将 ‘1’变为 ‘0’
# 上\下\左\右 查找可变为‘0’的区域
self.dfs(grid, x-1, y, row, col)
self.dfs(grid, x+1, y, row, col)
self.dfs(grid, x, y-1, row, col)
self.dfs(grid, x, y+1, row, col)
方法2:广度优先搜索
必须使用到辅助队列,用于判断
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
if grid is None or len(grid) == 0:
return 0
result = 0
row = len(grid)
col = len(grid[0])
q = [] # 辅助队列
for i in range(0, row):
for j in range(0, col):
if grid[i][j] == '1':
result = result + 1
q.append([i,j])
grid[i][j] = '0'
while len(q) > 0:
cur = q.pop(0) # 出队
x = cur[0]
y = cur[1]
# 如果位置坐标为‘1’同化之后添加坐标至队列中,
# 如果同化全部完成,坐标只会出列
if x-1 >= 0 and grid[x-1][y] == '1':
grid[x-1][y] = '0'
q.append([x-1, y])
if y-1 >= 0 and grid[x][y-1] == '1':
grid[x][y-1] = '0'
q.append([x, y-1])
if x+1 < row and grid[x+1][y] == '1':
grid[x+1][y] = '0'
q.append([x+1, y])
if y+1 < col and grid[x][y+1] == '1':
grid[x][y+1] = '0'
q.append([x, y+1])
return result
方法3:并查集
找到共同的祖先
- Union(x,y):合并x,y为同一个祖先
- Find(x):找x的祖先 x=root[x]
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
if grid == None or len(grid) == 0:
return 0
row = len(grid)
col = len(grid[0])
waters = 0 # 水域
uf = UnionFind(grid) # 实例化类
for i in range(0, row):
for j in range(0, col):
if grid[i][j] == '0':
waters = waters + 1
# 实现同化
else:
directions = [[0,1], [0,-1], [1,0], [-1,0]]
for d in directions:
x = i + d[0]
y = j + d[1]
if x>=0 and x=0 and y
733-图像渲染
对相同像素的相邻位置进行渲染
- 方法1:深度优先搜索
class Solution:
def floodFill(self, image: List[List[int]], sr: int, sc: int, newColor: int) -> List[List[int]]:
row = len(image)
col = len(image[0])
color = image[sr][sc] # 获取需要渲染的像素
# 当需要渲染的像素和目标像素值相等时,不需要渲染
if color == newColor:
return image
# 深度优先搜索
def dfs(r, c):
if image[r][c] == color:
image[r][c] = newColor
# 向上渲染
if r >= 1:
dfs(r-1, c)
# 向下渲染
if r+1 < row:
dfs(r+1, c)
# 向左渲染
if c >= 1:
dfs(r, c-1)
# 向右渲染
if c+1 < col:
dfs(r, c+1)
dfs(sr, sc)
return image
- 方法2:广度优先搜索
from queue import Queue
class Solution:
def floodFill(self, image: List[List[int]], sr: int, sc: int, newColor: int) -> List[List[int]]:
if image[sr][sc] == newColor:
return image
# 设置四个方向的偏移量,上,下,左,右
directions = {(-1,0), (1,0), (0,-1), (0,1)}
# 构造一个队列,放入起始点
que = Queue()
que.put((sr, sc))
# 记录初始颜色
initcolor = image[sr][sc]
# 当队列不为空
while not que.empty():
# 取出队列的点进行染色
point = que.get()
image[point[0]][point[1]] = newColor
# 遍历四个方向
for direction in directions:
# 新的点(new_i, new_j),行和列
new_i = point[0] + direction[0]
new_j = point[1] + direction[1]
# 如果这个点在定义域内 且 颜色与初始点颜色相同
if 0 <= new_i < len(image) and 0 <= new_j < len(image[0]) and image[new_i][new_j] == initcolor:
que.put((new_i, new_j))
return image
695-岛屿的最大面积
给定一个包含了一些 0 和 1 的非空二维数组 grid 。
一个 岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在水平或者竖直方向上相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着。
找到给定的二维数组中最大的岛屿面积。(如果没有岛屿,则返回面积为 0 。)
- 深度优先搜索
class Solution:
def maxAreaOfIsland(self, grid: List[List[int]]) -> int:
ans = 0
# i和j为网格的坐标位置
for i, l in enumerate(grid):
for j, n in enumerate(l):
ans = max(self.dfs(grid, i, j), ans)
return ans
def dfs(self, grid, cur_i, cur_j) -> int:
# 超出范围,递归终止条件-所有的网格节点全部变为0
if cur_i < 0 or cur_j < 0 or cur_i == len(grid) or cur_j == len(grid[0]) or grid[cur_i][cur_j] != 1:
return 0
grid[cur_i][cur_j] = 0
ans = 1
# 对相邻位置进行搜索并记录每个岛屿的面积
for di, dj in [[0,1], [0,-1], [1,0], [-1,0]]:
next_i, next_j = cur_i + di, cur_j + dj
ans += self.dfs(grid, next_i, next_j)
return ans
- 栈+广度优先搜索
class Solution:
def maxAreaOfIsland(self, grid: List[List[int]]) -> int:
ans = 0
for i, l in enumerate(grid):
for j, n in enumerate(l):
cur = 0
stack = [(i,j)]
while stack:
cur_i, cur_j = stack.pop()
if cur_i < 0 or cur_j < 0 or cur_i == len(grid) or cur_j == len(grid[0]) or grid[cur_i][cur_j] != 1:
continue
cur += 1
grid[cur_i][cur_j] = 0
for di, dj in [[0,1], [0,-1], [1, 0], [-1, 0]]:
next_i, next_j = cur_i + di, cur_j + dj
stack.append((next_i, next_j))
ans = max(ans, cur)
return ans