ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【搜索】力扣934:最短的桥

2022-08-16 23:00:42  阅读:140  来源: 互联网

标签:deque nx int List 最短 力扣 ny BFS 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,说明已经遇到了另一个岛,此时返回扩散的次数即可

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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有