Shortest Path by Removing K walls

Last Updated : 19 Jun, 2026

Given a binary matrix arr of size n × m, where 0 represents an empty cell and 1 represents a wall, and an integer k representing the maximum number of walls that can be removed.

  • Starting from the top-left cell (0, 0), find the minimum number of steps required to reach the bottom-right cell (n - 1, m - 1).
  • Movement is allowed in four directions: up, down, left, and right.
  • During the traversal, at most k walls can be removed.
  • If the destination cannot be reached, return -1.

Examples:

Input: k = 1, mat = [[0, 0, 0], [0, 0, 1], [0, 1, 0]]
Output: 4
Explanation: Since k = 1, one wall may be removed. Removing the wall at cell (2, 1) or (1, 2) opens a path connecting the start and destination cells. Following this path reaches the bottom-right corner in 4 steps.

img
Image for Explanation

Input: k = 0, mat = [[0, 1], [1, 0]]
Output: -1
Explanation: Since k = 0, no walls can be removed. Every possible path from the start cell to the destination is blocked by a wall, so the destination cannot be reached.

Try It Yourself
redirect icon

[Naive Approach] DFS Backtracking - O(4 ^ (n x m)) Time and O(n × m)

Try all possible paths from the start cell to the destination while keeping track of removed walls. Since the same cells may be visited in many different ways, this approach explores many repeated paths and is not efficient.

C++
#include <iostream>
#include <vector>
#include <climits>
using namespace std;

int dfs(int i, int j, int removed, int k, vector<vector<int>> &mat,
        vector<vector<bool>> &vis) {
    int n = mat.size(), m = mat[0].size();

    if (i < 0 || j < 0 || i >= n || j >= m || vis[i][j]) return INT_MAX;

    removed += mat[i][j];
    if (removed > k) return INT_MAX;

    if (i == n - 1 && j == m - 1) return 0;

    vis[i][j] = true;

    int res = INT_MAX;

    res = min(res, dfs(i + 1, j, removed, k, mat, vis));
    res = min(res, dfs(i - 1, j, removed, k, mat, vis));
    res = min(res, dfs(i, j + 1, removed, k, mat, vis));
    res = min(res, dfs(i, j - 1, removed, k, mat, vis));

    vis[i][j] = false;

    return res == INT_MAX ? INT_MAX : res + 1;
}

int shortestPath(int k, vector<vector<int>> &mat) {
    int n = mat.size(), m = mat[0].size();

    vector<vector<bool>> vis(n, vector<bool>(m, false));

    int res = dfs(0, 0, 0, k, mat, vis);

    return res == INT_MAX ? -1 : res;
}

int main() {
    int k = 1;
    vector<vector<int>> mat = {{0, 0, 0}, {0, 0, 1}, {0, 1, 0}};
    cout << shortestPath(k, mat) << endl;

    k = 0;
    mat = {{0, 1}, {1, 0}};
    cout << shortestPath(k, mat) << endl;

    return 0;
}
Java
import java.lang.Math;

class GFG {
    static int dfs(int i, int j, int removed, int k, int[][] mat,
                   boolean[][] vis) {
        int n = mat.length, m = mat[0].length;

        if (i < 0 || j < 0 || i >= n || j >= m || vis[i][j]) {
            return Integer.MAX_VALUE;
        }

        removed += mat[i][j];
        if (removed > k) {
            return Integer.MAX_VALUE;
        }

        if (i == n - 1 && j == m - 1) {
            return 0;
        }

        vis[i][j] = true;

        int res = Integer.MAX_VALUE;

        res = Math.min(res, dfs(i + 1, j, removed, k, mat, vis));
        res = Math.min(res, dfs(i - 1, j, removed, k, mat, vis));
        res = Math.min(res, dfs(i, j + 1, removed, k, mat, vis));
        res = Math.min(res, dfs(i, j - 1, removed, k, mat, vis));

        vis[i][j] = false;

        return res == Integer.MAX_VALUE ? Integer.MAX_VALUE : res + 1;
    }

    static int shortestPath(int k, int[][] mat) {
        int n = mat.length, m = mat[0].length;

        boolean[][] vis = new boolean[n][m];

        int res = dfs(0, 0, 0, k, mat, vis);

        return res == Integer.MAX_VALUE ? -1 : res;
    }

