leetcode
leetcode 2401 ~ 2450
找出最安全路径

找出最安全路径

难度:

标签:

题目描述

You are given a 0-indexed 2D matrix grid of size n x n, where (r, c) represents:

  • A cell containing a thief if grid[r][c] = 1
  • An empty cell if grid[r][c] = 0

You are initially positioned at cell (0, 0). In one move, you can move to any adjacent cell in the grid, including cells containing thieves.

The safeness factor of a path on the grid is defined as the minimum manhattan distance from any cell in the path to any thief in the grid.

Return the maximum safeness factor of all paths leading to cell (n - 1, n - 1).

An adjacent cell of cell (r, c), is one of the cells (r, c + 1), (r, c - 1), (r + 1, c) and (r - 1, c) if it exists.

The Manhattan distance between two cells (a, b) and (x, y) is equal to |a - x| + |b - y|, where |val| denotes the absolute value of val.

 

Example 1:

Input: grid = [[1,0,0],[0,0,0],[0,0,1]]
Output: 0
Explanation: All paths from (0, 0) to (n - 1, n - 1) go through the thieves in cells (0, 0) and (n - 1, n - 1).

Example 2:

Input: grid = [[0,0,1],[0,0,0],[0,0,0]]
Output: 2
Explanation: The path depicted in the picture above has a safeness factor of 2 since:
- The closest cell of the path to the thief at cell (0, 2) is cell (0, 0). The distance between them is | 0 - 0 | + | 0 - 2 | = 2.
It can be shown that there are no other paths with a higher safeness factor.

Example 3:

Input: grid = [[0,0,0,1],[0,0,0,0],[0,0,0,0],[1,0,0,0]]
Output: 2
Explanation: The path depicted in the picture above has a safeness factor of 2 since:
- The closest cell of the path to the thief at cell (0, 3) is cell (1, 2). The distance between them is | 0 - 1 | + | 3 - 2 | = 2.
- The closest cell of the path to the thief at cell (3, 0) is cell (3, 2). The distance between them is | 3 - 3 | + | 0 - 2 | = 2.
It can be shown that there are no other paths with a higher safeness factor.

 

Constraints:

  • 1 <= grid.length == n <= 400
  • grid[i].length == n
  • grid[i][j] is either 0 or 1.
  • There is at least one thief in the grid.

代码结果

运行时间: 1184 ms, 内存: 27.2 MB


/* 
 思路: 
 1. 使用Stream API来查找小偷的位置并计算每个单元格的安全系数。 
 2. 使用PriorityQueue来进行BFS搜索,并计算每条路径的最大安全系数。 
*/
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class MaxSafetyPathStream {
    public int maximumSafenessFactor(int[][] grid) {
        int n = grid.length;
        List<int[]> thieves = IntStream.range(0, n)
                .boxed()
                .flatMap(r -> IntStream.range(0, n)
                        .filter(c -> grid[r][c] == 1)
                        .mapToObj(c -> new int[]{r, c}))
                .collect(Collectors.toList());

        int[][] safeness = new int[n][n];
        Arrays.stream(safeness).forEach(row -> Arrays.fill(row, Integer.MAX_VALUE));

        thieves.forEach(thief -> IntStream.range(0, n).forEach(r -> IntStream.range(0, n).forEach(c -> safeness[r][c] = Math.min(safeness[r][c], Math.abs(r - thief[0]) + Math.abs(c - thief[1])))));

        PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> b[2] - a[2]);
        pq.offer(new int[]{0, 0, safeness[0][0]});
        boolean[][] visited = new boolean[n][n];
        visited[0][0] = true;
        int[] directions = {-1, 0, 1, 0, -1};

        while (!pq.isEmpty()) {
            int[] current = pq.poll();
            int r = current[0], c = current[1], minSafety = current[2];
            if (r == n - 1 && c == n - 1) {
                return minSafety;
            }

            for (int i = 0; i < 4; i++) {
                int nr = r + directions[i];
                int nc = c + directions[i + 1];
                if (nr >= 0 && nr < n && nc >= 0 && nc < n && !visited[nr][nc]) {
                    visited[nr][nc] = true;
                    pq.offer(new int[]{nr, nc, Math.min(minSafety, safeness[nr][nc])});
                }
            }
        }

        return 0;
    }
}

解释

方法:

题解采用了两阶段的广度优先搜索(BFS)策略来求解最大的安全系数。首先,从所有小偷所在的位置开始,对整个网格执行BFS以计算出每个单元格到最近小偷的距离。然后,使用另一轮BFS来找到从起点(0,0)到终点(n-1,n-1)的路径,同时尽可能保持路径上单元格到最近小偷的最小曼哈顿距离最大。这通过追踪当前路径中最小距离的最大值来实现。如果起点或终点有小偷,安全系数直接为0。第一轮BFS结束后,会确定到达每个单元格的最小距离。在第二轮BFS中,会检查从当前单元格到邻近单元格是否能保持或增加这个最小距离的最大值,并优先扩展那些能维持最大距离的路径。

时间复杂度:

O(n^2 log n)

空间复杂度:

O(n^2)

代码细节讲解

🦆
在双BFS策略中,第一轮BFS将每个单元格初始化为到最近小偷的曼哈顿距离。请问如果矩阵非常大,这个初始化过程是否会对性能产生显著影响,有没有更高效的方法?
在大矩阵中,第一轮BFS确实可能导致性能问题,因为它必须访问矩阵中的每个单元格来更新距离。这个过程的时间复杂度是O(n^2),其中n是网格的维度。更高效的方法可能包括使用多线程或并行处理来加速BFS过程,或者在某些情况下使用启发式算法如A*寻找最近小偷的路径,尽管这后者可能需要特定条件下的优化。
🦆
题解中提到如果起点或终点有小偷,则安全系数直接为0。这种情况下的处理是否可以更早在算法中进行判断,以优化算法效率?
是的,我们可以在算法的最开始就检查起点和终点是否有小偷。如果有,直接返回安全系数为0,这样可以避免不必要的计算,从而优化整体算法的效率。这种早期终止的策略通常在算法设计中被用来处理特殊情况,以减少资源消耗。
🦆
题解中第二轮BFS扩展路径时,优先扩展那些能维持最大距离的路径。在实际操作中,这种策略是否可能导致路径选择不是最优的情况?
优先扩展能维持最大距离的路径是一种启发式方法,它旨在最大化安全系数,但不一定能保证找到最短的路径或其他类型的最优路径。在某些情况下,可能存在多条路径都能达到相同的最大安全系数,但长度不同。因此,这种策略确实可能导致在路径长度或其他因素上不是最优的情况。
🦆
在处理边界条件时,题解中检查了单元格是否越界或已访问,但似乎没有明确说明如何处理格子中已经是由第一轮BFS设置过的距离值。这是否会影响第二轮BFS的准确性?
在第二轮BFS中,应该考虑第一轮BFS设置的距离值,因为这些值代表了到最近小偷的最小曼哈顿距离。如果第二轮BFS中不正确地处理这些值,可能会导致无法正确评估路径的安全系数。因此,确实需要明确地检查和利用这些距离值来保证第二轮BFS的准确性和有效性。

相关问题