zoukankan      html  css  js  c++  java
  • 总结BFS相关题目

    542.01 矩阵

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

    示例 1:
    输入:

    0 0 0
    0 1 0
    0 0 0
    输出:

    0 0 0
    0 1 0
    0 0 0
    示例 2:
    输入:

    0 0 0
    0 1 0
    1 1 1
    输出:

    0 0 0
    0 1 0
    1 2 1

    思路:在一个图中,能从一个点出发求这种最短距离的方法很容易想到就是 BFS,BFS 的名称是广度优先遍历,即把周围这一圈搜索完成之后,再搜索下一圈,是慢慢扩大搜索范围的。

    题目给出了多个1,要找出每个1到0的最近曼哈顿距离。由于1到0的距离和0到1的距离一样的,所以其实我们可以换个思维:找出每个0到1的距离。因此,题目可以抽象成:多个起始点的BFS。

    class Solution:
        def updateMatrix(self, matrix: List[List[int]]) -> List[List[int]]:
            M, N = len(matrix), len(matrix[0])
            queue = collections.deque()
            visited = [[0] * N for _ in range(M)]
            res = [[0] * N for _ in range(M)]
            for i in range(M):
                for j in range(N):
                    if matrix[i][j] == 0:
                        queue.append((i, j))
                        visited[i][j] = 1
            dirs = [(0, 1), (0, -1), (1, 0), (-1, 0)]
            step = 0
            while queue:
                size = len(queue)
                for i in range(size):
                    x, y = queue.popleft()
                    if matrix[x][y] == 1:
                        res[x][y] = step
                    for dx, dy in dirs:
                        newx, newy = x + dx, y + dy
                        if newx < 0 or newx >= M or newy < 0 or newy >= N or visited[newx][newy] == 1:
                            continue
                        queue.append((newx, newy))
                        visited[newx][newy] = 1
                step += 1
            return res
    

    200.岛屿数量

    给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。此外,你可以假设该网格的四条边均被水包围。

    示例 1:

    输入:
    11110
    11010
    11000
    00000
    输出: 1
    示例 2:

    输入:
    11000
    11000
    00100
    00011
    输出: 3
    解释: 每座岛屿只能由水平和/或竖直方向上相邻的陆地连接而成。

    思路1:核心思想依旧是 BFS,如果发现一个陆地,便对其进行 BFS,并将可由 BFS 访问到的点都置为已经访问状态,从而代表同属一个岛屿。

    class Solution:
        def numIslands(self, grid: List[List[str]]) -> int:
            count = 0
            for row in range(len(grid)):
                for col in range(len(grid[0])):
                    if grid[row][col] == '1':  # 发现陆地
                        count += 1  # 结果加1
                        grid[row][col] = '0'  # 将其转为 ‘0’ 代表已经访问过
                        # 对发现的陆地进行扩张即执行 BFS,将与其相邻的陆地都标记为已访问
                        # 下面还是经典的 BFS 模板
                        land_positions = collections.deque()
                        land_positions.append([row, col])
                        while len(land_positions) > 0:
                            x, y = land_positions.popleft()
                            for new_x, new_y in [[x, y + 1], [x, y - 1], [x + 1, y], [x - 1, y]]:  # 进行四个方向的扩张
                                # 判断有效性
                                if 0 <= new_x < len(grid) and 0 <= new_y < len(grid[0]) and grid[new_x][new_y] == '1':
                                    grid[new_x][new_y] = '0'  # 因为可由 BFS 访问到,代表同属一块岛,将其置 ‘0’ 代表已访问过
                                    land_positions.append([new_x, new_y])
            return count

    思路2:DFS 类似感染思想,首先遍历整个grid,如果遇到1 则岛屿数量+1,随后,开始使用感染法,将周围的1都变成0,直到周围不是1后,继续开始遍历。如此便能得到有几个岛屿。

    class Solution:
        def numIslands(self, grid: List[List[str]]) -> int:
            count = 0
            for i in range(len(grid)):
                for j in range(len(grid[0])):#遍历list
                    if grid[i][j] == '1':#开始有岛屿那么岛屿数量加1
                        count += 1
                        self.dfs(grid,i,j)#进入感染模式,把所有临近岛屿变为0
            return count
    
        def dfs(self,grid,i,j):#感染模式
            if i<0 or j<0 or i>=len(grid) or j>=len(grid[0]) or grid[i][j] !='1':
                return
            else:
                grid[i][j] = '0'
                self.dfs(grid,i+1,j)
                self.dfs(grid,i-1,j)
                self.dfs(grid,i,j+1)
                self.dfs(grid,i,j-1)
    

    1162.地图分析

    你现在手里有一份大小为 N x N 的「地图」(网格) grid,上面的每个「区域」(单元格)都用 0 和 1 标记好了。其中 0 代表海洋,1 代表陆地,请你找出一个海洋区域,这个海洋区域到离它最近的陆地区域的距离是最大的。我们这里说的距离是「曼哈顿距离」( Manhattan Distance):(x0, y0) 和 (x1, y1) 这两个区域之间的距离是 |x0 - x1| + |y0 - y1| 。如果我们的地图上只有陆地或者海洋,请返回 -1。

    示例 1:

    输入:[[1,0,1],[0,0,0],[1,0,1]]
    输出:2
    解释:
    海洋区域 (1, 1) 和所有陆地区域之间的距离都达到最大,最大距离为 2。
    示例 2:

    输入:[[1,0,0],[0,0,0],[0,0,0]]
    输出:4
    解释:
    海洋区域 (2, 2) 和所有陆地区域之间的距离都达到最大,最大距离为 4。

    思路:由于这道题求解的是最远的距离,而距离我们可以使用BFS来做。

    对于每一个海洋,我们都向四周扩展,寻找最近的陆地,每次扩展steps加1。
    1.如果找到了陆地,我们返回steps。
    2.我们的目标就是所有steps中的最大值。
    3.实际上面算法有很多重复计算,如图中间绿色的区域,向外扩展的时候,如果其周边四个海洋的距离已经计算出来了,那么没必要扩展到陆地。实际上只需要扩展到周边的四个海洋格子就好了,其距离陆地的最近距离就是1 + 周边四个格子中到达陆地的最小距离。

     

    我们考虑优化。

    1.将所有陆地加入队列,而不是海洋。
    2.陆地不断扩展到海洋,每扩展一次就steps加1,直到无法扩展位置。
    3.最终返回steps即可。

    class Solution:
        def maxDistance(self, grid: List[List[int]]) -> int:
            n = len(grid)
            steps = -1
            queue = [(i, j) for i in range(n) for j in range(n) if grid[i][j] == 1]
            if len(queue) == 0 or len(queue) == n ** 2: return steps
            while len(queue) > 0:
                for _ in range(len(queue)): 
                    x, y = queue.pop(0)
                    for xi, yj in [(x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)]:
                        if xi >= 0 and xi < n and yj >= 0 and yj < n and grid[xi][yj] == 0:
                            queue.append((xi, yj))
                            grid[xi][yj] = -1
                steps += 1
                    
            return steps
    #由于没有early return,steps 其实会多算一次。 我们可以返回值减去1,也可以steps初始化为-1。这里我选择是steps初始化为-1
    

    作者:fe-lucifer
    链接:https://leetcode-cn.com/problems/as-far-from-land-as-possible/solution/python-tu-jie-chao-jian-dan-de-bfs1162-di-tu-fen-x/
    来源:力扣(LeetCode)

  • 相关阅读:
    洛谷P2216 理想的正方形
    洛谷P2698 花盆Flowerpot【单调队列】
    洛谷P2178 品酒大会【后缀数组】【单调栈】
    洛谷P2463 Sandy的卡片【后缀数组】【二分】
    PAT甲1038 Recover the smallest number
    PAT甲1101 Quick Sort
    PAT甲1031 Hello World for U【字符串】
    PAT甲1005 Spell it right【字符串】
    django_logging
    django_session
  • 原文地址:https://www.cnblogs.com/USTC-ZCC/p/12738351.html
Copyright © 2011-2022 走看看