第十一章 图论 Part2

haohaoscnblogs / 2024-09-13 / 原文

目录
  • 任务
    • 200. 岛屿数量
      • 思路
    • 695. 岛屿的最大面积
      • 思路

任务

200. 岛屿数量

给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。

岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。

此外,你可以假设该网格的四条边均被水包围。

思路

总的逻辑是,每遇到一个新的岛屿,就将计数加1,具体的遍历格子则使用dfs和bfs去遍历陆地,对于每一个格子,都进行dfs或bfs的遍历,

  1. 当前为水,不统计计数,继续下一个格子的处理
  2. 当前为已经遍历过的岛屿,不统计计数,继续下一个格子的处理
  3. 遇到新大陆(未访问过的大陆格子),则对该格子进行遍历以找到与该格子相关的整个岛屿
    具体单个岛屿的遍历,实现既可以用dfs,也可以用bfs。
    对于dfs,每遇到新的格子(未访问过的)且为陆地则标记并递归遍历,这里隐含着,如果遇到不是陆地的地方则进行下一个方向的处理。如此,可以访问一个整岛屿,将其相关格子标记为True。
    对于bfs,实际与bfs同理,只是遍历的流程是按照层去遍历,也是遍历一整个岛屿,将整个岛屿的格子标记为True。需要注意的点是,在每次加入队列时,都需要标记格子为True,原因是为了不重复访问,节省时间,具体更详细的原因可以去看第十一章 图论 Part1的内容。
    下面给出dfs和bfs解决这个问题的代码
class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:
        visited =  [[False] * len(grid[0]) for _ in range(len(grid))]
        result = 0
        for i in range(len(grid)): #以每个格子为起点进行遍历
            for j in range(len(grid[0])):
                if visited[i][j]==False and grid[i][j] == '1': #为新大陆时,累加结果    
                    result += 1
                    #self.dfs(grid,visited,i,j) #按深度优先遍历标记某岛屿
                    self.bfs(grid,visited,i,j) #按广度优先遍历标记某岛屿
        return result

    def dfs(self,grid,visited,x,y):
        dir = [(1,0),(0,1),(-1,0),(0,-1)] #逆时针四个方向
        visited[x][y] = True # 由调用者(包含外部和自身)保证了该格子为访问过的陆地!
        
        for i in range(4):
            nextX = x + dir[i][0]
            nextY = y + dir[i][1]

            if nextX < 0 or nextY<0 or nextX>=len(grid) or nextY>=len(grid[0]):
                continue
            if visited[nextX][nextY] == False and grid[nextX][nextY] == '1':
                self.dfs(grid,visited,nextX,nextY)
    
    from collections import deque
    def bfs(self,grid,visited,x,y):
        dir = [(1,0),(0,1),(-1,0),(0,-1)] #逆时针四个方向
        que = deque()
        que.append((x,y))
        visited[x][y] = True

        while(que):
            curX,curY = que.popleft()
            
            for i in range(4):
                nextX = curX + dir[i][0]
                nextY = curY + dir[i][1]

                if nextX < 0 or nextY<0 or nextX>=len(grid) or nextY>=len(grid[0]):
                    continue
                if visited[nextX][nextY] == False and grid[nextX][nextY] == '1':
                    que.append((nextX,nextY))
                    visited[nextX][nextY] =True
            

695. 岛屿的最大面积

给你一个大小为 m x n 的二进制矩阵 grid 。

岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在 水平或者竖直的四个方向上 相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着。

岛屿的面积是岛上值为 1 的单元格的数目。

计算并返回 grid 中最大的岛屿面积。如果没有岛屿,则返回面积为 0 。

思路

如果理解了上一题,本题就可以直接解决,本题求的是岛屿面积,累计的值就是某一个岛屿的面积,就在dfs或者bfs中累计,然后在主函数中取最大的岛屿面积即可。
下面给出dfs和bfs的方法

class Solution:
    def __init__(self):
        self.count = 0
    def maxAreaOfIsland(self, grid: List[List[int]]) -> int:
        visited =  [[False] * len(grid[0]) for _ in range(len(grid))]
        result = 0
        for i in range(len(grid)): #以每个格子为起点进行遍历
            for j in range(len(grid[0])):
                if visited[i][j]==False and grid[i][j] == 1: #为新大陆时,累加结果    
                    self.count = 0
                    #self.dfs(grid,visited,i,j) #按深度优先遍历标记某岛屿
                    self.bfs(grid,visited,i,j) #按深度优先遍历标记某岛屿
                    result = max(result,self.count)
                   
        return result

    def dfs(self,grid,visited,x,y):
        dir = [(1,0),(0,1),(-1,0),(0,-1)] #逆时针四个方向
        visited[x][y] = True # 由调用者(包含外部和自身)保证了该格子为访问过的陆地!
        self.count += 1
        
        for i in range(4):
            nextX = x + dir[i][0]
            nextY = y + dir[i][1]

            if nextX < 0 or nextY<0 or nextX>=len(grid) or nextY>=len(grid[0]):
                continue
            if visited[nextX][nextY] == False and grid[nextX][nextY] == 1: #未访问过的陆地则继续访问(直到遍历完整个单独的岛屿)
                self.dfs(grid,visited,nextX,nextY)
    
    from collections import deque
    def bfs(self,grid,visited,x,y):
        dir = [(1,0),(0,1),(-1,0),(0,-1)] #逆时针四个方向
        que = deque()
        que.append((x,y))
        visited[x][y] = True
        self.count += 1

        while(que):
            curX,curY = que.popleft()
            
            for i in range(4):
                nextX = curX + dir[i][0]
                nextY = curY + dir[i][1]

                if nextX < 0 or nextY<0 or nextX>=len(grid) or nextY>=len(grid[0]):
                    continue
                if visited[nextX][nextY] == False and grid[nextX][nextY] == 1: #未访问过的陆地则继续访问(直到遍历完整个单独的岛屿)
                    que.append((nextX,nextY))
                    visited[nextX][nextY] =True
                    self.count+=1