    public static void main(String[] args) {
        int k = 1;
        int[][] mat = {{0, 0, 0}, {0, 0, 1}, {0, 1, 0}};
        System.out.println(shortestPath(k, mat));

        k = 0;
        mat = new int[][] {{0, 1}, {1, 0}};
        System.out.println(shortestPath(k, mat));
    }
}
Python
def dfs(i, j, removed, k, mat, vis):
    n = len(mat)
    m = len(mat[0])

    if i < 0 or j < 0 or i >= n or j >= m or vis[i][j]:
        return float("inf")

    removed += mat[i][j]
    if removed > k:
        return float("inf")

    if i == n - 1 and j == m - 1:
        return 0

    vis[i][j] = True

    res = float("inf")

    res = min(res, dfs(i + 1, j, removed, k, mat, vis))
    res = min(res, dfs(i - 1, j, removed, k, mat, vis))
    res = min(res, dfs(i, j + 1, removed, k, mat, vis))
    res = min(res, dfs(i, j - 1, removed, k, mat, vis))

    vis[i][j] = False

    return float("inf") if res == float("inf") else res + 1


def shortestPath(k, mat):
    n = len(mat)
    m = len(mat[0])

    vis = [[False] * m for _ in range(n)]

    res = dfs(0, 0, 0, k, mat, vis)

    return -1 if res == float("inf") else res


if __name__ == "__main__":
    k = 1
    mat = [[0, 0, 0], [0, 0, 1], [0, 1, 0]]
    print(shortestPath(k, mat))

    k = 0
    mat = [[0, 1], [1, 0]]
    print(shortestPath(k, mat))
C#
using System;

class GFG {
    static int dfs(int i, int j, int removed, int k, int[][] mat,
                   bool[,] vis) {
        int n = mat.Length, m = mat[0].Length;

        if (i < 0 || j < 0 || i >= n || j >= m || vis[i, j]) {
            return int.MaxValue;
        }

        removed += mat[i][j];
        if (removed > k) {
            return int.MaxValue;
        }

        if (i == n - 1 && j == m - 1) {
            return 0;
        }

        vis[i, j] = true;

        int res = int.MaxValue;

        res = Math.Min(res, dfs(i + 1, j, removed, k, mat, vis));
        res = Math.Min(res, dfs(i - 1, j, removed, k, mat, vis));
        res = Math.Min(res, dfs(i, j + 1, removed, k, mat, vis));
        res = Math.Min(res, dfs(i, j - 1, removed, k, mat, vis));

        vis[i, j] = false;

        return res == int.MaxValue ? int.MaxValue : res + 1;
    }

    static int shortestPath(int k, int[][] mat) {
        int n = mat.Length, m = mat[0].Length;

        bool[,] vis = new bool[n, m];

        int res = dfs(0, 0, 0, k, mat, vis);

        return res == int.MaxValue ? -1 : res;
    }

    static void Main() {
        int k = 1;
        int[][] mat = {
            new int[] {0, 0, 0},
            new int[] {0, 0, 1},
            new int[] {0, 1, 0}
        };
        Console.WriteLine(shortestPath(k, mat));

        k = 0;
        mat = new int[][] {
            new int[] {0, 1},
            new int[] {1, 0}
        };
        Console.WriteLine(shortestPath(k, mat));
    }
}
JavaScript
function dfs(i, j, removed, k, mat, vis) {
    let n = mat.length, m = mat[0].length;

    if (i < 0 || j < 0 || i >= n || j >= m || vis[i][j]) {
        return Infinity;
    }

    removed += mat[i][j];
    if (removed > k) {
        return Infinity;
    }

    if (i === n - 1 && j === m - 1) {
        return 0;
    }

    vis[i][j] = true;

    let res = Infinity;

    res = Math.min(res, dfs(i + 1, j, removed, k, mat, vis));
    res = Math.min(res, dfs(i - 1, j, removed, k, mat, vis));
    res = Math.min(res, dfs(i, j + 1, removed, k, mat, vis));
    res = Math.min(res, dfs(i, j - 1, removed, k, mat, vis));

    vis[i][j] = false;

    return res === Infinity ? Infinity : res + 1;
}

