【搜索】力扣934:最短的桥
作者:互联网
在给定的二维二进制数组 A 中,存在两座岛。(岛是由四面相连的 1 形成的一个最大组。)
现在,我们可以将 0 变为 1,以使两座岛连接起来,变成一座岛。
返回必须翻转的 0 的最小数目。(可以保证答案至少是 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]]
输出:1
很有意思的题
总体思路:首先找到这两座岛,然后选择其中一座,将它不断向外延伸一圈填海造陆,直到到达另一座岛。
BFS 常用来处理最短路径问题或可达性问题。
DFS + BFS
先 dfs 找到其中一个岛,然后 bfs 找第二个岛
- 在寻找第一座岛时,使用深度优先搜索
- 在向外延伸时,使用广度优先搜索
具体地:
-
遍历矩阵,找到的一个 1,调用dfs把和 1 联通的所有 1 改为 2,也就是识别出这整座岛,与另一座岛屿进行区分,也防止重复遍历。同时利用双端队列 queue 存储第一个岛
-
调用bfs从第一个岛开始逐层向外“填海造陆”(即把它把周围的 0 改为 2 ),直到在某次扩散时遇到 1,说明已经遇到了另一个岛,此时返回扩散的次数即可
来源:https://leetcode.cn/problems/shortest-bridge/solution/bfs-tian-hai-zao-lu-ti-jie-si-lu-by-carp-6w8j/
from collections import deque
class Solution:
def shortestBridge(self, A: List[List[int]]) -> int:
m, n = len(A), len(A[0])
directions = [(-1,0), (1,0), (0,-1), (0,1)] # 方向数组
q = collections.deque()
step = 0 # 要返回的结果
# 通过dfs查找第一个岛,并且标记为已访问,也就是将 1 变为 2
def dfs(i, j):
if not 0 <= i < m or not 0 <= j < n or A[i][j] == 0 or A[i][j] == 2:
return
# A[i][j] == 1 的情况,标记并加入队列,搜索周围
A[i][j] = 2
q.append((i, j))
for x, y in directions:
ni, nj = i + x, j + y
dfs(ni, nj)
find = False
for i in range(m):
for j in range(n):
if A[i][j] == 1 and not find:
dfs(i, j)
find = True
# bfs # 从找到的岛开始扩展,把过程中已访问的 0 变为 2,每扩展一层,step +1
while q:
size = len(q)
for _ in range(size):
i, j = q.popleft()
for x, y in directions:
ni, nj = i + x, j + y
if not 0 <= ni < m or not 0 <= nj < n or A[ni][nj] == 2:
continue
if A[ni][nj] == 1:
return step
# else: 也就是 A[ni][nj] == 0 的情况,标记
A[ni][nj] = 2
q.append((ni, nj))
step += 1
return step
时间复杂度:O(MN),其中 M 和 N 分别是数组 A 的行数和列数。
空间复杂度:O(MN)。
BFS + BFS
新建标记矩阵
先找到一个整体的 1,然后再探查另一个岛上的 1。
from collections import deque
class Solution:
def shortestBridge(self, A: List[List[int]]) -> int:
m, n = len(A), len(A[0])
directions = [(-1,0), (1,0), (0,-1), (0,1)]
visited = [[False] * n for _ in range(m)] # 标记数组
def bfs(i,j):
q = collections.deque([(i, j, 0)])
while q:
x, y, time = q.popleft()
for dx, dy in directions:
nx, ny = x + dx, y + dy
if nx >= 0 and nx < m and ny >= 0 and ny < n and visited[nx][ny] == False:
visited[nx][ny] = True
if A[nx][ny] == 1:
if time >= 1: # 通过跨越 0 找到了另一座岛
return time
else: # time 为 0 表示此时还是在同一座岛屿,记得左插,优先级大于 0 的块
q.appendleft((nx,ny,0))
else:
q.append((nx, ny, time + 1))
# 找到第一个为 1 的点
for i in range(m):
for j in range(n):
if A[i][j] == 1:
visited[i][j] = True
return bfs(i,j)
作者:linn-9k
链接:https://leetcode.cn/problems/shortest-bridge/solution/si-lu-bi-jiao-qing-xi-de-01bfs-by-linn-9-r0vu/
改变矩阵,使用数字标记(最佳)
先用BFS把一个岛全部标成 0 并同时加入另一个队列。 然后从这个队列出发进行BFS,直到找到一个陆地。
from collections import deque
class Solution:
def shortestBridge(self, A: List[List[int]]) -> int:
directions = [(0,1),(0,-1),(1,0),(-1,0)]
n = len(grid)
q = deque()
ql = deque()
i = 0
while not q:
for j in range(n):
if A[i][j] == 1:
q.append((i,j))
ql.append((i,j))
A[i][j] = 0
break
i += 1
while ql:
i, j = ql.popleft()
for d in directions:
x, y = i + d[0], j + d[1]
if 0 <= x < n and 0 <= y < n and A[x][y]:
q.append((x, y))
ql.append((x, y))
A[x][y] = 0
step = 0
visited = set(list(q))
while q:
w = len(q)
for k in range(w):
i, j = q.popleft()
for d in directions:
x, y = i + d[0], j + d[1]
if 0 <= x < n and 0 <= y < n and (x, y) not in visited:
if A[x][y]:
return step
q.append((x, y))
visited.add((x, y))
step += 1
标签:deque,nx,int,List,最短,力扣,ny,BFS,934 来源: https://www.cnblogs.com/Jojo-L/p/16592042.html