Shortest Path in a Grid with Obstacles Elimination

HardGraph BFS · State Expansion🧩 Graph BFSLeetCode #1293 ↗Updated

Problem

You are given an m x n grid of 0 (empty) and 1 (wall) cells and may step up, down, left or right. Walking into a wall is allowed only by destroying it, and you may destroy at most k walls in total. Return the minimum number of steps from the top-left to the bottom-right corner, or -1 if it cannot be done.
Inputgrid = [[0,0,0],[1,1,0],[0,0,0],[0,1,1],[0,0,0]], k = 1Output6
Inputgrid = [[0,1,1],[1,1,1],[1,0,0]], k = 1Output-1
Inputgrid = [[0,1],[1,0]], k = 1Output2

1 ≤ m, n ≤ 40  ·  1 ≤ k ≤ m·n  ·  grid[0][0] = grid[m-1][n-1] = 0

Try it yourself

Java
class Solution {
    public int shortestPath(int[][] grid, int k) {
        
    }
}
Your code is saved in this browser.Submit on LeetCode ↗
Key insight
A cell alone is not a state — (row, col, walls left) is. BFS over that expanded state gives the shortest path. Two prunings make it fast: if k ≥ m+n-3 the straight Manhattan path is always possible, and a cell revisited with no more walls-left than before can be skipped.
PatternGraph BFS

Instinct Minimum moves, fewest steps or shortest transformation where every step costs the same: spread outward level by level with a queue.

Memory hack Ripples in a pond: every ring is one step farther, so the first ring that touches the target is the answer.

Open the Graph BFS guide →

Approaches

Brute ForceBacktracking over Simple Paths

Time O(3m·n)Space O(m·n)

DFS from the start, never revisiting a cell on the current path, spending one elimination per wall entered. Record the shortest length that reaches the corner and prune branches already as long as the best. Every simple path may be explored.

Java
private int best;

public int shortestPath(int[][] grid, int k) {
    best = Integer.MAX_VALUE;
    dfs(grid, 0, 0, k, 0, new boolean[grid.length][grid[0].length]);
    return best == Integer.MAX_VALUE ? -1 : best;
}

private void dfs(int[][] g, int r, int c, int left, int steps, boolean[][] onPath) {
    if (r < 0 || c < 0 || r >= g.length || c >= g[0].length || onPath[r][c]) return;
    if (g[r][c] == 1) {
        if (left == 0) return;
        left--;                        // smash this wall
    }
    if (steps >= best) return;
    if (r == g.length - 1 && c == g[0].length - 1) {
        best = steps;
        return;
    }
    onPath[r][c] = true;
    dfs(g, r + 1, c, left, steps + 1, onPath);
    dfs(g, r - 1, c, left, steps + 1, onPath);
    dfs(g, r, c + 1, left, steps + 1, onPath);
    dfs(g, r, c - 1, left, steps + 1, onPath);
    onPath[r][c] = false;
}

Exponential — fine as a correctness oracle on tiny grids only.

At a glance

LevelApproachTimeSpace
Brute ForceBacktracking over Simple PathsO(3m·n)O(m·n)
BetterBFS over (row, col, walls left)O(m·n·k)O(m·n·k)
OptimalBFS with Manhattan Shortcut + Best-Remaining PruningO(m·n·min(k, m+n))O(m·n·min(k, m+n))
Common pitfalls
  • Using a 2-D visited array — a cell reached with more eliminations left must be revisitable.
  • Charging an elimination for the start or end cell (both are guaranteed empty).
  • Allocating [m][n][k+1] without capping k — k can be 1600.
Interview tips
  • Name the trick: “BFS with augmented state” (position + resource left).
  • Bring up the k ≥ m+n-3 shortcut — interviewers love the observation.
  • Contrast with Dijkstra: all moves cost 1, so plain BFS already gives shortest steps.
Pattern
BFS on (position, resource) states → shortest path where a limited budget changes which moves are legal.
My notes saved in this browser