function shortestPath(k, mat) {
    let n = mat.length, m = mat[0].length;

    let vis = Array.from({ length: n }, () => Array(m).fill(false));

    let res = dfs(0, 0, 0, k, mat, vis);

    return res === Infinity ? -1 : res;
}

// Driver Code
let k = 1;
let mat = [[0, 0, 0], [0, 0, 1], [0, 1, 0]];
console.log(shortestPath(k, mat));

k = 0;
mat = [[0, 1], [1, 0]];
console.log(shortestPath(k, mat));

Output
4
-1

[Better Approach] BFS with 3D Visited - O(n × m × k) Time and O(n × m × k) Space

Since each cell can be reached with different numbers of removed walls, maintain visited[i][j][wallsRemoved]. BFS guarantees the first time we reach the destination gives the minimum number of steps.

C++
#include <iostream>
#include <vector>
#include <queue>
using namespace std;

int shortestPath(int k, vector<vector<int>> &mat) {
    int n = mat.size();
    int m = mat[0].size();

    queue<vector<int>> q;
    vector<vector<vector<bool>>> vis(
        n, vector<vector<bool>>(m, vector<bool>(k + 1, false))
    );

    vector<vector<int>> dirs = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};

    q.push({0, 0, 0});
    vis[0][0][0] = true;

    int steps = 0;

    while (!q.empty()) {
        int sz = q.size();

        while (sz--) {
            vector<int> curr = q.front();
            q.pop();

            int i = curr[0], j = curr[1], removed = curr[2];

            if (i == n - 1 && j == m - 1) {
                return steps;
            }

            for (auto &dir : dirs) {
                int x = i + dir[0];
                int y = j + dir[1];

                if (x < 0 || y < 0 || x >= n || y >= m) {
                    continue;
                }

                int newRemoved = removed + mat[x][y];

                if (newRemoved > k || vis[x][y][newRemoved]) {
                    continue;
                }

                vis[x][y][newRemoved] = true;
                q.push({x, y, newRemoved});
            }
        }

        steps++;
    }

    return -1;
}

int main() {
    int k = 1;
    vector<vector<int>> mat = {{0, 0, 0}, {0, 0, 1}, {0, 1, 0}};
    cout << shortestPath(k, mat) << endl;

    k = 0;
    mat = {{0, 1}, {1, 0}};
    cout << shortestPath(k, mat) << endl;

    return 0;
}
Java
import java.util.Queue;
import java.util.LinkedList;

class GFG {
    static int shortestPath(int k, int[][] mat) {
        int n = mat.length;
        int m = mat[0].length;

        Queue<int[]> q = new LinkedList<>();
        boolean[][][] vis = new boolean[n][m][k + 1];

        int[][] dirs = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};

        q.offer(new int[] {0, 0, 0});
        vis[0][0][0] = true;

        int steps = 0;

        while (!q.isEmpty()) {
            int sz = q.size();

            while (sz-- > 0) {
                int[] curr = q.poll();

                int i = curr[0], j = curr[1], removed = curr[2];

                if (i == n - 1 && j == m - 1) {
                    return steps;
                }

                for (int[] dir : dirs) {
                    int x = i + dir[0];
                    int y = j + dir[1];

                    if (x < 0 || y < 0 || x >= n || y >= m) {
                        continue;
                    }

                    int newRemoved = removed + mat[x][y];

                    if (newRemoved > k || vis[x][y][newRemoved]) {
                        continue;
                    }

                    vis[x][y][newRemoved] = true;
                    q.offer(new int[] {x, y, newRemoved});
                }
            }

            steps++;
        }

        return -1;
    }

    public static void main(String[] args) {
        int k = 1;
        int[][] mat = {{0, 0, 0}, {0, 0, 1}, {0, 1, 0}};
        System.out.println(shortestPath(k, mat));

        k = 0;
        mat = new int[][] {{0, 1}, {1, 0}};
        System.out.println(shortestPath(k, mat));
    }
}
Python
from collections import deque

