leetcode
leetcode 3001 ~ 3050
信物传送

信物传送

难度:

标签:

题目描述

English description is not available for the problem. Please switch to Chinese.

代码结果

运行时间: 41 ms, 内存: 16.3 MB


/*
 * 思路:使用广度优先搜索(BFS)找到从起点到终点的最短路径。每次改变一个传送带的方向并检查是否能更接近终点。
 * 
 * 实现步骤:
 * 1. 初始化队列和访问标记。
 * 2. 使用队列进行BFS,记录每次改变传送带方向后的状态。
 * 3. 找到最少的操作次数,使得信物从起点到达终点。
 */
import java.util.*;
import java.util.stream.IntStream;

public class SolutionStream {
    private static final int[][] directions = { {0, 1}, {1, 0}, {0, -1}, {-1, 0} };
    private static final char[] symbols = {'>', 'v', '<', '^'};
    
    public int minMagicOperations(String[] matrix, int[] start, int[] end) {
        int rows = matrix.length;
        int cols = matrix[0].length();
        boolean[][][] visited = new boolean[rows][cols][4];
        Queue<int[]> queue = new LinkedList<>();
        queue.add(new int[]{start[0], start[1], 0});
        visited[start[0]][start[1]][0] = true;
        int operations = 0;
        
        while (!queue.isEmpty()) {
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                int[] current = queue.poll();
                int r = current[0];
                int c = current[1];
                int dir = current[2];
                
                if (r == end[0] && c == end[1]) {
                    return operations;
                }
                
                IntStream.range(0, 4).forEach(j -> {
                    int newR = r + directions[j][0];
                    int newC = c + directions[j][1];
                    if (isValid(matrix, newR, newC, rows, cols) && !visited[newR][newC][j]) {
                        visited[newR][newC][j] = true;
                        queue.add(new int[]{newR, newC, j});
                    }
                });
            }
            operations++;
        }
        return -1; // 无法到达终点
    }
    
    private boolean isValid(String[] matrix, int r, int c, int rows, int cols) {
        return r >= 0 && r < rows && c >= 0 && c < cols;
    }
}

解释

方法:

该题解采用了广度优先搜索(BFS)的思路。首先,创建一个与矩阵相同大小的访问数组 vst,用于记录每个位置是否被访问过。然后,从起点 start 开始,按照传送带的方向移动,并将到达的新位置加入到队列中。每次移动后,检查是否到达终点 end,如果到达,则返回当前的施法次数 c。如果没有到达,则对当前位置的四个方向进行探索,如果相邻的位置没有被访问过,则将其加入到下一轮的队列中,并更新访问数组。每一轮探索结束后,施法次数 c 加一。如果最终无法到达终点,则返回 -1。

时间复杂度:

O(m * n)

空间复杂度:

O(m * n)

代码细节讲解

🦆
如何处理在边界位置时传送带方向可能会指向矩阵外的情况?例如,如果在矩阵的最右侧一列,传送带方向向右,该如何确保不会引发索引错误?
在代码中,处理边界情况主要通过使用min和max函数确保坐标不会越界。例如,当传送带方向向右且处于最右侧一列时,使用表达式`min(j + 1, n - 1)`来确保列索引j不会超过矩阵的最大列索引n-1。类似地,向左移动时使用`max(0, j - 1)`确保不会小于0。这样处理可以保证即使传送带指示向外,代码也不会尝试访问矩阵边界之外的元素,从而避免索引错误。
🦆
在该题解中,对每个位置的四个方向进行探索时,所使用的条件`if i and not vst[i - 1][j]`似乎没有完全考虑边界条件,是否应该更明确地检查边界?
确实,条件`if i and not vst[i - 1][j]`只检查了i不为0(即不在第一行),但没有明确地检查是否在矩阵的有效行范围内。理想情况下,应该使用更严格的边界检查,如`if i > 0 and not vst[i - 1][j]`来确保进行访问的索引是有效的。这样的检查可以更清晰地表明只在i大于0时才向上探索,从而避免任何可能的边界问题。对于其他方向也应执行类似的边界检查。
🦆
为什么在到达终点后就直接返回当前的施法次数,而不考虑当前队列中可能还存在其他未探索的路径可能需要更少的施法次数?
在广度优先搜索(BFS)中,一旦找到终点,该路径保证是施法次数最少的路径。BFS按层级探索,意味着它首先探索所有距起点1步的所有位置,然后是2步的位置,依此类推。所以,当我们在某一施法次数层级首次到达终点时,可以确信没有其他更短的路径存在于此前或同一层级的其他节点中。因此,一旦到达终点,立即返回当前施法次数是合理的,无需考虑队列中的其他路径。

相关问题