leetcode
leetcode 501 ~ 550
获取食物的最短路径

获取食物的最短路径

难度:

标签:

题目描述

代码结果

运行时间: 80 ms, 内存: 22.4 MB


/*
 * 思路:
 * 1. 找到起点位置,并初始化一个队列用于BFS。
 * 2. 使用一个方向数组遍历当前节点的四个邻居(上下左右)。
 * 3. 如果邻居是空地或食物,且未被访问过,则将其加入队列并记录路径长度。
 * 4. 遇到食物时,返回当前路径长度。
 */
import java.util.*;
import java.util.stream.*;
 
class Solution {
    private static final int[][] DIRECTIONS = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
    
    public int getFood(char[][] grid) {
        int m = grid.length, n = grid[0].length;
        Queue<int[]> queue = new LinkedList<>();
        boolean[][] visited = new boolean[m][n];
        
        // Find the starting point using streams
        IntStream.range(0, m).forEach(i -> 
            IntStream.range(0, n).filter(j -> grid[i][j] == 'S').forEach(j -> {
                queue.offer(new int[]{i, j});
                visited[i][j] = true;
            })
        );
        
        int steps = 0;
        while (!queue.isEmpty()) {
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                int[] current = queue.poll();
                int x = current[0], y = current[1];
                if (grid[x][y] == 'F') {
                    return steps;
                }
                Arrays.stream(DIRECTIONS).forEach(direction -> {
                    int nx = x + direction[0], ny = y + direction[1];
                    if (nx >= 0 && ny >= 0 && nx < m && ny < n && !visited[nx][ny] && grid[nx][ny] != '#') {
                        queue.offer(new int[]{nx, ny});
                        visited[nx][ny] = true;
                    }
                });
            }
            steps++;
        }
        return -1; // If no path to food
    }
}

解释

方法:

这个题解使用广度优先搜索(BFS)算法来解决问题。首先遍历网格,找到起始位置'*'的坐标。然后使用队列进行BFS,每次从队列中取出一个节点,探索其四个方向的相邻节点。如果找到食物'#',则返回当前的步数;如果未找到食物,则将未访问过且不是障碍物'X'的相邻节点加入队列,并标记为已访问。当队列为空时,表示无法到达食物,返回-1。

时间复杂度:

O(mn)

空间复杂度:

O(mn)

代码细节讲解

🦆
在BFS算法中,为什么要使用队列而不是其他数据结构如栈或优先队列?
在广度优先搜索(BFS)中,队列用来确保首先探索所有距离起始点等距离的节点,然后再移向更远的节点。这保证了搜索的层级结构,即逐层向外扩展,这对于寻找最短路径是非常重要的。如果使用栈,则会变成深度优先搜索(DFS),这可能会导致首先探索远离起始点的路径,不适于最短路径的发现。而优先队列(用于实现最小优先队列的结构)通常用于最佳优先搜索(如A*搜索),这需要额外的逻辑来处理优先级(如距离评估),对于简单的最短路径问题,使用优先队列会增加不必要的复杂性和计算开销。
🦆
如果起始位置 '*' 不存在于网格中,这段代码是否会正确处理这种情况?如果不会,应该如何修改代码以处理这种特殊情况?
如果起始位置 '*' 不存在于网格中,代码在初始化队列时因找不到起始位置将导致 start_row 和 start_col 保持为 -1,这将在后续的队列操作中产生错误。为了处理这种情况,可以在完成起始位置的搜索后检查 start_row 和 start_col 是否被正确设置。如果它们仍为初始值 -1,函数应该返回 -1 或抛出一个异常,表明没有有效的起始点。
🦆
在BFS中,每次从队列中取出一个节点时,你是如何保证不会重复访问同一个节点?具体是通过哪些操作实现的?
在BFS实现中,为了防止重复访问节点,使用了一个二维数组 `visited` 来跟踪每个节点的访问状态。每当一个节点被取出队列进行处理时,都会检查 `visited` 数组;如果该节点已被标记为访问过,就不会再次将其加入队列。当节点首次被发现时,会立即在 `visited` 数组中将其标记为已访问,这确保了每个节点只被处理一次。
🦆
代码中提到的四个方向探索,是否考虑过使用其他探索路径优化策略,比如优先探索可能更接近目标的方向?这会对算法的效率有何影响?
虽然可以通过优先探索估计更接近目标的方向来优化搜索路径,但这样做实质上是在使用一种启发式搜索(如A*算法),而不是纯粹的BFS。这种优化通常涉及到计算启发式函数(如欧几里得距离或曼哈顿距离),以决定探索的优先级。这样做可以减少探索的节点总数,从而提高效率,但同时也增加了每次节点扩展的计算复杂性。对于特定类型的问题,这种方法可能更有效,但对于简单的最短路径搜索,纯粹的BFS由于其实现的简单性和可预测的性能通常更受欢迎。

相关问题