Given a 2D binary matrix mat[][] where 0 represents a landmine and 1 represents a safe cell, find the length of the shortest safe route from any cell in the first column to any cell in the last column.
You can move only up, down, left, or right, and can enter only safe cells (cells that are neither landmines nor adjacent to a landmine). If there is no safe path to reach the last column, return -1.
Examples:
Input: mat[][] = [ [1, 0, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 0, 1], [1, 1, 1, 1, 0] ] Output: 6 Explanation: The shortest safe path starts from the first column (row 2, column 0) and reaches the last column (row 1, column 4) with length 6.
Input: mat[][] = [ [1, 1, 1, 1, 1], [1, 1, 0, 1, 1], [1, 1, 1, 1, 1] ] Output: -1 Explanation: There is no possible path from first column to last column.
[Naive Approach] Using Backtracking - O(4(n*m)) Time and O(n*m) Space
The idea is to use Backtracking. We first mark all adjacent cells of the landmines as unsafe. Then for each safe cell of first column of the matrix, we move forward in all allowed directions and recursively checks if they leads to the destination or not. If destination is found, we update the value of shortest path else if none of the above solutions work we return false from our function.
C++
//Driver Code Starts#include<iostream>#include<vector>#include<climits>#include<algorithm>usingnamespacestd;//Driver Code Ends// Function to mark unsafe cells (landmines and their adjacent cells)voidmarkUnsafeCells(vector<vector<int>>&mat){intr=mat.size();intc=mat[0].size();// Directions for adjacent cells: up, down, left, rightintrow[]={-1,1,0,0};intcol[]={0,0,-1,1};vector<vector<int>>temp=mat;// Mark adjacent cells of landmines (0) as unsafe (0)for(inti=0;i<r;i++){for(intj=0;j<c;j++){if(temp[i][j]==0){for(intk=0;k<4;k++){intni=i+row[k];intnj=j+col[k];if(ni>=0&&ni<r&&nj>=0&&nj<c){mat[ni][nj]=0;}}}}}}// DFS to find shortest path from (i, j) to any cell in last columnintdfs(vector<vector<int>>&mat,vector<vector<bool>>&visited,inti,intj,intc){intr=mat.size();if(i<0||i>=r||j<0||j>=c||mat[i][j]==0||visited[i][j]){returnINT_MAX;}if(j==c-1){return1;}visited[i][j]=true;// Four possible moves: up, down, left, rightintrow[]={-1,1,0,0};intcol[]={0,0,-1,1};intminPath=INT_MAX;// Try all four directionsfor(intk=0;k<4;k++){intni=i+row[k];intnj=j+col[k];intpathLength=dfs(mat,visited,ni,nj,c);if(pathLength!=INT_MAX){minPath=min(minPath,1+pathLength);}}// Backtrack - unmark current cellvisited[i][j]=false;returnminPath;}intshortestPath(vector<vector<int>>&mat){intr=mat.size();intc=mat[0].size();// Mark all adjacent cells of landmines as unsafemarkUnsafeCells(mat);// Initialize visited arrayvector<vector<bool>>visited(r,vector<bool>(c,false));intminPath=INT_MAX;// Try starting from each safe cell in the first columnfor(inti=0;i<r;i++){if(mat[i][0]==1){intpathLength=dfs(mat,visited,i,0,c);if(pathLength!=INT_MAX){minPath=min(minPath,pathLength);}}}returnminPath==INT_MAX?-1:minPath;}//Driver Code Startsintmain(){vector<vector<int>>mat={{1,0,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,0,1},{1,1,1,1,0}};intresult=shortestPath(mat);cout<<result<<endl;return0;}//Driver Code Ends
Java
//Driver Code Startsimportjava.util.Arrays;classGFG{//Driver Code Ends// Function to mark unsafe cells (landmines and their adjacent cells)staticvoidmarkUnsafeCells(int[][]mat){intr=mat.length;intc=mat[0].length;int[]row={-1,1,0,0};int[]col={0,0,-1,1};int[][]temp=newint[r][c];for(inti=0;i<r;i++){for(intj=0;j<c;j++){temp[i][j]=mat[i][j];}}// Mark adjacent cells of landmines (0) as unsafe (0)for(inti=0;i<r;i++){for(intj=0;j<c;j++){if(temp[i][j]==0){for(intk=0;k<4;k++){intni=i+row[k];intnj=j+col[k];if(ni>=0&&ni<r&&nj>=0&&nj<c){mat[ni][nj]=0;}}}}}}// DFS to find shortest path from (i, j) to any cell in last columnstaticintdfs(int[][]mat,boolean[][]visited,inti,intj,intc){intr=mat.length;// If out of bounds, blocked, or visitedif(i<0||i>=r||j<0||j>=c||mat[i][j]==0||visited[i][j]){returnInteger.MAX_VALUE;}if(j==c-1){return1;}visited[i][j]=true;int[]row={-1,1,0,0};int[]col={0,0,-1,1};intminPath=Integer.MAX_VALUE;// Try all four directionsfor(intk=0;k<4;k++){intni=i+row[k];intnj=j+col[k];intpathLength=dfs(mat,visited,ni,nj,c);if(pathLength!=Integer.MAX_VALUE){minPath=Math.min(minPath,1+pathLength);}}// Backtrack - unmark current cellvisited[i][j]=false;returnminPath;}staticintshortestPath(int[][]mat){intr=mat.length;intc=mat[0].length;// Mark all adjacent cells of landmines as unsafemarkUnsafeCells(mat);boolean[][]visited=newboolean[r][c];intminPath=Integer.MAX_VALUE;// Try starting from each safe cell in the first columnfor(inti=0;i<r;i++){if(mat[i][0]==1){intpathLength=dfs(mat,visited,i,0,c);if(pathLength!=Integer.MAX_VALUE){minPath=Math.min(minPath,pathLength);}}}returnminPath==Integer.MAX_VALUE?-1:minPath;}//Driver Code Startspublicstaticvoidmain(String[]args){int[][]mat={{1,0,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,0,1},{1,1,1,1,0}};intresult=shortestPath(mat);System.out.println(result);}}//Driver Code Ends
Python
#Driver Code Startsimportsys#Driver Code Ends# Function to mark unsafe cells (landmines and their adjacent cells)defmarkUnsafeCells(mat):r=len(mat)c=len(mat[0])# Directions for adjacent cells: up, down, left, rightrow_dir=[-1,1,0,0]col_dir=[0,0,-1,1]temp=[row[:]forrowinmat]# Mark adjacent cells of landmines (0) as unsafe (0)foriinrange(r):forjinrange(c):iftemp[i][j]==0:forkinrange(4):ni=i+row_dir[k]nj=j+col_dir[k]if0<=ni<rand0<=nj<c:mat[ni][nj]=0# DFS to find shortest path from (i, j) to any cell in last columndefdfs(mat,visited,i,j,c):r=len(mat)# If out of bounds, blocked, or already visitedifi<0ori>=rorj<0orj>=cormat[i][j]==0orvisited[i][j]:returnsys.maxsize# If last column reachedifj==c-1:return1visited[i][j]=True# Four possible moves: up, down, left, rightrow_dir=[-1,1,0,0]col_dir=[0,0,-1,1]minPath=sys.maxsize# Explore all four directionsforkinrange(4):ni=i+row_dir[k]nj=j+col_dir[k]pathLength=dfs(mat,visited,ni,nj,c)ifpathLength!=sys.maxsize:minPath=min(minPath,1+pathLength)# Backtrack - unmark current cellvisited[i][j]=FalsereturnminPathdefshortestPath(mat):r=len(mat)c=len(mat[0])# Mark all adjacent cells of landmines as unsafemarkUnsafeCells(mat)# Initialize visited arrayvisited=[[False]*cfor_inrange(r)]minPath=sys.maxsize# Try starting from each safe cell in the first columnforiinrange(r):ifmat[i][0]==1:pathLength=dfs(mat,visited,i,0,c)ifpathLength!=sys.maxsize:minPath=min(minPath,pathLength)return-1ifminPath==sys.maxsizeelseminPath#Driver Code Startsif__name__=="__main__":mat=[[1,0,1,1,1],[1,1,1,1,1],[1,1,1,1,1],[1,1,1,0,1],[1,1,1,1,0]]result=shortestPath(mat)print(result)#Driver Code Ends
C#
usingSystem;classGFG{// Function to mark unsafe cells (landmines and their adjacent cells)staticvoidmarkUnsafeCells(int[,]mat){intr=mat.GetLength(0);intc=mat.GetLength(1);// Directions for adjacent cells: up, down, left, rightint[]rowDir={-1,1,0,0};int[]colDir={0,0,-1,1};int[,]temp=newint[r,c];for(inti=0;i<r;i++)for(intj=0;j<c;j++)temp[i,j]=mat[i,j];// Mark adjacent cells of landmines (0) as unsafe (0)for(inti=0;i<r;i++){for(intj=0;j<c;j++){if(temp[i,j]==0){for(intk=0;k<4;k++){intni=i+rowDir[k];intnj=j+colDir[k];if(ni>=0&&ni<r&&nj>=0&&nj<c){mat[ni,nj]=0;}}}}}}// DFS to find shortest path from (i, j) to any cell in last columnstaticintdfs(int[,]mat,bool[,]visited,inti,intj,intc){intr=mat.GetLength(0);// If out of bounds, blocked, or already visitedif(i<0||i>=r||j<0||j>=c||mat[i,j]==0||visited[i,j])returnint.MaxValue;// If last column reachedif(j==c-1)return1;visited[i,j]=true;int[]rowDir={-1,1,0,0};int[]colDir={0,0,-1,1};intminPath=int.MaxValue;// Explore all four directionsfor(intk=0;k<4;k++){intni=i+rowDir[k];intnj=j+colDir[k];intpathLength=dfs(mat,visited,ni,nj,c);if(pathLength!=int.MaxValue)minPath=Math.Min(minPath,1+pathLength);}// Backtrack - unmark current cellvisited[i,j]=false;returnminPath;}staticintshortestPath(int[,]mat){intr=mat.GetLength(0);intc=mat.GetLength(1);// Mark all adjacent cells of landmines as unsafemarkUnsafeCells(mat);bool[,]visited=newbool[r,c];intminPath=int.MaxValue;// Try starting from each safe cell in the first columnfor(inti=0;i<r;i++){if(mat[i,0]==1){intpathLength=dfs(mat,visited,i,0,c);if(pathLength!=int.MaxValue)minPath=Math.Min(minPath,pathLength);}}returnminPath==int.MaxValue?-1:minPath;}publicstaticvoidMain(){int[,]mat={{1,0,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,0,1},{1,1,1,1,0}};intresult=shortestPath(mat);Console.WriteLine(result);}}
JavaScript
// Function to mark unsafe cells (landmines and their adjacent cells)functionmarkUnsafeCells(mat){constr=mat.length;constc=mat[0].length;constrowDir=[-1,1,0,0];constcolDir=[0,0,-1,1];// Create a copy to avoid modifying original safe cells prematurelyconsttemp=mat.map(row=>row.slice());// Mark adjacent cells of landmines (0) as unsafe (0)for(leti=0;i<r;i++){for(letj=0;j<c;j++){if(temp[i][j]===0){for(letk=0;k<4;k++){constni=i+rowDir[k];constnj=j+colDir[k];if(ni>=0&&ni<r&&nj>=0&&nj<c){mat[ni][nj]=0;}}}}}}// DFS to find shortest path from (i, j) to any cell in last columnfunctiondfs(mat,visited,i,j,c){constr=mat.length;// If out of bounds, blocked, or already visitedif(i<0||i>=r||j<0||j>=c||mat[i][j]===0||visited[i][j]){returnNumber.MAX_SAFE_INTEGER;}// If last column reachedif(j===c-1)return1;visited[i][j]=true;constrowDir=[-1,1,0,0];constcolDir=[0,0,-1,1];letminPath=Number.MAX_SAFE_INTEGER;// Explore all four directionsfor(letk=0;k<4;k++){constni=i+rowDir[k];constnj=j+colDir[k];constpathLength=dfs(mat,visited,ni,nj,c);if(pathLength!==Number.MAX_SAFE_INTEGER){minPath=Math.min(minPath,1+pathLength);}}// Backtrack - unmark current cellvisited[i][j]=false;returnminPath;}functionshortestPath(mat){constr=mat.length;constc=mat[0].length;markUnsafeCells(mat);constvisited=Array.from({length:r},()=>Array(c).fill(false));letminPath=Number.MAX_SAFE_INTEGER;// Try starting from each safe cell in the first columnfor(leti=0;i<r;i++){if(mat[i][0]===1){constpathLength=dfs(mat,visited,i,0,c);if(pathLength!==Number.MAX_SAFE_INTEGER){minPath=Math.min(minPath,pathLength);}}}returnminPath===Number.MAX_SAFE_INTEGER?-1:minPath;}//Driver Code Starts// Driver codeconstmat=[[1,0,1,1,1],[1,1,1,1,1],[1,1,1,1,1],[1,1,1,0,1],[1,1,1,1,0]];constresult=shortestPath(mat);console.log(result);//Driver Code Ends
Output
6
[Expected Approach] Using Breadth First Search - O(n*m) Time and O(n*m) Space
The idea is to use BFS to find the shortest safe path from any cell in the first column to the last column in a binary matrix. BFS is ideal here because it explores cells level by level, so the first time we reach a cell in the last column, we are guaranteed that it is via the shortest path.
For each cell we visit, we check if it is safe by ensuring it is not a landmine and none of its four neighbors is a landmine. Safe cells are added to the queue with their current distance, and we mark them visited directly in the matrix to avoid revisiting. BFS continues until a last-column cell is reached, returning its distance, or returns -1 if no safe path exists.
C++
//Driver Code Starts#include<iostream>#include<vector>#include<queue>usingnamespacestd;//Driver Code Ends// Check if a cell (i,j) is safe to step onboolisSafe(vector<vector<int>>&mat,inti,intj){intr=mat.size();intc=mat[0].size();// cell itself is a landmine or visitedif(mat[i][j]!=1)returnfalse;// Check all four neighborsintrowDir[]={-1,1,0,0};intcolDir[]={0,0,-1,1};for(intk=0;k<4;k++){intni=i+rowDir[k];intnj=j+colDir[k];if(ni>=0&&ni<r&&nj>=0&&nj<c&&mat[ni][nj]==0)// adjacent to a landminereturnfalse;}returntrue;}// function to find shortest safe path from first column to last columnintshortestPath(vector<vector<int>>&mat){intr=mat.size();intc=mat[0].size();introwDir[]={-1,1,0,0};intcolDir[]={0,0,-1,1};// {i, j, distance}queue<array<int,3>>q;// Enqueue all safe cells in the first columnfor(inti=0;i<r;i++){if(isSafe(mat,i,0)){q.push({i,0,1});// mark visitedmat[i][0]=-1;}}while(!q.empty()){autofront=q.front();q.pop();inti=front[0];intj=front[1];intdist=front[2];// Reached last columnif(j==c-1)returndist;// Explore four directionsfor(intk=0;k<4;k++){intni=i+rowDir[k];intnj=j+colDir[k];if(ni>=0&&ni<r&&nj>=0&&nj<c&&isSafe(mat,ni,nj)){q.push({ni,nj,dist+1});// mark visitedmat[ni][nj]=-1;}}}// no path foundreturn-1;}//Driver Code Startsintmain(){vector<vector<int>>mat={{1,0,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,0,1},{1,1,1,1,0}};intresult=shortestPath(mat);cout<<result<<endl;return0;}//Driver Code Ends
Java
//Driver Code Startsimportjava.util.ArrayDeque;importjava.util.Deque;classGFG{//Driver Code Ends// Check if a cell (i,j) is safe to step onstaticbooleanisSafe(int[][]mat,inti,intj){intr=mat.length;intc=mat[0].length;// cell itself is a landmine or visitedif(mat[i][j]!=1)returnfalse;// Check all four neighborsint[]rowDir={-1,1,0,0};int[]colDir={0,0,-1,1};for(intk=0;k<4;k++){intni=i+rowDir[k];intnj=j+colDir[k];if(ni>=0&&ni<r&&nj>=0&&nj<c&&mat[ni][nj]==0)// adjacent to a landminereturnfalse;}returntrue;}// Function to find shortest safe path// from first column to last columnstaticintshortestPath(int[][]mat){intr=mat.length;intc=mat[0].length;int[]rowDir={-1,1,0,0};int[]colDir={0,0,-1,1};// {i, j, distance}Deque<int[]>q=newArrayDeque<>();// Enqueue all safe cells in the first columnfor(inti=0;i<r;i++){if(isSafe(mat,i,0)){q.add(newint[]{i,0,1});mat[i][0]=-1;// mark visited}}while(!q.isEmpty()){int[]front=q.poll();inti=front[0],j=front[1],dist=front[2];// Reached last columnif(j==c-1)returndist;// Explore four directionsfor(intk=0;k<4;k++){intni=i+rowDir[k];intnj=j+colDir[k];if(ni>=0&&ni<r&&nj>=0&&nj<c&&isSafe(mat,ni,nj)){q.add(newint[]{ni,nj,dist+1});mat[ni][nj]=-1;}}}// No path foundreturn-1;}//Driver Code Startspublicstaticvoidmain(String[]args){int[][]mat={{1,0,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,0,1},{1,1,1,1,0}};intresult=shortestPath(mat);System.out.println(result);}}//Driver Code Ends
Python
#Driver Code Startsfromcollectionsimportdeque#Driver Code Ends# Check if a cell (i,j) is safe to step ondefisSafe(mat,i,j):r,c=len(mat),len(mat[0])# cell itself is a landmine or visitedifmat[i][j]!=1:returnFalse# Check all four neighborsrowDir=[-1,1,0,0]colDir=[0,0,-1,1]forkinrange(4):ni,nj=i+rowDir[k],j+colDir[k]if0<=ni<rand0<=nj<candmat[ni][nj]==0:# adjacent to a landminereturnFalsereturnTrue# Function to find shortest safe path # from first column to last columndefshortestPath(mat):r,c=len(mat),len(mat[0])rowDir=[-1,1,0,0]colDir=[0,0,-1,1]q=deque()# stores [i, j, distance]# Enqueue all safe cells in the first columnforiinrange(r):ifisSafe(mat,i,0):q.append([i,0,1])mat[i][0]=-1whileq:i,j,dist=q.popleft()# Reached last columnifj==c-1:returndist# Explore four directionsforkinrange(4):ni,nj=i+rowDir[k],j+colDir[k]if0<=ni<rand0<=nj<candisSafe(mat,ni,nj):q.append([ni,nj,dist+1])mat[ni][nj]=-1# No path foundreturn-1#Driver Code Startsif__name__=="__main__":mat=[[1,0,1,1,1],[1,1,1,1,1],[1,1,1,1,1],[1,1,1,0,1],[1,1,1,1,0]]result=shortestPath(mat)print(result)#Driver Code Ends
C#
//Driver Code StartsusingSystem;usingSystem.Collections.Generic;classGFG{//Driver Code Ends// Check if a cell (i,j) is safe to step onstaticboolisSafe(int[,]mat,inti,intj){intr=mat.GetLength(0);intc=mat.GetLength(1);// cell itself is a landmine or visitedif(mat[i,j]!=1)returnfalse;int[]rowDir={-1,1,0,0};int[]colDir={0,0,-1,1};for(intk=0;k<4;k++){intni=i+rowDir[k];intnj=j+colDir[k];if(ni>=0&&ni<r&&nj>=0&&nj<c&&mat[ni,nj]==0)// adjacent to a landminereturnfalse;}returntrue;}// Function to find shortest safe path// from first column to last columnstaticintshortestPath(int[,]mat){intr=mat.GetLength(0);intc=mat.GetLength(1);int[]rowDir={-1,1,0,0};int[]colDir={0,0,-1,1};// {i, j, distance}Queue<int[]>q=newQueue<int[]>();// Enqueue all safe cells in the first columnfor(inti=0;i<r;i++){if(isSafe(mat,i,0)){q.Enqueue(newint[]{i,0,1});// mark visitedmat[i,0]=-1;}}while(q.Count>0){varfront=q.Dequeue();inti=front[0],j=front[1],dist=front[2];// reached last columnif(j==c-1)returndist;for(intk=0;k<4;k++){intni=i+rowDir[k];intnj=j+colDir[k];if(ni>=0&&ni<r&&nj>=0&&nj<c&&isSafe(mat,ni,nj)){q.Enqueue(newint[]{ni,nj,dist+1});// mark visitedmat[ni,nj]=-1;}}}// no path foundreturn-1;}//Driver Code StartsstaticvoidMain(){int[,]mat={{1,0,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,0,1},{1,1,1,1,0}};intresult=shortestPath(mat);Console.WriteLine(result);}}//Driver Code Ends
JavaScript
constDenque=require("denque");// Check if a cell (i,j) is safe to step onfunctionisSafe(mat,i,j){letr=mat.length;letc=mat[0].length;if(mat[i][j]!==1)returnfalse;letrowDir=[-1,1,0,0];letcolDir=[0,0,-1,1];for(letk=0;k<4;k++){letni=i+rowDir[k];letnj=j+colDir[k];if(ni>=0&&ni<r&&nj>=0&&nj<c&&mat[ni][nj]===0){returnfalse;}}returntrue;}// Function to find shortest safe path// from first column to last columnfunctionshortestPath(mat){letr=mat.length;letc=mat[0].length;letrowDir=[-1,1,0,0];letcolDir=[0,0,-1,1];letq=newDenque();// Enqueue all safe cells in the first columnfor(leti=0;i<r;i++){if(isSafe(mat,i,0)){q.push([i,0,1]);// mark visitedmat[i][0]=-1;}}// BFS traversalwhile(!q.isEmpty()){let[i,j,dist]=q.shift();// Reached last columnif(j===c-1)returndist;// Explore four directionsfor(letk=0;k<4;k++){letni=i+rowDir[k];letnj=j+colDir[k];if(ni>=0&&ni<r&&nj>=0&&nj<c&&isSafe(mat,ni,nj)){q.push([ni,nj,dist+1]);// mark visitedmat[ni][nj]=-1;}}}// No safe path foundreturn-1;}//Driver Code Starts// Driver Codeletmat=[[1,0,1,1,1],[1,1,1,1,1],[1,1,1,1,1],[1,1,1,0,1],[1,1,1,1,0]];console.log(shortestPath(mat));//Driver Code Ends