深度遍历(dfs) 和 广度遍历(bfs) 理解
今天参加LeetCode周赛时候,把我一直不理解的dfs
和 bfs
搞懂了,真的开心!相信我,搞懂我下面这道题,这个概念就理解了!
解释
**dfs:**一条路走的死,用栈实现,进栈、退栈,一搜到底!一般用递归实现
bfs: 辐射八方,用队实现,入队、出队,步步为营!一般用迭代实现
举例
最短的桥
在给定的二维二进制数组 A 中,存在两座岛。(岛是由四面相连的 1 形成的一个最大组。)
现在,我们可以将 0 变为 1,以使两座岛连接起来,变成一座岛。
返回必须翻转的 0 的最小数目。(可以保证答案至少是 1。)
例子:
输入:
[[1,1,1,1,1],[1,0,0,0,1],[1,0,1,0,1],[1,0,0,0,1],[1,1,1,1,1]]
输出:
1
思路:
- 先找到其中一个岛(染色,我会用dfs和bfs分别实现)
- 再找到另一个岛,从这个岛中,任意位置出发,首先碰到第一个岛就是最小值,所以可以用bfs,意思这些岛中点一起出发,看谁先碰到另一个岛,返回最小值
** 用dfs染色 ,找到一个岛屿**
visited1 = set()
def dfs(i,j):
A[i][j] = 2
visited1.add((i,j))
if i> 0 and (i-1,j) not in visited1 and A[i-1][j] == 1:
dfs(i-1,j)
visited1.add((i-1,j))
if i < row-1 and (i+1,j) not in visited1 and A[i+1][j] == 1:
dfs(i+1,j)
visited1.add((i+1,j))
if j > 0 and (i,j-1) not in visited1 and A[i][j-1] == 1:
dfs(i,j-1)
visited1.add((i,j-1))
if j < col-1 and (i,j+1) not in visited1 and A[i][j+1] == 1:
dfs(i,j+1)
visited1.add((i,j+1))
刚开始A:[[1,1,1,1,1],[1,0,0,0,1],[1,0,1,0,1],[1,0,0,0,1],[1,1,1,1,1]]
经过dfs:,A:[[2, 2, 2, 2, 2], [2, 0, 0, 0, 2], [2, 0, 1, 0, 2], [2, 0, 0, 0, 2], [2, 2, 2, 2, 2]]
def bfs(i,j):
queue = [(i,j)]
visited = set((i,j))
while queue:
i,j = queue.pop(0)
A[i][j] = 2
if i>0 and (i-1,j) not in visited and A[i-1][j] == 1:
queue.append((i-1,j))
visited.add((i-1,j))
if i < row-1 and (i+1,j) not in visited and A[i+1][j] == 1:
queue.append((i+1,j))
visited.add((i+1,j))
if j > 0 and (i,j-1) not in visited and A[i][j-1] == 1:
queue.append((i,j-1))
visited.add((i,j-1))
if j < col-1 and (i,j+1) not in visited and A[i][j+1] == 1:
queue.append((i,j+1))
visited.add((i,j+1))
a = Solution()
print(a.shortestBridge([[1,1,1,1,1],[1,0,0,0,1],[1,0,1,0,1],[1,0,0,0,1],[1,1,1,1,1]]))
刚开始A:[[1,1,1,1,1],[1,0,0,0,1],[1,0,1,0,1],[1,0,0,0,1],[1,1,1,1,1]]
经过bfs:,A:[[2, 2, 2, 2, 2], [2, 0, 0, 0, 2], [2, 0, 1, 0, 2], [2, 0, 0, 0, 2], [2, 2, 2, 2, 2]]
所以,
染色成功!
# 找一个岛
queue = []
visited2 = set()
for i in range(row):
for j in range(col):
if A[i][j] == 1:
# 位置i,j 和 step = 0
queue.append((i,j,0))
visited2.add((i,j))
接下来,
# bfs 找一个岛到另一个岛最小值
while queue:
i,j,step = queue.pop(0)
if (i>0 and A[i-1][j] == 2) or (i<row-1 and A[i+1][j] == 2) \
or ( j > 0 and A[i][j-1] == 2) or (j<col-1 and A[i][j+1]==2):
return step
if i > 0 and (i-1,j) not in visited1 and A[i-1][j] == 0:
queue.append((i-1,j,step+1))
visited1.add((i-1,j))
if i < row -1 and (i+1,j) not in visited1 and A[i+1][j] == 0:
queue.append((i+1,j,step+1))
visited1.add((i+1,j))
if j > 0 and (i,j-1) not in visited1 and A[i][j-1] == 0:
queue.append((i,j-1,step+1))
visited1.add((i,j-1))
if j < col-1 and (i,j+1) not in visited1 and A[i][j+1] == 0:
queue.append((i,j+1,step+1))
visited1.add((i,j+1))
结果
a = Solution()
print(a.shortestBridge([[1,1,1,1,1],[1,0,0,0,1],[1,0,1,0,1],[1,0,0,0,1],[1,1,1,1,1]]))
1
附上完整代码
class Solution(object):
def shortestBridge(self, A):
"""
:type A: List[List[int]]
:rtype: int
"""
# 行 和 列
row = len(A)
col = len(A[0])
"""
我分别用dfs和bfs把其中一个岛染成2(一开始是1)
"""
# 记录已经访问的点
visited1 = set()
def dfs(i,j):
A[i][j] = 2
visited1.add((i,j))
if i> 0 and (i-1,j) not in visited1 and A[i-1][j] == 1:
dfs(i-1,j)
visited1.add((i-1,j))
if i < row-1 and (i+1,j) not in visited1 and A[i+1][j] == 1:
dfs(i+1,j)
visited1.add((i+1,j))
if j > 0 and (i,j-1) not in visited1 and A[i][j-1] == 1:
dfs(i,j-1)
visited1.add((i,j-1))
if j < col-1 and (i,j+1) not in visited1 and A[i][j+1] == 1:
dfs(i,j+1)
visited1.add((i,j+1))
def bfs(i,j):
queue = [(i,j)]
visited = set((i,j))
while queue:
i,j = queue.pop(0)
A[i][j] = 2
if i>0 and (i-1,j) not in visited and A[i-1][j] == 1:
queue.append((i-1,j))
visited.add((i-1,j))
if i < row-1 and (i+1,j) not in visited and A[i+1][j] == 1:
queue.append((i+1,j))
visited.add((i+1,j))
if j > 0 and (i,j-1) not in visited and A[i][j-1] == 1:
queue.append((i,j-1))
visited.add((i,j-1))
if j < col-1 and (i,j+1) not in visited and A[i][j+1] == 1:
queue.append((i,j+1))
visited.add((i,j+1))
# 保证只找到一个岛
flag = False
for i in range(row):
if flag:
break
for j in range(col):
if A[i][j] == 1:
# dfs
# dfs(i,j)
# flag = True
# break
# bfs
bfs(i,j)
flag = True
break
# print("dfs:",A)
# print("bfs:",A)
# 下面开始找另一个岛,把位置放入队列,用bfs找它离上一个岛最小距离
queue = []
visited2 = set()
for i in range(row):
for j in range(col):
if A[i][j] == 1:
# 位置i,j 和 step = 0
queue.append((i,j,0))
visited2.add((i,j))
# 用bfs
while queue:
i,j,step = queue.pop(0)
if (i>0 and A[i-1][j] == 2) or (i<row-1 and A[i+1][j] == 2) \
or ( j > 0 and A[i][j-1] == 2) or (j<col-1 and A[i][j+1]==2):
return step
if i > 0 and (i-1,j) not in visited1 and A[i-1][j] == 0:
queue.append((i-1,j,step+1))
visited1.add((i-1,j))
if i < row -1 and (i+1,j) not in visited1 and A[i+1][j] == 0:
queue.append((i+1,j,step+1))
visited1.add((i+1,j))
if j > 0 and (i,j-1) not in visited1 and A[i][j-1] == 0:
queue.append((i,j-1,step+1))
visited1.add((i,j-1))
if j < col-1 and (i,j+1) not in visited1 and A[i][j+1] == 0:
queue.append((i,j+1,step+1))
visited1.add((i,j+1))