Description

給定一個 n x n 的二維網格 grid,其中 0 代表可通行、1 代表障礙。求從左上角 (0,0) 到右下角 (n-1,n-1) 的最短路徑長度(可沿 8 個方向移動)。路徑長度為經過的格子數。

Example:

Input: grid = [[0,1],[1,0]] Output: 2

Intuition#

等權圖最短路徑 – BFS 從左上到右下,允許八方向移動。

  • 可沿 8 個方向移動(含對角線)
  • BFS 天然找到最短路徑(每步權重相同)
  • 路徑長度是格子數,不是邊數

Approaches#

⭐1: BFS#

  • 概念: 從 (0,0) 開始 BFS,每步向 8 個方向擴展,第一次到達 (n-1,n-1) 即為最短路徑
  • 時間複雜度: O(n^2)
  • 空間複雜度: O(n^2)
class Solution {
    fun shortestPathBinaryMatrix(grid: Array<IntArray>): Int {
        val n = grid.size
        if (grid[0][0] == 1 || grid[n - 1][n - 1] == 1) return -1
        if (n == 1) return 1

        val queue = ArrayDeque<IntArray>()
        queue.add(intArrayOf(0, 0))
        grid[0][0] = 1
        var length = 1

        while (queue.isNotEmpty()) {
            length++
            repeat(queue.size) {
                val (r, c) = queue.removeFirst()
                for (dr in -1..1) {
                    for (dc in -1..1) {
                        if (dr == 0 && dc == 0) continue
                        val nr = r + dr
                        val nc = c + dc
                        if (nr in 0 until n && nc in 0 until n && grid[nr][nc] == 0) {
                            if (nr == n - 1 && nc == n - 1) return length
                            grid[nr][nc] = 1
                            queue.add(intArrayOf(nr, nc))
                        }
                    }
                }
            }
        }
        return -1
    }
}

2: A* 搜尋#

  • 概念: 用 A* 搜尋加速,啟發函式為切比雪夫距離 max(|dr|, |dc|)
  • 時間複雜度: O(n^2 log n)
  • 空間複雜度: O(n^2)
class Solution {
    fun shortestPathBinaryMatrix(grid: Array<IntArray>): Int {
        val n = grid.size
        if (grid[0][0] == 1 || grid[n - 1][n - 1] == 1) return -1
        if (n == 1) return 1

        val dist = Array(n) { IntArray(n) { Int.MAX_VALUE } }
        dist[0][0] = 1
        // [estimated total, distance, row, col]
        val pq = java.util.PriorityQueue<IntArray>(compareBy { it[0] })
        pq.add(intArrayOf(maxOf(n - 1, n - 1), 1, 0, 0))

        while (pq.isNotEmpty()) {
            val (_, d, r, c) = pq.poll()
            if (r == n - 1 && c == n - 1) return d
            if (d > dist[r][c]) continue

            for (dr in -1..1) {
                for (dc in -1..1) {
                    if (dr == 0 && dc == 0) continue
                    val nr = r + dr
                    val nc = c + dc
                    if (nr in 0 until n && nc in 0 until n && grid[nr][nc] == 0 && d + 1 < dist[nr][nc]) {
                        dist[nr][nc] = d + 1
                        val h = maxOf(n - 1 - nr, n - 1 - nc)
                        pq.add(intArrayOf(d + 1 + h, d + 1, nr, nc))
                    }
                }
            }
        }
        return -1
    }
}

🔑 Takeaways#

  • Pattern: 網格 BFS 最短路徑 – 8 方向移動
  • 關鍵技巧: 路徑長度是格子數(起點也算);原地標記可避免額外 visited 陣列;A* 的切比雪夫距離啟發函式適用於 8 方向移動