Medium草稿★★★★★O(m * n) 時間 · O(m * n) 空間
GraphDFSBFSMatrixUnion-Find
Patterns🔗 並查集🌊 廣度優先 BFS🕸️ 圖遍歷・連通分量
尚未複習過

解法已隱藏 — 先讀題目敘述、自己想想看,再點上方按鈕揭曉。

1905Count Sub IslandsGraphsMediumGraphs

給定兩個 m x n 的二維網格 grid1grid2grid2 中的一座島嶼被稱為「子島嶼」,若該島嶼的所有陸地格子在 grid1 中也是陸地。回傳 grid2 中子島嶼的數量。

Example:

Input: grid1 = [[1,1,1,0,0],[0,1,1,1,1],[0,0,0,0,0],[1,0,0,0,0],[1,1,0,1,1]], grid2 = [[1,1,1,0,0],[0,0,1,1,1],[0,1,0,0,0],[1,0,1,1,0],[0,1,0,1,0]] Output: 3

Intuition

TIP

在 grid2 做 DFS 找島嶼時,同時檢查每個陸地格子在 grid1 是否也是陸地。

Approaches

1. Exclude then Count — O(m * n) / O(m * n)
  • Idea: 先把 grid2 中在 grid10 的陸地格子淹沒(DFS 標記為 0),再計算 grid2 剩餘島嶼數
  • Time: O(m * n)
  • Space: O(m * n)(遞迴堆疊)
class Solution {
    fun countSubIslands(grid1: Array<IntArray>, grid2: Array<IntArray>): Int {
        val m = grid1.size
        val n = grid1[0].size

        // 先淹沒 grid2 中不可能是子島嶼的陸地
        for (i in 0 until m) {
            for (j in 0 until n) {
                if (grid2[i][j] == 1 && grid1[i][j] == 0) {
                    flood(grid2, i, j)
                }
            }
        }

        // 計算剩餘島嶼數
        var count = 0
        for (i in 0 until m) {
            for (j in 0 until n) {
                if (grid2[i][j] == 1) {
                    count++
                    flood(grid2, i, j)
                }
            }
        }
        return count
    }

    private fun flood(grid: Array<IntArray>, i: Int, j: Int) {
        if (i < 0 || i >= grid.size || j < 0 || j >= grid[0].size || grid[i][j] == 0) return
        grid[i][j] = 0
        flood(grid, i + 1, j)
        flood(grid, i - 1, j)
        flood(grid, i, j + 1)
        flood(grid, i, j - 1)
    }
}
⭐ 2. Single DFS (decide in one pass) — O(m * n) / O(m * n)
  • Idea: DFS 遍歷 grid2 島嶼時,同時追蹤是否所有格子在 grid1 也是陸地
  • Time: O(m * n)
  • Space: O(m * n)(遞迴堆疊)
class Solution {
    fun countSubIslands(grid1: Array<IntArray>, grid2: Array<IntArray>): Int {
        val m = grid1.size
        val n = grid1[0].size
        var count = 0

        for (i in 0 until m) {
            for (j in 0 until n) {
                if (grid2[i][j] == 1) {
                    if (dfs(grid1, grid2, i, j)) count++
                }
            }
        }
        return count
    }

    private fun dfs(grid1: Array<IntArray>, grid2: Array<IntArray>, i: Int, j: Int): Boolean {
        if (i < 0 || i >= grid2.size || j < 0 || j >= grid2[0].size || grid2[i][j] == 0) return true
        grid2[i][j] = 0
        var isSub = grid1[i][j] == 1
        // 必須繼續 DFS 所有方向,不能短路
        isSub = dfs(grid1, grid2, i + 1, j) && isSub
        isSub = dfs(grid1, grid2, i - 1, j) && isSub
        isSub = dfs(grid1, grid2, i, j + 1) && isSub
        isSub = dfs(grid1, grid2, i, j - 1) && isSub
        return isSub
    }
}

🔑 Takeaways