第十一章 圖論 Part2

haohaoscnblogs發表於2024-09-05

目錄
  • 任務
    • 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

相關文章