算法题汇总 广度优先搜索 & 深度优先搜索

深度优先搜索

DFS模板

733. 图像渲染

有一幅以二维整数数组表示的图画,每一个整数表示该图画的像素值大小,数值在 0 到 65535 之间。

给你一个坐标 (sr, sc) 表示图像渲染开始的像素值(行 ,列)和一个新的颜色值 newColor,让你重新上色这幅图像。

为了完成上色工作,从初始坐标开始,记录初始坐标的上下左右四个方向上像素值与初始坐标相同的相连像素点,接着再记录这四个方向上符合条件的像素点与他们对应四个方向上像素值与初始坐标相同的相连像素点,……,重复该过程。将所有有记录的像素点的颜色值改为新的颜色值。

最后返回经过上色渲染后的图像。

DFS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
"""先递归,再判断条件"""
class Solution(object):
def floodFill(self, image, sr, sc, newColor):
"""
:type image: List[List[int]]
:type sr: int
:type sc: int
:type newColor: int
:rtype: List[List[int]]
"""
m,n,color=len(image),len(image[0]),image[sr][sc]

def dfs(i,j):
# 不合法状态1:坐标(i,j)超越了边界,直接返回
if i<0 or i>=m or j<0 or j>=n:
return
# 不合法状态2:坐标点颜色等于新颜色、或与初始点颜色不相同,直接返回
if image[i][j]==newColor or image[i][j]!=color:
return
# 合法状态:切记先改变颜色,再从四个方向继续搜索
image[i][j]=newColor
for x,y in zip((1,-1,0,0),(0,0,1,-1)):
dfs(i+x,j+y)

dfs(sr,sc) # 因为递归函数里面,是先判断条件,再递归,所以再调用递归函数是,不需要先判断条件
return image
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
"""先判断条件,再递归"""
class Solution(object):
def floodFill(self, image, sr, sc, newColor):
"""
:type image: List[List[int]]
:type sr: int
:type sc: int
:type newColor: int
:rtype: List[List[int]]
"""
m, n, color= len(image), len(image[0]), image[sr][sc]

def dfs(i, j):
image[i][j]=newColor # 先判断条件,再递归
for x, y in ((i+1,j),(i-1,j),(i,j+1),(i,j-1)):
if 0<=x<m and 0<=y<n and image[x][y]==color:
dfs(x,y)
if color!=newColor: # 先判断条件,再递归(因为递归函数具体定义,是设定了坐标点符合条件,再更改颜色,再从四个方向去进一步递归)
dfs(sr,sc)

return image

BFS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution(object):
def floodFill(self, image, sr, sc, newColor):
"""
:type image: List[List[int]]
:type sr: int
:type sc: int
:type newColor: int
:rtype: List[List[int]]
"""
m, n, color= len(image), len(image[0]), image[sr][sc]

if color!=newColor:
queue=collections.deque([[sr,sc]])
while queue:
i,j=queue.popleft()
image[i][j]=newColor
for x,y in ((i+1,j),(i-1,j),(i,j+1),(i,j-1)):
if 0<=x<m and 0<=y<n and image[x][y]==color:
queue.append([x,y])
return image

130.被围绕的区域

给定一个二维的矩阵,包含 ‘X’ 和 ‘O’(字母 O)。

找到所有被 ‘X’ 围绕的区域,并将这些区域里所有的 ‘O’ 用 ‘X’ 填充。

DFS

将边界上及与边界上的’O’相连的’O’标记为’G’,然后将所有标记’G’的改为’O’,其他标记为’X’

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
class Solution(object):
def solve(self, board):
"""
:type board: List[List[str]]
:rtype: None Do not return anything, modify board in-place instead.
"""
if not board or not board[0]:
return
m,n=len(board),len(board[0])

def dfs(board, i, j):
if i<0 or i>=m or j<0 or j>=n or board[i][j]!='O':
return
board[i][j]='G'
for x,y in zip((1,-1,0,0),(0,0,1,-1)):
dfs(board, i+x, j+y)

