LeetCode 2812.找出最安全路径:两次BFS(先进先出队列+优先队列)

【LetMeFly】2812.找出最安全路径:两次BFS(先进先出队列+优先队列)

力扣题目链接:https://leetcode.cn/problems/find-the-safest-path-in-a-grid/

给你一个下标从 0 开始、大小为 n x n 的二维矩阵 grid ,其中 (r, c) 表示:

  • 如果 grid[r][c] = 1 ,则表示一个存在小偷的单元格
  • 如果 grid[r][c] = 0 ,则表示一个空单元格

你最开始位于单元格 (0, 0) 。在一步移动中,你可以移动到矩阵中的任一相邻单元格,包括存在小偷的单元格。

矩阵中路径的 安全系数 定义为:从路径中任一单元格到矩阵中任一小偷所在单元格的 最小 曼哈顿距离。

返回所有通向单元格(n - 1, n - 1) 的路径中的 最大安全系数

单元格 (r, c) 的某个 相邻 单元格,是指在矩阵中存在的 (r, c + 1)(r, c - 1)(r + 1, c)(r - 1, c) 之一。

两个单元格 (a, b)(x, y) 之间的 曼哈顿距离 等于 | a - x | + | b - y | ,其中 |val| 表示 val 的绝对值。

示例 1:

复制代码
输入:grid = [[1,0,0],[0,0,0],[0,0,1]]
输出:0
解释:从 (0, 0) 到 (n - 1, n - 1) 的每条路径都经过存在小偷的单元格 (0, 0) 和 (n - 1, n - 1) 。

示例 2:

复制代码
输入:grid = [[0,0,1],[0,0,0],[0,0,0]]
输出:2
解释:
上图所示路径的安全系数为 2:
- 该路径上距离小偷所在单元格(0,2)最近的单元格是(0,0)。它们之间的曼哈顿距离为 | 0 - 0 | + | 0 - 2 | = 2 。
可以证明,不存在安全系数更高的其他路径。

示例 3:

复制代码
输入:grid = [[0,0,0,1],[0,0,0,0],[0,0,0,0],[1,0,0,0]]
输出:2
解释:
上图所示路径的安全系数为 2:
- 该路径上距离小偷所在单元格(0,3)最近的单元格是(1,2)。它们之间的曼哈顿距离为 | 0 - 1 | + | 3 - 2 | = 2 。
- 该路径上距离小偷所在单元格(3,0)最近的单元格是(3,2)。它们之间的曼哈顿距离为 | 3 - 3 | + | 0 - 2 | = 2 。
可以证明,不存在安全系数更高的其他路径。

提示:

  • 1 <= grid.length == n <= 400
  • grid[i].length == n
  • grid[i][j]01
  • grid 至少存在一个小偷

解题方法:两次广度优先搜索

初始时候我们只知道哪里有小偷,但不知道每个单元格的安全系数 。我们可以通过一次广度优先搜索得到每个单元格的安全系数

使用一个先入先出队列,初始时将所有小偷单元格入队,接着在队列非空时不断出队。

对于出队的单元格,若其上下左右四个相邻单元格还没有入队过,则入队,并更新相邻单元格的安全系数 为当前出队单元格的 安全系数 + 1 安全系数+1 安全系数+1。

队列为空则说明已经求得所有单元格的安全系数

知道了每个单元格的安全系数 ,剩下的就是求从起点(左上角)到终点(右下角)的尽可能走大安全系数的路径中的最小单元格是多少:

由于路径可以上下左右到出走,所以我们不能简单地DP遍历。一旦在到达终点前我们不得不走了某小安全系数的单元格,那么以后大于等于这个最小安全系数的单元格就能肆无忌惮地走了。

因此可以使用一个优先队列再从起点开始进行一次广度优先搜索,每次出队时更新答案(所经过单元格的最小值),若出队单元格是终点则直接返回。否则上下左右四个相邻单元格中未遍历过的单元格入队,并按安全系数大的优先为依据优先出队。

  • 时间复杂度 O ( n 2 log ⁡ n ) O(n^2\log n) O(n2logn),因为 O ( log ⁡ n 2 ) = O ( 2 log ⁡ n ) = O ( log ⁡ n ) O(\log n^2)=O(2\log n)=O(\log n) O(logn2)=O(2logn)=O(logn)
  • 空间复杂度 O ( n 2 ) O(n^2) O(n2)

AC代码

C++
cpp 复制代码
/*
 * @LastEditTime: 2026-07-01 22:58:28
 */
#define debug_(x) {cout << #x << ":" << endl; debug(x);}

