最大島嶼面積

XFS小风發表於2024-11-15

DFS解法

class Solution:
    dir = [(-1,0),(1,0),(0,-1),(0,1)]
    def dfs(self,grid,x,y):
        if x < 0 or x >= len(grid) or y < 0 or y >= len(grid[0]) or grid[x][y] != 1:
            return 0
        grid[x][y] = 0
        ans = 1
        for (dx,dy) in self.dir:
            ans += self.dfs(grid,x+dx,y+dy)
        return ans
    def maxAreaOfIsland(self, grid: List[List[int]]) -> int:
        ans = 0
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                ans = max(ans, self.dfs(grid,i,j))
        return ans

為什麼要遍歷整個網格?

島嶼可能是多個分離的區域

  • 一個二維網格可能包含多個島嶼,它們彼此不相連。我們不能假設只用一個起點就能發現整個網格中的所有島嶼,因為每個島嶼的起點可能散佈在不同的位置。

  • 示例:

grid = [ [1, 0, 0, 1], [1, 0, 1, 0], [0, 0, 1, 0] ]

在上面的示例中有 3 個獨立的島嶼:一個位於左上角,一個位於中部,一個位於右下角。因此,必須遍歷整個網格以找到所有的島嶼。

DFS 需要從每個可能的起點出發 當你遍歷到某個位置 (i, j) 並且發現它是陸地(1),這意味著它可能是島嶼的一部分。於是你需要呼叫 DFS 來探索與這個位置相連的所有陸地單元格,以計算這個島嶼的面積。

為什麼將訪問過的陸地變為0

在每次 DFS 呼叫中,你會將訪問過的陸地標記為水(將 1 變成 0),這樣可以避免重複計算已經處理過的島嶼。

其實也可以變為 -1 或者任何不為1的數

當然也可以新建一個列表 visited 記錄下來每一個訪問過的地方,但是這樣會浪費空間

BFS解法

class Solution:
    dir = [(-1,0),(1,0),(0,-1),(0,1)]
    def maxAreaOfIsland(self, grid: List[List[int]]) -> int:
        ans = 0
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                queue = [(i,j)]
                count = 0
                while len(queue) > 0:
                    x,y = queue.pop(0)
                    if  x < 0 or x >= len(grid) or y < 0 or y >= len(grid[0]) or grid[x][y] != 1:
                        continue
                    grid[x][y] = -1
                    count += 1
                    for dx,dy in self.dir:
                        nx,ny = x+dx,y+dy
                        queue.append((nx,ny))
                ans = max(ans,count)
        return ans

為什麼將檢查放在四個方向迴圈之後是錯誤的

如果你把檢查邏輯放在四個方向迴圈之後,程式碼可能會變成這樣:

for dx, dy in self.dir:
    nx, ny = x + dx, y + dy
    # 假設這裡再檢查是否越界或是否訪問過
    if nx < 0 or nx >= len(grid) or ny < 0 or ny >= len(grid[0]) or grid[nx][ny] != 1:
        continue
    queue.append((nx, ny))

這樣處理代表在彈出節點 (x, y) 後,你已經預設地將這個節點當作有效節點,甚至可能在 count += 1 之前錯誤地處理了它。例如第一次新增的節點,你並不知道他是否有效,但你只在這裡進行判斷就會導致漏掉一個判斷。

這裡你可以使用控制變數法,將這段程式碼加入進去發現還是正確的,但是如果去掉while迴圈下的判斷就會發生錯誤

class Solution:
    dir = [(-1,0),(1,0),(0,-1),(0,1)]
    def maxAreaOfIsland(self, grid: List[List[int]]) -> int:
        ans = 0
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                queue = [(i,j)]
                count = 0
                while len(queue) > 0:
                    x,y = queue.pop(0)
                    if  x < 0 or x >= len(grid) or y < 0 or y >= len(grid[0]) or grid[x][y] != 1:
                        continue
                    grid[x][y] = -1
                    count += 1
                    for dx,dy in self.dir:
                        nx,ny = x+dx,y+dy
                        if nx < 0 or nx >= len(grid) or ny < 0 or ny >= len(grid[0]) or grid[nx][ny] != 1:
                            continue
                        queue.append((nx,ny))
                ans = max(ans,count)
        return ans

相關文章