for i in range(m):
for j in range(n):
if (i==0 or i==m-1 or j==0 or j==n-1) and board[i][j]=='O':
dfs(board, i, j)
# for i in range(n):
# if board[0][i]=='O':
# dfs(board,0,i)
# if board[m-1][i]=='O':
# dfs(board,m-1,i)
#
# for i in range(m):
# if board[i][0]=='O':
# dfs(board,i,0)
# if board[i][n-1]=='O':
# dfs(board,i,n-1)

for i in range(m):
for j in range(n):
if board[i][j]=='G':
board[i][j]='O'
else:
board[i][j]='X'
```

#### BFS
```python
class Solution(object):
def solve(self, board):
"""
:type board: List[List[str]]
:rtype: None Do not return anything, modify board in-place instead.
"""
if not board or not board[0]:
return
m,n=len(board),len(board[0])

def bfs(board, i, j):
queue=collections.deque([[i,j]])
board[i][j]='G'
while queue:
i,j=queue.popleft()
for x, y in zip((1,-1,0,0),(0,0,1,-1)):
if 0<=i+x<m and 0<=j+y<n and board[i+x][j+y]=='O':
queue.append([i+x,j+y])
board[i+x][j+y]='G'


for i in range(m):
for j in range(n):
if (i==0 or i==m-1 or j==0 or j==n-1) and board[i][j]=='O':
bfs(board, i, j)

for i in range(m):
for j in range(n):
if board[i][j]=='G':
board[i][j]='O'
else:
board[i][j]='X'
```


### [200.岛屿的个数](https://leetcode-cn.com/problems/number-of-islands/submissions/)
给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。

#### DFS
```Python
class Solution(object):
def numIslands(self, grid):
"""
:type grid: List[List[str]]
:rtype: int
"""
if not grid or not grid[0]:
return 0

m,n=len(grid),len(grid[0])
count=0
for i in range(m):
for j in range(n):
if grid[i][j]=='1':
count+=1
self.dfs(grid, i, j)
return count

def dfs(self, grid, i, j):
if i<0 or i>=len(grid) or j<0 or j>=len(grid[0]) or grid[i][j]=='0':
return
grid[i][j]='0'
for x,y in ((i+1,j),(i-1,j),(i,j+1),(i,j-1)):
self.dfs(grid, x, y)

BFS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Solution(object):
def numIslands(self, grid):
"""
:type grid: List[List[str]]
:rtype: int
"""
if not grid or not grid[0]:
return 0

m,n=len(grid),len(grid[0])
count=0
for i in range(m):
for j in range(n):
if grid[i][j]=='1':
count+=1
self.bfs(grid, i, j)
return count

def bfs(self, grid, i, j):
queue=collections.deque([[i,j]])
grid[i][j]='0'
while queue:
i,j=queue.popleft()
for x,y in ((i+1,j),(i-1,j),(i,j+1),(i,j-1)):
if 0<=x<len(grid) and 0<=y<len(grid[0]) and grid[x][y]=='1':
grid[x][y]='0'
queue.append([x,y])

01矩阵

给定一个由 0 和 1 组成的矩阵,找出每个元素到最近的 0 的距离。

两个相邻元素间的距离为 1 。

DFS (超时)

