置頂

GeoGebra 文章目錄

GeoGebra 文章目錄  更新日期:2018/2/8 我將 GeoGebra 相關的文章及檔案連結都整理在這篇裡,之後如果有新的文章也會同時更新這個目錄。上傳到 GeoGebraTube 的檔案,我有試著用 Google Chrome 63.0.3239.13...

熱門文章

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

Runtime: 9464 ms, beats 5.21%. Memory: 43.04 MB, beats 50.29%.
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 = [(i, j)]  # 待走訪佇列
                    head = 0
                    dist[i][j] = 0  # 這個的距離為 0
                    while head < len(que):
                        r, c = que[head]  # 目前的位置
                        head += 1
                        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 = [[False] * n for _ in range(n)]  # 已走訪的格子
        visited[0][0] = True
        while pq:
            d, r, c = heapq.heappop(pq)
            d = -d
            visited[r][c] = True
            # 走到終點,回傳 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 not visited[nr][nc]:
                    visited[nr][nc] = True
                    newDist = min(d, dist[nr][nc])
                    heapq.heappush(pq, (-newDist, nr, nc))
        # 預設的回傳值,用不到
        return 0


C++ 程式碼


Runtime: 897 ms, beats 11.09%. Memory: 331.31 MB, beats 8.76%.
class Solution {
public:
    int maximumSafenessFactor(vector<vector<int>>& grid) {
        int n = (int)grid.size();  // 地圖尺寸 n*n
        /* 特例,起點或終點有小偷,回傳 0 */
        if (grid[0][0] == 1 || grid[n-1][n-1] == 1) {
            return 0;
        }
        /* 用 BFS 從小偷的位置開始往外,找小偷到格子的距離 */
        int dr[4] = {0, 1, 0, -1}, dc[4] = {1, 0, -1, 0};
        vector<vector<int>> dist (n, vector<int> (n, 1000));
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < n; j++) {
                if (grid[i][j] == 1) {
                    dist[i][j] = 0;
                    queue<pair<int, int>> que;
                    que.push({i, j});
                    while(!que.empty()) {
                        int r = que.front().first, c = que.front().second, d = dist[r][c];
                        que.pop();
                        for(int k = 0; k < 4; k++) {
                            int nr = r + dr[k], nc = c + dc[k];
                            if (nr >= 0 && nr < n && nc >= 0 && nc < n && dist[nr][nc] > d + 1) {
                                dist[nr][nc] = d + 1;
                                que.push({nr, nc});
                            }
                        }
                    }
                }
            }
        }
        
        /* 用最大優先佇列找出從 (0, 0) 到 (n-1, n-1) 最佳路徑上距離最小值 */
        priority_queue<tuple<int, int, int>> pq;
        pq.push({dist[0][0], 0, 0});
        vector<vector<bool>> visited (n, vector<bool> (n, false));
        visited[0][0] = true;
        while(!pq.empty()) {
            auto [d, r, c] = pq.top();
            pq.pop();
            if (r == n-1 && c == n-1) {
                return d;
            }
            for(int i = 0; i < 4; i++) {
                int nr = r + dr[i], nc = c + dc[i];
                if (nr >= 0 && nr < n && nc >= 0 && nc < n && !visited[nr][nc]) {
                    visited[nr][nc] = true;
                    int newDist = min(d, dist[nr][nc]);
                    pq.push({newDist, nr, nc});
                }
            }
        }
        return 0;
    }
};


沒有留言:

張貼留言