其他分享
首页 > 其他分享> > 【搜索】力扣934:最短的桥

【搜索】力扣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 找第二个岛

具体地:

image
来源: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