def shortestPath(k, mat):
    n = len(mat)
    m = len(mat[0])

    q = deque()
    vis = [[[False] * (k + 1) for _ in range(m)] for _ in range(n)]

    dirs = [(1, 0), (-1, 0), (0, 1), (0, -1)]

    q.append((0, 0, 0))
    vis[0][0][0] = True

    steps = 0

    while q:
        for _ in range(len(q)):
            i, j, removed = q.popleft()

            if i == n - 1 and j == m - 1:
                return steps

            for dx, dy in dirs:
                x = i + dx
                y = j + dy

                if x < 0 or y < 0 or x >= n or y >= m:
                    continue

                newRemoved = removed + mat[x][y]

                if newRemoved > k or vis[x][y][newRemoved]:
                    continue

                vis[x][y][newRemoved] = True
                q.append((x, y, newRemoved))

        steps += 1

    return -1


if __name__ == "__main__":
    k = 1
    mat = [[0, 0, 0], [0, 0, 1], [0, 1, 0]]
    print(shortestPath(k, mat))

    k = 0
    mat = [[0, 1], [1, 0]]
    print(shortestPath(k, mat))
C#
using System;
using System.Collections.Generic;

class GFG {
    static int shortestPath(int k, int[][] mat) {
        int n = mat.Length;
        int m = mat[0].Length;

        Queue<int[]> q = new Queue<int[]>();
        bool[,,] vis = new bool[n, m, k + 1];

        int[][] dirs = {
            new int[] {1, 0},
            new int[] {-1, 0},
            new int[] {0, 1},
            new int[] {0, -1}
        };

        q.Enqueue(new int[] {0, 0, 0});
        vis[0, 0, 0] = true;

        int steps = 0;

        while (q.Count > 0) {
            int sz = q.Count;

            while (sz-- > 0) {
                int[] curr = q.Dequeue();

                int i = curr[0], j = curr[1], removed = curr[2];

                if (i == n - 1 && j == m - 1) {
                    return steps;
                }

                foreach (int[] dir in dirs) {
                    int x = i + dir[0];
                    int y = j + dir[1];

                    if (x < 0 || y < 0 || x >= n || y >= m) {
                        continue;
                    }

                    int newRemoved = removed + mat[x][y];

                    if (newRemoved > k || vis[x, y, newRemoved]) {
                        continue;
                    }

                    vis[x, y, newRemoved] = true;
                    q.Enqueue(new int[] {x, y, newRemoved});
                }
            }

            steps++;
        }

        return -1;
    }

    static void Main() {
        int k = 1;
        int[][] mat = {
            new int[] {0, 0, 0},
            new int[] {0, 0, 1},
            new int[] {0, 1, 0}
        };
        Console.WriteLine(shortestPath(k, mat));

        k = 0;
        mat = new int[][] {
            new int[] {0, 1},
            new int[] {1, 0}
        };
        Console.WriteLine(shortestPath(k, mat));
    }
}
JavaScript
function shortestPath(k, mat) {
    let n = mat.length;
    let m = mat[0].length;

    let q = [[0, 0, 0]];
    let front = 0;

    let vis = Array.from({ length: n }, () =>
        Array.from({ length: m }, () => Array(k + 1).fill(false))
    );

    let dirs = [[1, 0], [-1, 0], [0, 1], [0, -1]];

    vis[0][0][0] = true;

    let steps = 0;

    while (front < q.length) {
        let sz = q.length - front;

        while (sz--) {
            let [i, j, removed] = q[front++];

            if (i === n - 1 && j === m - 1) {
                return steps;
            }

            for (let [dx, dy] of dirs) {
                let x = i + dx;
                let y = j + dy;

                if (x < 0 || y < 0 || x >= n || y >= m) {
                    continue;
                }

                let newRemoved = removed + mat[x][y];

                if (newRemoved > k || vis[x][y][newRemoved]) {
                    continue;
                }

                vis[x][y][newRemoved] = true;
                q.push([x, y, newRemoved]);
            }
        }

        steps++;
    }

    return -1;
}

// Driver Code
let k = 1;
let mat = [[0, 0, 0], [0, 0, 1], [0, 1, 0]];
console.log(shortestPath(k, mat));

