The "Shortest Path to Get Food" problem involves a 2D grid represented by a list of lists (or a matrix). Each cell in the grid can contain:
'*'
: The starting position (there is exactly one such cell)'#'
: A food cell (there may be one or more)'O'
: An open cell you can walk through'X'
: A blocked cell you cannot walk through-1
.
At first glance, the problem resembles classic pathfinding in a maze. A brute-force approach would be to try all possible paths from the start to every food cell, but this is highly inefficient, especially for larger grids.
Instead, we should look for an efficient way to find the shortest path. Since every move has the same cost and we want the minimal number of steps, this is a perfect scenario for Breadth-First Search (BFS). BFS explores all possible moves level by level, ensuring that the first time we encounter a food cell, it is via the shortest possible path.
Key considerations:
We'll use Breadth-First Search (BFS) to solve this problem efficiently. Here’s how:
'*'
): Loop through the grid to find the coordinates of the start.'#'
), return the step count.-1
as there is no path to any food cell.We use a queue for BFS because it ensures the first time we reach a cell, it is via the shortest possible path. The visited set prevents infinite loops and redundant work.
Consider the following grid:
[['X','X','X','X','X','X'], ['X','*','O','O','O','X'], ['X','O','O','#','O','X'], ['X','X','X','X','X','X']]
'*'
.'#'
(food!).BFS ensures we find this shortest path without exploring longer alternatives.
Brute-force approach:
This is optimal for grid-based shortest path problems.
The "Shortest Path to Get Food" problem is a classic example of grid-based pathfinding. By using Breadth-First Search (BFS), we efficiently find the minimal steps required to reach food, leveraging the fact that BFS always finds the shortest path in an unweighted graph. Avoiding revisiting cells and processing the grid systematically ensures both correctness and efficiency.
from collections import deque
class Solution:
def getFood(self, grid):
rows, cols = len(grid), len(grid[0])
# Find the start
for r in range(rows):
for c in range(cols):
if grid[r][c] == '*':
start = (r, c)
queue = deque([(start[0], start[1], 0)])
visited = set([start])
directions = [(-1,0), (1,0), (0,-1), (0,1)]
while queue:
r, c, steps = queue.popleft()
if grid[r][c] == '#':
return steps
for dr, dc in directions:
nr, nc = r + dr, c + dc
if 0 <= nr < rows and 0 <= nc < cols and (nr, nc) not in visited:
if grid[nr][nc] != 'X':
visited.add((nr, nc))
queue.append((nr, nc, steps+1))
return -1
#include <vector>
#include <queue>
#include <utility>
using namespace std;
class Solution {
public:
int getFood(vector<vector<char>>& grid) {
int rows = grid.size(), cols = grid[0].size();
int startR, startC;
for (int r = 0; r < rows; ++r) {
for (int c = 0; c < cols; ++c) {
if (grid[r][c] == '*') {
startR = r; startC = c;
}
}
}
queue<tuple<int,int,int>> q;
vector<vector<bool>> visited(rows, vector<bool>(cols, false));
q.push({startR, startC, 0});
visited[startR][startC] = true;
int dr[4] = {-1, 1, 0, 0}, dc[4] = {0, 0, -1, 1};
while (!q.empty()) {
auto [r, c, steps] = q.front(); q.pop();
if (grid[r][c] == '#') return steps;
for (int d = 0; d < 4; ++d) {
int nr = r + dr[d], nc = c + dc[d];
if (nr >= 0 && nr < rows && nc >= 0 && nc < cols
&& !visited[nr][nc] && grid[nr][nc] != 'X') {
visited[nr][nc] = true;
q.push({nr, nc, steps+1});
}
}
}
return -1;
}
};
import java.util.*;
class Solution {
public int getFood(char[][] grid) {
int rows = grid.length, cols = grid[0].length;
int startR = -1, startC = -1;
for (int r = 0; r < rows; ++r)
for (int c = 0; c < cols; ++c)
if (grid[r][c] == '*') { startR = r; startC = c; }
Queue<int[]> queue = new LinkedList<>();
boolean[][] visited = new boolean[rows][cols];
queue.offer(new int[]{startR, startC, 0});
visited[startR][startC] = true;
int[][] dirs = {{-1,0},{1,0},{0,-1},{0,1}};
while (!queue.isEmpty()) {
int[] curr = queue.poll();
int r = curr[0], c = curr[1], steps = curr[2];
if (grid[r][c] == '#') return steps;
for (int[] d : dirs) {
int nr = r + d[0], nc = c + d[1];
if (nr >= 0 && nr < rows && nc >= 0 && nc < cols
&& !visited[nr][nc] && grid[nr][nc] != 'X') {
visited[nr][nc] = true;
queue.offer(new int[]{nr, nc, steps+1});
}
}
}
return -1;
}
}
/**
* @param {character[][]} grid
* @return {number}
*/
var getFood = function(grid) {
const rows = grid.length, cols = grid[0].length;
let startR, startC;
for (let r = 0; r < rows; ++r)
for (let c = 0; c < cols; ++c)
if (grid[r][c] === '*') { startR = r; startC = c; }
const queue = [[startR, startC, 0]];
const visited = Array.from({length: rows}, () => Array(cols).fill(false));
visited[startR][startC] = true;
const dirs = [[-1,0],[1,0],[0,-1],[0,1]];
while (queue.length) {
const [r, c, steps] = queue.shift();
if (grid[r][c] === '#') return steps;
for (const [dr, dc] of dirs) {
const nr = r + dr, nc = c + dc;
if (nr >= 0 && nr < rows && nc >= 0 && nc < cols
&& !visited[nr][nc] && grid[nr][nc] !== 'X') {
visited[nr][nc] = true;
queue.push([nr, nc, steps+1]);
}
}
}
return -1;
};