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

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

200Number of IslandsGraphsMediumGraphs

給定一個 m x n 的二維網格 grid,其中 '1' 代表陸地、'0' 代表水域。計算島嶼的數量。島嶼被水域包圍,由相鄰(水平或垂直)的陸地連接而成。

Example:

Input: grid = [[“1”,“1”,“0”,“0”,“0”],[“1”,“1”,“0”,“0”,“0”],[“0”,“0”,“1”,“0”,“0”],[“0”,“0”,“0”,“1”,“1”]] Output: 3

Intuition

TIP

每找到一個未訪問的 ‘1’,就代表發現一座新島嶼,用 DFS/BFS 把整座島標記為已訪問。

Approaches

1. BFS — O(m * n) / O(min(m, n))
  • Idea: 遇到 '1' 時,用 BFS 展開,將所有相連的 '1' 改為 '0'(原地標記避免額外空間)
  • Time: O(m * n)
  • Space: O(min(m, n))(BFS 佇列最大寬度)
class Solution {
    fun numIslands(grid: Array<CharArray>): Int {
        val m = grid.size
        val n = grid[0].size
        var count = 0
        val dirs = intArrayOf(0, 1, 0, -1, 0)

        for (i in 0 until m) {
            for (j in 0 until n) {
                if (grid[i][j] == '1') {
                    count++
                    grid[i][j] = '0'
                    val queue: ArrayDeque<Int> = ArrayDeque()
                    queue.add(i * n + j)
                    while (queue.isNotEmpty()) {
                        val cur = queue.removeFirst()
                        val r = cur / n
                        val c = cur % n
                        for (d in 0 until 4) {
                            val nr = r + dirs[d]
                            val nc = c + dirs[d + 1]
                            if (nr in 0 until m && nc in 0 until n && grid[nr][nc] == '1') {
                                grid[nr][nc] = '0'
                                queue.add(nr * n + nc)
                            }
                        }
                    }
                }
            }
        }
        return count
    }
}
⭐ 2. DFS (in-place marking) — O(m * n) / O(m * n)
  • Idea: 遇到 '1' 時,用遞迴 DFS 將所有相連的 '1' 改為 '0',程式碼最簡潔
  • Time: O(m * n)
  • Space: O(m * n)(遞迴呼叫堆疊最壞情況)
class Solution {
    fun numIslands(grid: Array<CharArray>): Int {
        var count = 0
        for (i in grid.indices) {
            for (j in grid[0].indices) {
                if (grid[i][j] == '1') {
                    count++
                    dfs(grid, i, j)
                }
            }
        }
        return count
    }

    private fun dfs(grid: Array<CharArray>, i: Int, j: Int) {
        if (i < 0 || i >= grid.size || j < 0 || j >= grid[0].size || grid[i][j] != '1') return
        grid[i][j] = '0'
        dfs(grid, i + 1, j)
        dfs(grid, i - 1, j)
        dfs(grid, i, j + 1)
        dfs(grid, i, j - 1)
    }
}
Alternative: Union-Find
  • Idea: 將所有 '1' 格子初始化為獨立集合,相鄰的 '1' 進行 union,最終集合數即島嶼數
  • Time: O(m * n * α(m * n))(近似線性)
  • Space: O(m * n)
class Solution {
    private lateinit var parent: IntArray
    private lateinit var rank: IntArray
    private var count = 0

    fun numIslands(grid: Array<CharArray>): Int {
        val m = grid.size
        val n = grid[0].size
        parent = IntArray(m * n)
        rank = IntArray(m * n)
        count = 0

        for (i in 0 until m) {
            for (j in 0 until n) {
                if (grid[i][j] == '1') {
                    parent[i * n + j] = i * n + j
                    count++
                }
            }
        }

        for (i in 0 until m) {
            for (j in 0 until n) {
                if (grid[i][j] == '1') {
                    if (i + 1 < m && grid[i + 1][j] == '1') union(i * n + j, (i + 1) * n + j)
                    if (j + 1 < n && grid[i][j + 1] == '1') union(i * n + j, i * n + j + 1)
                }
            }
        }
        return count
    }

    private fun find(x: Int): Int {
        if (parent[x] != x) parent[x] = find(parent[x])
        return parent[x]
    }

    private fun union(x: Int, y: Int) {
        val px = find(x)
        val py = find(y)
        if (px == py) return
        if (rank[px] < rank[py]) parent[px] = py
        else if (rank[px] > rank[py]) parent[py] = px
        else { parent[py] = px; rank[px]++ }
        count--
    }
}

🔑 Takeaways

Ladders 看全部 →