k = 0;
mat = [[0, 1], [1, 0]];
console.log(shortestPath(k, mat));

Output
4
-1

[Expected Approach] BFS with Minimum Walls Removed - O(n × m × k) Time and O(n × m) Space

Instead of storing all states in a 3D visited array, store the minimum walls removed to reach each cell. A cell is revisited only if it can be reached with fewer removed walls.

C++
#include <iostream>
#include <vector>
#include <queue>
#include <climits>
using namespace std;

int shortestPath(int k, vector<vector<int>> &mat) {
    int n = mat.size();
    int m = mat[0].size();

    queue<vector<int>> q;
    vector<vector<int>> obstacles(n, vector<int>(m, INT_MAX));

    vector<vector<int>> dirs = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};

    // obstacles[i][j] stores the minimum walls removed
    // to reach cell (i, j)
    obstacles[0][0] = mat[0][0];
    q.push({0, 0});

    int steps = 0;

    while (!q.empty()) {
        int sz = q.size();

        while (sz--) {
            vector<int> curr = q.front();
            q.pop();

            int i = curr[0];
            int j = curr[1];

            if (i == n - 1 && j == m - 1) {
                return steps;
            }

            for (auto &dir : dirs) {
                int x = i + dir[0];
                int y = j + dir[1];

                if (x < 0 || y < 0 || x >= n || y >= m) {
                    continue;
                }

                if (obstacles[i][j] + mat[x][y] > k) {
                    continue;
                }

                if (obstacles[x][y] <= obstacles[i][j] + mat[x][y]) {
                    continue;
                }

                obstacles[x][y] = obstacles[i][j] + mat[x][y];
                q.push({x, y});
            }
        }

        steps++;
    }

    return -1;
}

int main() {
    int k = 1;
    vector<vector<int>> mat = {{0, 0, 0}, {0, 0, 1}, {0, 1, 0}};
    cout << shortestPath(k, mat) << endl;

    k = 0;
    mat = {{0, 1}, {1, 0}};
    cout << shortestPath(k, mat) << endl;

    return 0;
}
Java
import java.util.Arrays;
import java.util.Queue;
import java.util.LinkedList;

class GFG {
    static int shortestPath(int k, int[][] mat) {
        int n = mat.length;
        int m = mat[0].length;

        Queue<int[]> q = new LinkedList<>();
        int[][] obstacles = new int[n][m];

        for (int[] row : obstacles) {
            Arrays.fill(row, Integer.MAX_VALUE);
        }

        int[][] dirs = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};

        obstacles[0][0] = mat[0][0];
        q.offer(new int[] {0, 0});

        int steps = 0;

        while (!q.isEmpty()) {
            int sz = q.size();

            while (sz-- > 0) {
                int[] curr = q.poll();

                int i = curr[0];
                int j = curr[1];

                if (i == n - 1 && j == m - 1) {
                    return steps;
                }

                for (int[] dir : dirs) {
                    int x = i + dir[0];
                    int y = j + dir[1];

                    if (x < 0 || y < 0 || x >= n || y >= m) {
                        continue;
                    }

                    if (obstacles[i][j] + mat[x][y] > k) {
                        continue;
                    }

                    if (obstacles[x][y] <= obstacles[i][j] + mat[x][y]) {
                        continue;
                    }

                    obstacles[x][y] = obstacles[i][j] + mat[x][y];
                    q.offer(new int[] {x, y});
                }
            }

            steps++;
        }

        return -1;
    }

    public static void main(String[] args) {
        int k = 1;
        int[][] mat = {{0, 0, 0}, {0, 0, 1}, {0, 1, 0}};
        System.out.println(shortestPath(k, mat));

        k = 0;
        mat = new int[][] {{0, 1}, {1, 0}};
        System.out.println(shortestPath(k, mat));
    }
}
Python
from collections import deque

