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.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.
Table of Content
[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.
#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;
}
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));
}
}
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))
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));
}
}
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.
#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;
}
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));
}
}
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))
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));
}
}
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.
#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;
}
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));
}
}
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))
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));
}
}
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
