2026年7月2日 星期四

LeetCode 解題筆記:3286. Find a Safe Walk Through a Grid

作者:王一哲
日期:2026年7月2日


LeetCode 題目連結:3286. Find a Safe Walk Through a Grid

解題想法


中等難度題。題目給定代表地圖的二維陣列 $grid$,假設尺寸為 $m \times n$,地圖中的數字代表走到這格會扣的血量,題目要求從左上角 $(0, 0)$ 出發走到右下角 $(m-1, n-1)$,如果能夠走到右下角回傳 True,如果無法走到右下角回傳 False。這類走格子的題目,我習慣用 BFS 解題。用 $que$ 儲存待走訪的格子座標,另外再開一個二維陣列 $visited$,用來儲存走到這格的最大血量,預設值為 $-1$,代表還沒有走到這格。持續從 $que$ 之中取出目前檢查的格子座標 $(r, c)$,如果 $r = m-1, c = n-1$ 回傳 True,如果還沒有走到終點則要做四方位檢查。時間複雜度為 $O(n^2)$。

Python 程式碼


Runtime: 63 ms, beats 83.49%. Memory: 19.47 MB, beats 97.17%.
class Solution:
    def findSafeWalk(self, grid: List[List[int]], health: int) -> bool:
        m, n = len(grid), len(grid[0])  # 地圖尺寸 m*n
        visited = [[-1] * n for _ in range(m)]  # 是否已走訪,-1 代表未走訪
        visited[0][0] = health - grid[0][0]  # 正值代表走到這格的 hp,起點可能會扣血
        que = deque([(0, 0)])  # 待走訪佇列
        # --- BFS ---
        while que:
            r, c = que.popleft()  # 目前的位置
            curr = visited[r][c]  # 目前的血量
            if r == m-1 and c == n-1:  # 走到終點,回傳 True
                return True
            # 四方位檢查
            for dr, dc in ((0, 1), (1, 0), (0, -1), (-1, 0)):
                nr, nc = r + dr, c + dc
                # 如果 (nr, nc) 未出界,目前的血量大於 (nr, nc) 會扣的血量,剩下的血量大於之前走到 (nr, nc) 的血量
                if 0 <= nr < m and 0 <= nc < n and curr > grid[nr][nc] and curr - grid[nr][nc] > visited[nr][nc]:
                    visited[nr][nc] = curr - grid[nr][nc]
                    que.append((nr, nc))
        return False


2026年7月1日 星期三

LeetCode 解題筆記:2812. Find the Safest Path in a Grid

作者:王一哲
日期:2026年7月1日


LeetCode 題目連結:2812. Find the Safest Path in a Grid

解題想法


中等難度題。題目給定代表地圖的二維陣列 $grid$,假設尺寸為 $n \times n$,地圖中 1 代表小偷,0 代表空地,要從位置 $(0, 0)$ 走到 $(n-1, n-1)$,找出最佳路徑上與所有小偷的最小曼哈頓距離。解題過程主要分為 2 個步驟:
  1. 掃過地圖每一格,從小偷的位置開始 BFS,找出所有格子與所有小偷的最短距離。
  2. 用最大優先佇列 $pq$,先放入 $(dist[0][0], 0, 0)$,不斷地從 $pq$ 取出資料,如果遇到位置 $(n-1, n-1)$ 回傳這格的距離;如果還沒有走到終點,對這個位置 $(r, c)$ 四方位檢查,將新的位置及距離加入 $pq$ 之中。
雖然這樣寫比較好懂,但是時間複雜度有點高,速度很慢。

Python 程式碼


Runtime: 9455 ms, beats 5.21%. Memory: 41.56 MB, beats 51.73%.
class Solution:
    def maximumSafenessFactor(self, grid: List[List[int]]) -> int:
        n = len(grid)  # 地圖尺寸 n*n
        # --- 特例,起點或終點有小偷,回傳 0 ---
        if grid[0][0] == 1 or grid[n-1][n-1] == 1:
            return 0
        # --- 用 BFS 從小偷的位置開始往外,找小偷到格子的距離 ---
        dist = [[1000]*n for _ in range(n)]  # 測資最大為 100,預設距離為超出範圍的 1000
        for i in range(n):  # 掃過每一格
            for j in range(n):
                if grid[i][j] == 1:  # 小偷
                    que = deque([(i, j)])  # 待走訪佇列
                    dist[i][j] = 0  # 這個的距離為 0
                    while que:
                        r, c = que.popleft()  # 目前的位置
                        d = dist[r][c]  # 目前的距離
                        # 四方位檢查,如果 (nr, nc) 沒有出界而且距離大於 d+1,更新 dist[nr][nc],將 (nr, nc) 加入 que
                        for dr, dc in ((0, 1), (1, 0), (0, -1), (-1, 0)):
                            nr, nc = r + dr, c + dc
                            if 0 <= nr < n and 0 <= nc < n and dist[nr][nc] > d + 1:
                                dist[nr][nc] = d + 1
                                que.append((nr, nc))
        # --- 用最大優先佇列找出從 (0, 0) 到 (n-1, n-1) 最佳路徑上距離最小值 ---
        pq = [(-dist[0][0], 0, 0)]  # (-distance, row, col)
        visited = set()  # 已走訪的格子
        while pq:
            d, r, c = heapq.heappop(pq)
            d = -d
            visited.add((r, c))
            # 走到終點,回傳 d
            if r == n-1 and c == n-1:
                return d
            # 四方位檢查
            for dr, dc in ((0, 1), (1, 0), (0, -1), (-1, 0)):
                nr, nc = r + dr, c + dc
                if 0 <= nr < n and 0 <= nc < n and (nr, nc) not in visited:
                    visited.add((nr, nc))
                    newDist = min(d, dist[nr][nc])
                    heapq.heappush(pq, (-newDist, nr, nc))
        # 預設的回傳值,用不到
        return 0