def shortestPath(k, mat):
    n = len(mat)
    m = len(mat[0])

    q = deque()
    obstacles = [[float("inf")] * m for _ in range(n)]

    dirs = [(1, 0), (-1, 0), (0, 1), (0, -1)]

    obstacles[0][0] = mat[0][0]
    q.append((0, 0))

    steps = 0

    while q:
        for _ in range(len(q)):
            i, j = q.popleft()

            if i == n - 1 and j == m - 1:
                return steps

            for dx, dy in dirs:
                x = i + dx
                y = j + dy

                if x < 0 or y < 0 or x >= n or y >= m:
                    continue

                if obstacles[i][j] + mat[x][y] > k:
                    continue

                if obstacles[x][y] <= obstacles[i][j] + mat[x][y]:
                    continue

                obstacles[x][y] = obstacles[i][j] + mat[x][y]
                q.append((x, y))

        steps += 1

    return -1


if __name__ == "__main__":
    k = 1
    mat = [[0, 0, 0], [0, 0, 1], [0, 1, 0]]
    print(shortestPath(k, mat))

    k = 0
    mat = [[0, 1], [1, 0]]
    print(shortestPath(k, mat))
C#
using System;
using System.Collections.Generic;

class GFG {
    static int shortestPath(int k, int[][] mat) {
        int n = mat.Length;
        int m = mat[0].Length;

        Queue<int[]> q = new Queue<int[]>();
        int[,] obstacles = new int[n, m];

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                obstacles[i, j] = int.MaxValue;
            }
        }

        int[][] dirs = {
            new int[] {1, 0},
            new int[] {-1, 0},
            new int[] {0, 1},
            new int[] {0, -1}
        };

        obstacles[0, 0] = mat[0][0];
        q.Enqueue(new int[] {0, 0});

        int steps = 0;

        while (q.Count > 0) {
            int sz = q.Count;

            while (sz-- > 0) {
                int[] curr = q.Dequeue();

                int i = curr[0];
                int j = curr[1];

                if (i == n - 1 && j == m - 1) {
                    return steps;
                }

                foreach (int[] dir in dirs) {
                    int x = i + dir[0];
                    int y = j + dir[1];

                    if (x < 0 || y < 0 || x >= n || y >= m) {
                        continue;
                    }

                    if (obstacles[i, j] + mat[x][y] > k) {
                        continue;
                    }

                    if (obstacles[x, y] <= obstacles[i, j] + mat[x][y]) {
                        continue;
                    }

                    obstacles[x, y] = obstacles[i, j] + mat[x][y];
                    q.Enqueue(new int[] {x, y});
                }
            }

            steps++;
        }

        return -1;
    }

    static void Main() {
        int k = 1;
        int[][] mat = {
            new int[] {0, 0, 0},
            new int[] {0, 0, 1},
            new int[] {0, 1, 0}
        };

        Console.WriteLine(shortestPath(k, mat));

        k = 0;
        mat = new int[][] {
            new int[] {0, 1},
            new int[] {1, 0}
        };

        Console.WriteLine(shortestPath(k, mat));
    }
}
JavaScript
function shortestPath(k, mat) {
    let n = mat.length;
    let m = mat[0].length;

    let q = [[0, 0]];
    let front = 0;

    let obstacles = Array.from({ length: n }, () => Array(m).fill(Infinity));
    let dirs = [[1, 0], [-1, 0], [0, 1], [0, -1]];

    obstacles[0][0] = mat[0][0];

    let steps = 0;

    while (front < q.length) {
        let sz = q.length - front;

        while (sz--) {
            let [i, j] = q[front++];

            if (i === n - 1 && j === m - 1) {
                return steps;
            }

            for (let [dx, dy] of dirs) {
                let x = i + dx;
                let y = j + dy;

                if (x < 0 || y < 0 || x >= n || y >= m) {
                    continue;
                }

                if (obstacles[i][j] + mat[x][y] > k) {
                    continue;
                }

                if (obstacles[x][y] <= obstacles[i][j] + mat[x][y]) {
                    continue;
                }

                obstacles[x][y] = obstacles[i][j] + mat[x][y];
                q.push([x, y]);
            }
        }

        steps++;
    }

    return -1;
}

// Driver Code
let k = 1;
let mat = [[0, 0, 0], [0, 0, 1], [0, 1, 0]];
console.log(shortestPath(k, mat));

k = 0;
mat = [[0, 1], [1, 0]];
console.log(shortestPath(k, mat));

Output
4
-1
Comment