从0开始入手,超时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution(object):
def updateMatrix(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: List[List[int]]
"""
if not matrix or not matrix[0]:
return []

m,n=len(matrix),len(matrix[0])
for i in range(m):
for j in range(n):
if matrix[i][j]==1:
matrix[i][j]=float('inf')

for i in range(m):
for j in range(n):
if matrix[i][j]==0:
self.dfs(matrix, i, j, 0)

return matrix

def dfs(self, matrix, i, j, d):
if i<0 or i>=len(matrix) or j<0 or j>=len(matrix[0]) or matrix[i][j]<d:
return
matrix[i][j]=d
for x, y in ((i+1,j),(i-1,j),(i,j+1),(i,j-1)):
self.dfs(matrix, x, y, d+1)

DFS

从与0相邻的1开始

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution(object):
def updateMatrix(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: List[List[int]]
"""
if not matrix or not matrix[0]:
return []

m,n=len(matrix),len(matrix[0])
for i in range(m):
for j in range(n):
mark=((i>0 and matrix[i-1][j]==0) or (i+1<m and matrix[i+1][j]==0) or \
(j>0 and matrix[i][j-1]==0) or (j+1<n and matrix[i][j+1]==0))
if matrix[i][j]==1 and not mark:
matrix[i][j]=float('inf')


def dfs(matrix, i, j):
for x,y in zip((i+1,i-1,i,i),(j,j,j+1,j-1)):
if 0<=x<m and 0<=y<n and matrix[x][y]>matrix[i][j]+1:
matrix[x][y]=matrix[i][j]+1
dfs(matrix,x,y)

for i in range(m):
for j in range(n):
if matrix[i][j]==1:
dfs(matrix, i, j)
return matrix

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class Solution(object):
# def updateMatrix(self, matrix):
# """
# :type matrix: List[List[int]]
# :rtype: List[List[int]]
# """
# """BFS, 将0作为迷宫的入口,多个入口入栈,然后遍历四周,在入栈(没有访问过的入栈)"""
# m, n = len(matrix), len(matrix[0])
# queue = []
# #集合查找的复杂度为O(1)
# visited = set()
# # 将0的位置作为始点并加入,类似于迷宫的入口。这里有多个入口
# for i in range(m):
# for j in range(n):
# if matrix[i][j] == 0:
# queue.append((i, j))
# visited.add((i, j))
# # 将所有相邻节点加入队列
# while queue:
# i, j = queue[0]
# del queue[0]
# for x, y in [(i+1, j), (i-1, j), (i, j+1), (i, j-1)]:
# if 0 <= x < m and 0 <= y < n and (x, y) not in visited:
# matrix[x][y] = matrix[i][j] + 1
# visited.add((x, y))
# queue.append((x, y))
# return matrix

"""DFS解法尝试"""
def updateMatrix(self, matrix):
m, n = len(matrix), len(matrix[0])
for i in range(m):
for j in range(n):
mark = ((i>0 and matrix[i-1][j]==0) or (i+1<m and matrix[i+1][j]==0)
or (j>0 and matrix[i][j-1]==0) or (j+1<n and matrix[i][j+1]==0))
if matrix[i][j] == 1 and not mark:
matrix[i][j] = m+n
for i in range(m):
for j in range(n):
if matrix[i][j]==1:
self.DFS(matrix, i, j, m, n)
return matrix

def DFS(self, matrix, i, j, m, n):
for x, y in [(i+1, j), (i-1, j), (i, j+1), (i, j-1)]:
if 0 <= x < m and 0 <= y < n and matrix[x][y] > matrix[i][j] + 1:
matrix[x][y] = matrix[i][j] + 1
self.DFS(matrix, x, y, m, n)

BFS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution(object):
def updateMatrix(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: List[List[int]]
"""
if not matrix or not matrix[0]:
return matrix

m,n=len(matrix),len(matrix[0])
queue=collections.deque()
for i in range(m):
for j in range(n):
if matrix[i][j]!=0:
matrix[i][j]=float('inf')
else:
queue.append([i,j])


while queue:
r,c=queue.popleft()
for x,y in ((r+1,c),(r-1,c),(r,c+1),(r,c-1)):
if 0<=x<m and 0<=y<n and matrix[x][y]>matrix[r][c]+1:
matrix[x][y]=matrix[r][c]+1
queue.append([x,y])
return matrix

[286. Walls and Gates]

You are given a m x n 2D grid initialized with these three possible values.

1
2
3
4
-1 - A wall or an obstacle.
0 - A gate.
INF - Infinity means an empty room. We use the value 231 - 1 = 2147483647 to represent INF as you may assume that the distance to a gate is less than 2147483647.
Fill each empty room with the distance to its nearest gate. If it is impossible to reach a gate, it should be filled with INF.

DFS (待完善)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution(object):
def updateMatrix(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: List[List[int]]
"""
if not matrix or not matrix[0]:
return []
m = len(matrix)
n = len(matrix[0])
for i in range(m):
for j in range(n):
if matrix[i][j] == 1:
matrix[i][j] = float('inf')
for i in range(m):
for j in range(n):
if matrix[i][j] == 0:
self.dfs(i,j,matrix,0)
return matrix

def dfs(self, i, j, matrix, d):
if i < 0 or j < 0 or i >= len(matrix) or j >= len(matrix[0]) or matrix[i][j] < d:
return
matrix[i][j] = d
self.dfs(i+1, j, matrix, d+1)
self.dfs(i-1, j, matrix, d+1)
self.dfs(i, j-1, matrix, d+1)
self.dfs(i, j+1, matrix, d+1)

329. 矩阵中的最长递增路径

给定一个整数矩阵,找出最长递增路径的长度。

对于每个单元格,你可以往上,下,左,右四个方向移动。 你不能在对角线方向上移动或移动到边界外(即不允许环绕)。

dp[i][j]表示matrix[i][j]开始的递增路径长度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution(object):
def longestIncreasingPath(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: int
"""
if not matrix or not matrix[0]:
return 0

m,n=len(matrix),len(matrix[0])
dp=[[0]*n for _ in range(m)]

def dfs(i,j):
if not dp[i][j]:
dp[i][j]=1+max(
dfs(i-1,j) if i>0 and matrix[i-1][j]>matrix[i][j] else 0,
dfs(i+1,j) if i+1<m and matrix[i+1][j]>matrix[i][j] else 0,
dfs(i,j-1) if j>0 and matrix[i][j-1]>matrix[i][j] else 0,
dfs(i,j+1) if j+1<n and matrix[i][j+1]>matrix[i][j] else 0,
)
return dp[i][j] # 记得要返回值
return max([dfs(i,j) for i in range(m) for j in range(n)])

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution(object):
def longestIncreasingPath(self, m):
"""
:type matrix: List[List[int]]
:rtype: int
"""

x=len(m)
if x == 0: return 0
y=len(m[0])

res = [0]*(x*y)

def calcPath(i,j):
if res[j*x+i]:
return res[j*x+i]
v = m[i][j]
l = calcPath(i-1,j) if i and m[i-1][j]>v else 0
r = calcPath(i+1,j) if i+1<x and m[i+1][j]>v else 0
t = calcPath(i,j-1) if j and m[i][j-1]>v else 0
b = calcPath(i,j+1) if j+1<y and m[i][j+1]>v else 0
res[j*x+i]=max(l,r,t,b)+1
return res[j*x+i]

for i in range(x):
for j in range(y):
calcPath(i,j)

return max(res)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
class Solution(object):
def longestIncreasingPath(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: int
"""
#可以借鉴跟上一个一样的思路。 搞一个visit数组,0,1,x三个值分别代表尚未遍历,正在遍历,已经遍历的长度。遇到的每一条路径,用一个maxLen记录它的长度
if not matrix or not matrix[0]:
return 0



# def dfs(i,j,currentLen):
# if visit[i][j] == -1:
# return currentLen
# if visit[i][j] != 0:
# return currentLen + visit[i][j]
# #如果这个节点还未被遍历
# visit[i][j] = -1
# dr = [0,0,1,-1]
# dc = [1,-1,0,0]
# max_tem = currentLen
# for idx in range(4):
# ii = i + dr[idx]
# jj = j + dc[idx]
# if ii >= 0 and ii < len(matrix) and jj >= 0 and jj < len(matrix[0]):
# if matrix[ii][jj] > matrix[i][j]:
# max_cur = dfs(ii,jj,currentLen + 1)
# max_tem = max(max_cur,max_tem)
# visit[i][j] = max_tem - currentLen
# return max_tem



def dfs(i,j):
if visit[i][j] != 0:
return visit[i][j]


visit[i][j] = 1 + max(
dfs(i-1,j) if i>0 and matrix[i-1][j]>matrix[i][j] else 0,
dfs(i+1,j) if i<M-1 and matrix[i+1][j]>matrix[i][j] else 0,
dfs(i,j-1) if j>0 and matrix[i][j-1]>matrix[i][j] else 0,
dfs(i,j+1) if j<N-1 and matrix[i][j+1]>matrix[i][j] else 0)


return visit[i][j]

#一个同维的数组,用于标记当前数组的遍历情况
visit = [[0] * len(matrix[0]) for i in range(len(matrix))]
maxLen = 0
M, N = len(matrix), len(matrix[0])
#依次遍历每个元素
for i in range(len(matrix)):
for j in range(len(matrix[0])):
current = dfs(i,j)
if current > maxLen:
maxLen = current
return maxLen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution(object):
def longestIncreasingPath(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: int
"""
def dfs(i,j):
if not dp[i][j]:
val = matrix[i][j]
dp[i][j] = 1+max(
dfs(i-1,j) if i>0 and matrix[i-1][j]>val else 0,
dfs(i+1,j) if i<M-1 and matrix[i+1][j]>val else 0,
dfs(i,j-1) if j>0 and matrix[i][j-1]>val else 0,
dfs(i,j+1) if j<N-1 and matrix[i][j+1]>val else 0)
return dp[i][j]

if not matrix or not matrix[0]:
return 0
M, N = len(matrix), len(matrix[0])
dp = [[0] * N for i in range(M)]
return max([dfs(x, y) for x in range(M) for y in range(N)])

695. 岛屿的最大面积

给定一个包含了一些 0 和 1的非空二维数组 grid , 一个 岛屿 是由四个方向 (水平或垂直) 的 1 (代表土地) 构成的组合。你可以假设二维矩阵的四个边缘都被水包围着。

找到给定的二维数组中最大的岛屿面积。(如果没有岛屿,则返回面积为0。)

DFS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution(object):
def maxAreaOfIsland(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
if not grid or not grid[0]:
return 0

m,n,ans=len(grid),len(grid[0]),0

def dfs(i,j):
if i<0 or i>=m or j<0 or j>=n or grid[i][j]==0:
return 0
grid[i][j]=0
area=1
for x,y in zip((i+1,i-1,i,i),(j,j,j+1,j-1)):
area+=dfs(x,y)
return area

for i in range(m):
for j in range(n):
if grid[i][j]==1:
ans=max(ans,dfs(i,j))
return ans

BFS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution(object):
def maxAreaOfIsland(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
if not grid or not grid[0]:
return 0

m,n,ans=len(grid),len(grid[0]),0

def bfs(i,j):
queue=collections.deque([[i,j]])
grid[i][j]=0
area=1
while queue:
r,c=queue.popleft()
for x,y in zip((r+1,r-1,r,r),(c,c,c+1,c-1)):
if 0<=x<m and 0<=y<n and grid[x][y]==1:
grid[x][y]=0
area+=1
queue.append([x,y])
return area

for i in range(m):
for j in range(n):
if grid[i][j]==1:
ans=max(ans,bfs(i,j))
return ans

690. 员工的重要性

给定一个保存员工信息的数据结构,它包含了员工唯一的id,重要度 和 直系下属的id。

比如,员工1是员工2的领导,员工2是员工3的领导。他们相应的重要度为15, 10, 5。那么员工1的数据结构是[1, 15, [2]],员工2的数据结构是[2, 10, [3]],员工3的数据结构是[3, 5, []]。注意虽然员工3也是员工1的一个下属,但是由于并不是直系下属,因此没有体现在员工1的数据结构中。

现在输入一个公司的所有员工信息,以及单个员工id,返回这个员工和他所有下属的重要度之和。

DFS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
"""
# Employee info
class Employee(object):
def __init__(self, id, importance, subordinates):
# It's the unique id of each node.
# unique id of this employee
self.id = id
# the importance value of this employee
self.importance = importance
# the id of direct subordinates
self.subordinates = subordinates
"""
class Solution(object):
def getImportance(self, employees, id):
"""
:type employees: Employee
:type id: int
:rtype: int
"""
dic={e.id:e for e in employees}

def dfs(id):
e=dic[id]
return e.importance+sum(dfs(subid) for subid in e.subordinates)
return dfs(id)

BFS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
"""
# Employee info
class Employee(object):
def __init__(self, id, importance, subordinates):
# It's the unique id of each node.
# unique id of this employee
self.id = id
# the importance value of this employee
self.importance = importance
# the id of direct subordinates
self.subordinates = subordinates
"""
class Solution(object):
def getImportance(self, employees, id):
"""
:type employees: Employee
:type id: int
:rtype: int
"""
dic={e.id:e for e in employees}
queue=collections.deque([id])
ans=0

while queue:
id=queue.popleft()
if id in dic:
ans+=dic[id].importance
for sub in dic[id].subordinates:
queue.append(sub)
return ans