typedef pair<int, int> pii;
class Solution {
private:
    vector<vector<int>> dis;
    static constexpr int directions[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};

    void genDis(vector<vector<int>>& grid) {
        int n = grid.size(), m = grid[0].size();
        vector<vector<bool>> visited(n, vector<bool>(m, false));
        queue<pii> q;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (grid[i][j]) {
                    q.push({i, j});
                    visited[i][j] = true;
                }
            }
        }

        dis = vector<vector<int>>(n, vector<int>(m));
        while (q.size()) {
            auto [x, y] = q.front();
            q.pop();
            for (int d = 0; d < 4; d++) {
                int nx = x + directions[d][0];
                int ny = y + directions[d][1];
                if (nx >= 0 && nx < n && ny >= 0 && ny <m && !visited[nx][ny]) {
                    q.push({nx, ny});
                    visited[nx][ny] = true;
                    dis[nx][ny] = dis[x][y] + 1;
                }
            }
        }
    }

    int dfs() {
        int n = dis.size(), m = dis[0].size();
        auto cmp = [this](const pii& a, const pii& b) {
            return dis[a.first][a.second] < dis[b.first][b.second];
        };
        priority_queue<pii, vector<pii>, decltype(cmp)> q(cmp);
        vector<vector<bool>> visited(n, vector<bool>(m));
        int ans = min(dis[0][0], dis[n - 1][m - 1]);
        q.push({0, 0});
        visited[0][0] = true;
        if (n == 1 && m == 1) {
            return ans;
        }
        
        while (q.size()) {
            auto [x, y] = q.top();
            q.pop();
            ans = min(ans, dis[x][y]);
            for (int d = 0; d < 4; d++) {
                int nx = x + directions[d][0];
                int ny = y + directions[d][1];
                if (nx >= 0 && nx < n && ny >= 0 && ny < m && !visited[nx][ny]) {
                    visited[nx][ny] = true;
                    q.push({nx, ny});
                    if (nx == n - 1 && ny == m - 1) {
                        return ans;
                    }
                }
            }
        }
        return ans;
    }
    
    void debug(vector<vector<int>>& v) {
        int n = v.size(), m = v[0].size();
        for (int i = 0; i < n; i++) {
            if (i == 0) {
                cout << "[[";
            } else {
                cout << " [";
            }

            for (int j = 0; j < m; j++) {
                if (j) {
                    cout << ", ";
                }
                cout << v[i][j];
            }

            if (i == n - 1) {
                cout << "]]";
            } else {
                cout << "],";
            }
            puts("");
        }
    }
public:
    int maximumSafenessFactor(vector<vector<int>>& grid) {
        genDis(grid);
        return dfs();
    }
};

// 忽然发现其实m=n
Python
python 复制代码
'''
LastEditTime: 2026-07-03 10:59:07
'''
from typing import List
from collections import deque
import heapq

class Solution:
    def __init__(self) -> None:
        self.directions = [[-1, 0], [1, 0], [0, -1], [0, 1]]
    
    def genDis(self, grid: List[List[int]]):
        n, m = len(grid), len(grid[0])
        dis = [[-1] * m for _ in range(n)]
        q = deque()
        for i, row in enumerate(grid):
            for j, v in enumerate(row):
                if v:
                    q.append((i, j))
                    dis[i][j] = 0
        
        while q:
            x, y = q.popleft()
            for dx, dy in self.directions:
                nx, ny = x + dx, y + dy
                if 0 <= nx < n and 0 <= ny < m and dis[nx][ny] == -1:
                    q.append((nx, ny))
                    dis[nx][ny] = dis[x][y] + 1
        self.dis = dis

    def dfs(self) -> int:
        n, m = len(self.dis), len(self.dis[0])
        visited = [[False] * m for _ in range(n)]
        pq = [(-self.dis[0][0], 0, 0)]
        visited[0][0] = True
        ans = self.dis[0][0]
        
        while pq:
            dis, x, y = heapq.heappop(pq)
            dis = -dis
            ans = min(ans, dis)
            if x == n - 1 and y == m - 1:
                return ans
            for dx, dy in self.directions:
                nx, ny = x + dx, y + dy
                if 0 <= nx < n and 0 <= ny < m and not visited[nx][ny]:
                    visited[nx][ny] = True
                    heapq.heappush(pq, (-self.dis[nx][ny], nx, ny))

    def maximumSafenessFactor(self, grid: List[List[int]]) -> int:
        self.genDis(grid)
        return self.dfs()

同步发文于CSDN和我的个人博客,原创不易,转载经作者同意后请附上原文链接哦~

千篇源码题解已开源