Given a 2D array mat[][] of size n*m. The cost of a path is defined as the maximum absolute difference between the values of any two consecutive cells along that path. You are allowed to move up, down, left, or right to adjacent cells. Find the minimum possible cost of a path from (0, 0) to (n-1, m-1).
Examples:
Input: mat[][] = [[7, 2, 6, 5], [3, 1, 10, 8]] Output: 4 Explanation: The route [7, 3, 1, 2, 6, 5, 8] has a minimum value of maximum absolute difference between two any consecutive cells in the route, i.e., 4.
Input: mat[][] = [[2, 2, 2, 1], [8, 1, 2, 7], [2, 2, 2, 8], [2, 1, 4, 7], [2, 2, 2, 2], Output: 0 Explanation: The route [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2] has a minimum value of maximum absolute difference between two any consecutive cells in the route, i.e., 0.
The idea is to explore every possible path from the current cell to the destination using backtracking. At each step, we move in all valid directions and keep track of the maximum absolute difference between consecutive cell values along the current path. When we finally reach the destination, we compare the cost of this path with the global minimum and update the minimum cost if the current path offers a smaller value. To avoid revisiting cells within the same path, the current cell is temporarily marked as visited and restored afterward.
C++
//Driver Code Starts#include<iostream>#include<vector>#include<climits>usingnamespacestd;//Driver Code EndsintminCost=INT_MAX;// directions: up, down, right, leftintdirArr[4][2]={{-1,0},{1,0},{0,1},{0,-1}};// checks if the next cell is within bounds and not visitedboolisSafe(intx,inty,intd[2],vector<vector<int>>&mat){intn=mat.size();intm=mat[0].size();if(x+d[0]>=0&&x+d[0]<n&&y+d[1]>=0&&y+d[1]<m&&mat[x+d[0]][y+d[1]]!=-1)returntrue;returnfalse;}// explores all possible paths using backtracking and updates minimum costvoidfindMinCost(inti,intj,intmaxDiff,vector<vector<int>>&mat){intn=mat.size();intm=mat[0].size();// reached destination → update global minimumif(i==n-1&&j==m-1){minCost=min(minCost,maxDiff);return;}intcurr=mat[i][j];// mark current cell as visitedmat[i][j]=-1;for(auto&d:dirArr){// move only if next cell is validif(isSafe(i,j,d,mat)){// continue path with updated maximum differencefindMinCost(i+d[0],j+d[1],max(maxDiff,abs(mat[i+d[0]][j+d[1]]-curr)),mat);}}// restore cell value for other pathsmat[i][j]=curr;}// initiates backtracking and// returns minimum possible path costintminCostPath(vector<vector<int>>&mat){minCost=INT_MAX;findMinCost(0,0,0,mat);returnminCost;}//Driver Code Startsintmain(){vector<vector<int>>mat={{7,2,6,5},{3,1,10,8}};cout<<minCostPath(mat);}//Driver Code Ends
Java
//Driver Code StartsclassGFG{//Driver Code EndsstaticintminCost=Integer.MAX_VALUE;// directions: up, down, right, leftstaticint[][]dirArr={{-1,0},{1,0},{0,1},{0,-1}};// checks if next cell is valid and not visitedstaticbooleanisSafe(intx,inty,int[]d,int[][]mat){intn=mat.length;intm=mat[0].length;intnx=x+d[0];intny=y+d[1];returnnx>=0&&nx<n&&ny>=0&&ny<m&&mat[nx][ny]!=-1;}// explores all possible paths and updates minimum coststaticvoidfindMinCost(inti,intj,intmaxDiff,int[][]mat){intn=mat.length;intm=mat[0].length;// reached destination → update minimumif(i==n-1&&j==m-1){minCost=Math.min(minCost,maxDiff);return;}intcurr=mat[i][j];// mark as visitedmat[i][j]=-1;for(int[]d:dirArr){// valid movementif(isSafe(i,j,d,mat)){// continue with updated costfindMinCost(i+d[0],j+d[1],Math.max(maxDiff,Math.abs(mat[i+d[0]][j+d[1]]-curr)),mat);}}// restore for other pathsmat[i][j]=curr;}// initiates backtrackingstaticintminCostPath(int[][]mat){minCost=Integer.MAX_VALUE;findMinCost(0,0,0,mat);returnminCost;}//Driver Code Startspublicstaticvoidmain(String[]args){int[][]mat={{7,2,6,5},{3,1,10,8}};System.out.println(minCostPath(mat));}}//Driver Code Ends
Python
minCost=float('inf')# directions: up, down, right, leftdirArr=[[-1,0],[1,0],[0,1],[0,-1]]# checks if next cell is valid and not visiteddefisSafe(x,y,d,mat):n=len(mat)m=len(mat[0])nx=x+d[0]ny=y+d[1]return0<=nx<nand0<=ny<mandmat[nx][ny]!=-1# explores all possible paths and updates minimum costdeffindMinCost(i,j,maxDiff,mat):globalminCostn=len(mat)m=len(mat[0])# reached destination → update minimumifi==n-1andj==m-1:minCost=min(minCost,maxDiff)returncurr=mat[i][j]# mark as visitedmat[i][j]=-1fordindirArr:# valid movementifisSafe(i,j,d,mat):# continue with updated costfindMinCost(i+d[0],j+d[1],max(maxDiff,abs(mat[i+d[0]][j+d[1]]-curr)),mat)# restore for other pathsmat[i][j]=curr# initiates backtrackingdefminCostPath(mat):globalminCostminCost=float('inf')findMinCost(0,0,0,mat)returnminCost#Driver Code Startsif__name__=='__main__':mat=[[7,2,6,5],[3,1,10,8]]print(minCostPath(mat))#Driver Code Ends
C#
//Driver Code StartsusingSystem;classGFG{//Driver Code EndsstaticintminCost=int.MaxValue;// directions: up, down, right, leftstaticint[,]dirArr={{-1,0},{1,0},{0,1},{0,-1}};// checks if next cell is valid and not visitedstaticboolisSafe(intx,inty,int[]d,int[,]mat){intn=mat.GetLength(0);intm=mat.GetLength(1);intnx=x+d[0];intny=y+d[1];returnnx>=0&&nx<n&&ny>=0&&ny<m&&mat[nx,ny]!=-1;}// explores all possible paths and updates minimum coststaticvoidfindMinCost(inti,intj,intmaxDiff,int[,]mat){intn=mat.GetLength(0);intm=mat.GetLength(1);// reached destination → update minimumif(i==n-1&&j==m-1){minCost=Math.Min(minCost,maxDiff);return;}intcurr=mat[i,j];// mark as visitedmat[i,j]=-1;for(intk=0;k<4;k++){int[]d={dirArr[k,0],dirArr[k,1]};// valid movementif(isSafe(i,j,d,mat)){// continue with updated costintnx=i+d[0];intny=j+d[1];findMinCost(nx,ny,Math.Max(maxDiff,Math.Abs(mat[nx,ny]-curr)),mat);}}// restore for other pathsmat[i,j]=curr;}// initiates backtrackingstaticintminCostPath(int[,]mat){minCost=int.MaxValue;findMinCost(0,0,0,mat);returnminCost;}//Driver Code StartsstaticvoidMain(){int[,]mat={{7,2,6,5},{3,1,10,8}};Console.WriteLine(minCostPath(mat));}}//Driver Code Ends
JavaScript
letminCost=Infinity;// directions: up, down, right, leftletdirArr=[[-1,0],[1,0],[0,1],[0,-1]];// checks if next cell is valid and not visitedfunctionisSafe(x,y,d,mat){letn=mat.length;letm=mat[0].length;letnx=x+d[0];letny=y+d[1];returnnx>=0&&nx<n&&ny>=0&&ny<m&&mat[nx][ny]!==-1;}// explores all possible paths and updates minimum costfunctionfindMinCost(i,j,maxDiff,mat){letn=mat.length;letm=mat[0].length;// reached destination → update minimumif(i===n-1&&j===m-1){minCost=Math.min(minCost,maxDiff);return;}letcurr=mat[i][j];// mark as visitedmat[i][j]=-1;for(letdofdirArr){// valid movementif(isSafe(i,j,d,mat)){// continue with updated costletnx=i+d[0];letny=j+d[1];findMinCost(nx,ny,Math.max(maxDiff,Math.abs(mat[nx][ny]-curr)),mat);}}// restore for other pathsmat[i][j]=curr;}// initiates backtrackingfunctionminCostPath(mat){minCost=Infinity;findMinCost(0,0,0,mat);returnminCost;}//Driver Code Starts// Driver Codeletmat=[[7,2,6,5],[3,1,10,8]];console.log(minCostPath(mat));//Driver Code Ends
Output
4
Time complexity: 3(n*m), Since each of the m×n cells can branch into at most 3 new directions (excluding the previous cell), the overall time complexity is O(3^(m*n)). Auxiliary Space: O(n*m), stack space for a path from source to destination
[Better Approach] - Using Binary Search with Graph Traversal
The key idea is that the minimum possible maximum difference lies within a numeric range, so instead of checking all paths, we binary search on this value. For a given limit mid, we check whether a path exists from (0,0) to (n-1,m-1) such that every move satisfies:
abs(mat[next] - mat[curr]) ≤ mid
To verify this, we run a DFS/BFS and only move to neighbors that follow the limit. If the destination is reachable under this constraint, we try a smaller value; otherwise, we search higher.
Why we are not unmarking visited[][] array
We do not unmark visited cells because, for a fixed mid, DFS only needs to check whether a path exists (true/false), not compute any path value. When a cell is visited the first time, DFS explores all valid neighbors from it under the same mid condition. If a neighbor was already visited, its entire reachable area has already been checked, so revisiting it cannot lead to a different outcome.
C++
//Driver Code Starts#include<iostream>#include<vector>#include<climits>usingnamespacestd;//Driver Code Ends// directions: up, down, right, leftintdirArr[4][2]={{-1,0},{1,0},{0,1},{0,-1}};// DFS to check if we can reach destination// with max allowed difference = limitbooldfs(intx,inty,intlimit,vector<vector<int>>&mat,vector<vector<int>>&vis){intn=mat.size();intm=mat[0].size();// reached destinationif(x==n-1&&y==m-1)returntrue;vis[x][y]=1;for(auto&d:dirArr){intnx=x+d[0];intny=y+d[1];// valid move inside grid and not visitedif(nx>=0&&nx<n&&ny>=0&&ny<m&&!vis[nx][ny]){// move only if difference is within allowed limitif(abs(mat[nx][ny]-mat[x][y])<=limit){if(dfs(nx,ny,limit,mat,vis))returntrue;}}}returnfalse;}// checks if path exists for given maximum allowed differenceboolcanReach(intlimit,vector<vector<int>>&mat){intn=mat.size();intm=mat[0].size();vector<vector<int>>vis(n,vector<int>(m,0));returndfs(0,0,limit,mat,vis);}// binary search on minimum possible maximum differenceintminCostPath(vector<vector<int>>&mat){intlow=0,high=0;intn=mat.size();intm=mat[0].size();// compute upper bound of differencesfor(inti=0;i<n;i++){for(intj=0;j<m;j++){if(i+1<n)high=max(high,abs(mat[i+1][j]-mat[i][j]));if(j+1<m)high=max(high,abs(mat[i][j+1]-mat[i][j]));}}intans=high;// binary search to find smallest feasible limitwhile(low<=high){intmid=(low+high)/2;if(canReach(mid,mat)){ans=mid;high=mid-1;}else{low=mid+1;}}returnans;}//Driver Code Startsintmain(){vector<vector<int>>mat={{7,2,6,5},{3,1,10,8}};cout<<minCostPath(mat);}//Driver Code Ends
Java
//Driver Code StartsclassGFG{//Driver Code Ends// directions: up, down, right, leftstaticint[][]dirArr={{-1,0},{1,0},{0,1},{0,-1}};// DFS to check if we can reach destination // with allowed difference = limitstaticbooleandfs(intx,inty,intlimit,int[][]mat,int[][]vis){intn=mat.length;intm=mat[0].length;if(x==n-1&&y==m-1)returntrue;vis[x][y]=1;for(int[]d:dirArr){intnx=x+d[0];intny=y+d[1];if(nx>=0&&nx<n&&ny>=0&&ny<m&&vis[nx][ny]==0){if(Math.abs(mat[nx][ny]-mat[x][y])<=limit){if(dfs(nx,ny,limit,mat,vis))returntrue;}}}returnfalse;}// checks if path exists for this limitstaticbooleancanReach(intlimit,int[][]mat){intn=mat.length;intm=mat[0].length;int[][]vis=newint[n][m];returndfs(0,0,limit,mat,vis);}// binary search on minimum possible maximum differencestaticintminCostPath(int[][]mat){intn=mat.length;intm=mat[0].length;intlow=0,high=0;// compute upper boundfor(inti=0;i<n;i++){for(intj=0;j<m;j++){if(i+1<n)high=Math.max(high,Math.abs(mat[i+1][j]-mat[i][j]));if(j+1<m)high=Math.max(high,Math.abs(mat[i][j+1]-mat[i][j]));}}intans=high;while(low<=high){intmid=(low+high)/2;if(canReach(mid,mat)){ans=mid;high=mid-1;}else{low=mid+1;}}returnans;}//Driver Code Startspublicstaticvoidmain(String[]args){int[][]mat={{7,2,6,5},{3,1,10,8}};System.out.println(minCostPath(mat));}}//Driver Code Ends
Python
# directions: up, down, right, leftdirArr=[[-1,0],[1,0],[0,1],[0,-1]]# DFS to check if destination is# reachable with allowed difference = limitdefdfs(x,y,limit,mat,vis):n=len(mat)m=len(mat[0])ifx==n-1andy==m-1:returnTruevis[x][y]=1fordx,dyindirArr:nx=x+dxny=y+dyif0<=nx<nand0<=ny<mandvis[nx][ny]==0:ifabs(mat[nx][ny]-mat[x][y])<=limit:ifdfs(nx,ny,limit,mat,vis):returnTruereturnFalse# checks if path exists for this limitdefcanReach(limit,mat):n=len(mat)m=len(mat[0])vis=[[0]*mfor_inrange(n)]returndfs(0,0,limit,mat,vis)# binary search on minimum possible maximum differencedefminCostPath(mat):n=len(mat)m=len(mat[0])low,high=0,0# compute upper boundforiinrange(n):forjinrange(m):ifi+1<n:high=max(high,abs(mat[i+1][j]-mat[i][j]))ifj+1<m:high=max(high,abs(mat[i][j+1]-mat[i][j]))ans=highwhilelow<=high:mid=(low+high)//2ifcanReach(mid,mat):ans=midhigh=mid-1else:low=mid+1returnans#Driver Code Startsif__name__=='__main__':mat=[[7,2,6,5],[3,1,10,8]]print(minCostPath(mat))#Driver Code Ends
C#
//Driver Code StartsusingSystem;classGFG{//Driver Code Ends// directions: up, down, right, leftstaticint[,]dirArr={{-1,0},{1,0},{0,1},{0,-1}};// DFS to check if destination is reachable // with allowed difference = limitstaticbooldfs(intx,inty,intlimit,int[,]mat,int[,]vis){intn=mat.GetLength(0);intm=mat.GetLength(1);if(x==n-1&&y==m-1)returntrue;vis[x,y]=1;for(intk=0;k<4;k++){intnx=x+dirArr[k,0];intny=y+dirArr[k,1];if(nx>=0&&nx<n&&ny>=0&&ny<m&&vis[nx,ny]==0){if(Math.Abs(mat[nx,ny]-mat[x,y])<=limit){if(dfs(nx,ny,limit,mat,vis))returntrue;}}}returnfalse;}// checks if path exists for this limitstaticboolcanReach(intlimit,int[,]mat){intn=mat.GetLength(0);intm=mat.GetLength(1);int[,]vis=newint[n,m];returndfs(0,0,limit,mat,vis);}// binary search on minimum possible maximum differencestaticintminCostPath(int[,]mat){intn=mat.GetLength(0);intm=mat.GetLength(1);intlow=0,high=0;// compute upper boundfor(inti=0;i<n;i++){for(intj=0;j<m;j++){if(i+1<n)high=Math.Max(high,Math.Abs(mat[i+1,j]-mat[i,j]));if(j+1<m)high=Math.Max(high,Math.Abs(mat[i,j+1]-mat[i,j]));}}intans=high;while(low<=high){intmid=(low+high)/2;if(canReach(mid,mat)){ans=mid;high=mid-1;}else{low=mid+1;}}returnans;}//Driver Code StartsstaticvoidMain(){int[,]mat={{7,2,6,5},{3,1,10,8}};Console.WriteLine(minCostPath(mat));}}//Driver Code Ends
JavaScript
// directions: up, down, right, leftletdirArr=[[-1,0],[1,0],[0,1],[0,-1]];// DFS to check if destination is// reachable with allowed difference = limitfunctiondfs(x,y,limit,mat,vis){letn=mat.length;letm=mat[0].length;if(x===n-1&&y===m-1)returntrue;vis[x][y]=1;for(letdofdirArr){letnx=x+d[0];letny=y+d[1];if(nx>=0&&nx<n&&ny>=0&&ny<m&&vis[nx][ny]===0){if(Math.abs(mat[nx][ny]-mat[x][y])<=limit){if(dfs(nx,ny,limit,mat,vis))returntrue;}}}returnfalse;}// checks if path exists for this limitfunctioncanReach(limit,mat){letn=mat.length;letm=mat[0].length;letvis=Array.from({length:n},()=>Array(m).fill(0));returndfs(0,0,limit,mat,vis);}// binary search on minimum possible maximum differencefunctionminCostPath(mat){letn=mat.length;letm=mat[0].length;letlow=0,high=0;// compute upper boundfor(leti=0;i<n;i++){for(letj=0;j<m;j++){if(i+1<n)high=Math.max(high,Math.abs(mat[i+1][j]-mat[i][j]));if(j+1<m)high=Math.max(high,Math.abs(mat[i][j+1]-mat[i][j]));}}letans=high;while(low<=high){letmid=Math.floor((low+high)/2);if(canReach(mid,mat)){ans=mid;high=mid-1;}else{low=mid+1;}}returnans;}//Driver Code Starts// Driver Codeletmat=[[7,2,6,5],[3,1,10,8]];console.log(minCostPath(mat));//Driver Code Ends
Output
4
Time complexity: O((n*m) * log(k)), where k is max the values in the matrix, therefore, the maximum possible difference between the values of 2 consecutive cells can be k, hence the maximum cost can be k. And for each cost, we explore the grid, therefore the time complexity of exploring the grid is n*m Auxiliary Space: O(n*m)
[Expected Approach - 1] - Using Dijkstra's Algorithm
We can observe that along any path, the maximum difference so far never decreases—it either increases or stays the same. This property allows us to solve the problem using Dijkstra’s algorithm.
We treat each cell as a node, and edges connect adjacent cells with weights equal to the absolute difference of their values. We maintain a cost matrix where cost[i][j] is the minimum maximum difference needed to reach (i,j).
At each step, we process the cell with the current smallest cost and explore its neighbors. For each neighbor, the new cost is:
If newCost is smaller than the neighbor’s recorded cost, we update it.
When the destination is reached, its cost in the matrix gives the minimum possible maximum difference along any path.
C++
//Driver Code Starts#include<iostream>#include<vector>#include<queue>usingnamespacestd;//Driver Code Ends// Directions: up, down, left, rightintdir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};intminCostPath(vector<vector<int>>&mat){intn=mat.size();intm=mat[0].size();vector<vector<int>>cost(n,vector<int>(m,INT_MAX));cost[0][0]=0;// {current cost, {x, y}}priority_queue<pair<int,pair<int,int>>,vector<pair<int,pair<int,int>>>,greater<>>pq;pq.push({0,{0,0}});while(!pq.empty()){auto[currCost,cell]=pq.top();pq.pop();intx=cell.first,y=cell.second;// Skip if this is an outdated entryif(currCost!=cost[x][y])continue;// Destination reachedif(x==n-1&&y==m-1)returncurrCost;for(autod:dir){intnx=x+d[0],ny=y+d[1];if(nx>=0&&nx<n&&ny>=0&&ny<m){// Maximum difference along this pathintnewCost=max(currCost,abs(mat[nx][ny]-mat[x][y]));// Update if newCost improves the neighborif(newCost<cost[nx][ny]){cost[nx][ny]=newCost;pq.push({newCost,{nx,ny}});}}}}returncost[n-1][m-1];}//Driver Code Startsintmain(){vector<vector<int>>mat={{7,2,6,5},{3,1,10,8}};cout<<minCostPath(mat);}//Driver Code Ends
Java
//Driver Code Startsimportjava.util.PriorityQueue;importjava.util.Comparator;importjava.util.Arrays;classGFG{//Driver Code Ends// Directions: up, down, left, rightstaticint[][]dir={{-1,0},{1,0},{0,-1},{0,1}};staticintminCostPath(int[][]mat){intn=mat.length,m=mat[0].length;int[][]cost=newint[n][m];for(int[]row:cost)Arrays.fill(row,Integer.MAX_VALUE);cost[0][0]=0;// {current cost, x, y}PriorityQueue<int[]>pq=newPriorityQueue<>(Comparator.comparingInt(a->a[0]));pq.add(newint[]{0,0,0});while(!pq.isEmpty()){int[]top=pq.poll();intcurrCost=top[0],x=top[1],y=top[2];// Skip if this is an outdated entryif(currCost!=cost[x][y])continue;// Destination reachedif(x==n-1&&y==m-1)returncurrCost;for(int[]d:dir){intnx=x+d[0],ny=y+d[1];if(nx>=0&&nx<n&&ny>=0&&ny<m){// Maximum difference along this pathintnewCost=Math.max(currCost,Math.abs(mat[nx][ny]-mat[x][y]));// Update if newCost improves the neighborif(newCost<cost[nx][ny]){cost[nx][ny]=newCost;pq.add(newint[]{newCost,nx,ny});}}}}returncost[n-1][m-1];}//Driver Code Startspublicstaticvoidmain(String[]args){int[][]mat={{7,2,6,5},{3,1,10,8}};System.out.println(minCostPath(mat));}}//Driver Code Ends
Python
#Driver Code Startsimportheapq#Driver Code Ends# Directions: up, down, left, rightdir=[(-1,0),(1,0),(0,-1),(0,1)]defminCostPath(mat):n,m=len(mat),len(mat[0])cost=[[float('inf')]*mfor_inrange(n)]cost[0][0]=0# {current cost, x, y}pq=[(0,0,0)]whilepq:currCost,x,y=heapq.heappop(pq)# Skip if this is an outdated entryifcurrCost!=cost[x][y]:continue# Destination reachedifx==n-1andy==m-1:returncurrCostfordx,dyindir:nx,ny=x+dx,y+dyif0<=nx<nand0<=ny<m:# Maximum difference along this pathnewCost=max(currCost,abs(mat[nx][ny]-mat[x][y]))# Update if newCost improves the neighborifnewCost<cost[nx][ny]:cost[nx][ny]=newCostheapq.heappush(pq,(newCost,nx,ny))returncost[n-1][m-1]#Driver Code Startsif__name__=='__main__':mat=[[7,2,6,5],[3,1,10,8]]print(minCostPath(mat))#Driver Code Ends
//Driver Code Starts// Min-heap priority queueclassPriorityQueue{constructor(){this.heap=[];}push(cell){this.heap.push(cell);this._heapifyUp();}pop(){if(this.size()===0)returnnull;consttop=this.heap[0];constlast=this.heap.pop();if(this.size()>0){this.heap[0]=last;this._heapifyDown();}returntop;}size(){returnthis.heap.length;}_heapifyUp(){letidx=this.heap.length-1;while(idx>0){letparent=Math.floor((idx-1)/2);if(this.heap[idx].cost>=this.heap[parent].cost)break;[this.heap[idx],this.heap[parent]]=[this.heap[parent],this.heap[idx]];idx=parent;}}_heapifyDown(){letidx=0;constn=this.heap.length;while(true){letleft=2*idx+1,right=2*idx+2;letsmallest=idx;if(left<n&&this.heap[left].cost<this.heap[smallest].cost)smallest=left;if(right<n&&this.heap[right].cost<this.heap[smallest].cost)smallest=right;if(smallest===idx)break;[this.heap[idx],this.heap[smallest]]=[this.heap[smallest],this.heap[idx]];idx=smallest;}}}//Driver Code Ends// Cell classclassCell{constructor(cost,x,y){this.cost=cost;this.x=x;this.y=y;}}// Directions: up, down, left, rightconstdir=[[-1,0],[1,0],[0,-1],[0,1]];// Dijkstra-based minimum maximum pathfunctionminCostPath(mat){constn=mat.length,m=mat[0].length;constcost=Array.from({length:n},()=>Array(m).fill(Infinity));cost[0][0]=0;// {current cost, x, y}constpq=newPriorityQueue();pq.push(newCell(0,0,0));while(pq.size()){consttop=pq.pop();constcurrCost=top.cost,x=top.x,y=top.y;// Skip if this is an outdated entryif(currCost!==cost[x][y])continue;// Destination reachedif(x===n-1&&y===m-1)returncurrCost;for(constdofdir){constnx=x+d[0],ny=y+d[1];if(nx>=0&&nx<n&&ny>=0&&ny<m){// Maximum difference along this pathconstnewCost=Math.max(currCost,Math.abs(mat[nx][ny]-mat[x][y]));// Update if newCost improves the neighborif(newCost<cost[nx][ny]){cost[nx][ny]=newCost;pq.push(newCell(newCost,nx,ny));}}}}returncost[n-1][m-1];}//Driver Code Starts// Driver codeconstmat=[[7,2,6,5],[3,1,10,8]];console.log(minCostPath(mat));//Driver Code Ends
Output
4
Time complexity: O((n*m) * log (n*m)), as the priority queue may contain n*m elements at max, and the cost of insertion/deletion of each element is log (size of priority queue). Auxiliary Space: O(n*m), the maximum size of priority queue
[Expected Approach - 2] - Using DSU - O((n*m) log(n*m)) Time and O(n*m) Space
We can treat each cell as a node and connect it to its neighbors with edges weighted by the absolute difference of their values. To represent each cell uniquely in DSU, we assign it a number using i*m + j, where i and j are the row and column indices and m is the number of columns.
We start connecting cells using the edges with the smallest differences first. Iteratively, we union the two cells of each edge. The moment the start (0, 0) and destination (n-1, m-1) become connected, the weight of the current edge is the minimum maximum difference along a path.
This works because by connecting edges from smallest to largest, the first time the start and end are connected ensures that the largest difference along the path is minimized, giving the correct answer.
C++
//Driver Code Starts#include<iostream>#include<vector>usingnamespacestd;// DSU classclassDSU{vector<int>parent,rank;public:DSU(intn){parent.resize(n);rank.resize(n,0);for(inti=0;i<n;i++)parent[i]=i;}intfind(intx){if(parent[x]!=x)parent[x]=find(parent[x]);returnparent[x];}voidunite(intx,inty){intpx=find(x),py=find(y);if(px==py)return;if(rank[px]<rank[py])parent[px]=py;elseif(rank[px]>rank[py])parent[py]=px;else{parent[py]=px;rank[px]++;}}boolconnected(intx,inty){returnfind(x)==find(y);}};//Driver Code EndsintminCostPath(vector<vector<int>>&mat){intn=mat.size(),m=mat[0].size();inttotal=n*m;// Store edges: {weight, cell1, cell2}vector<array<int,3>>edges;for(inti=0;i<n;i++){for(intj=0;j<m;j++){intu=i*m+j;// Only right and down neighbors to avoid duplicatesif(i+1<n)edges.push_back({abs(mat[i][j]-mat[i+1][j]),u,(i+1)*m+j});if(j+1<m)edges.push_back({abs(mat[i][j]-mat[i][j+1]),u,i*m+(j+1)});}}// Sort edges by weight (smallest first)sort(edges.begin(),edges.end());DSUdsu(total);// Connect cells using edges in increasing orderfor(auto&e:edges){intw=e[0],u=e[1],v=e[2];dsu.unite(u,v);// Check if start and end are connectedif(dsu.connected(0,total-1))returnw;}// Only occurs if single cellreturn0;}//Driver Code Startsintmain(){vector<vector<int>>mat={{7,2,6,5},{3,1,10,8}};cout<<minCostPath(mat);}//Driver Code Ends
Java
//Driver Code Starts// DSU classclassDSU{int[]parent,rank;DSU(intn){parent=newint[n];rank=newint[n];for(inti=0;i<n;i++)parent[i]=i;}intfind(intx){if(parent[x]!=x)parent[x]=find(parent[x]);returnparent[x];}voidunite(intx,inty){intpx=find(x),py=find(y);if(px==py)return;if(rank[px]<rank[py])parent[px]=py;elseif(rank[px]>rank[py])parent[py]=px;else{parent[py]=px;rank[px]++;}}booleanconnected(intx,inty){returnfind(x)==find(y);}}classGFG{//Driver Code EndsstaticintminCostPath(int[][]mat){intn=mat.length,m=mat[0].length,total=n*m;java.util.ArrayList<int[]>edges=newjava.util.ArrayList<>();// Store edges: {weight, cell1, cell2}for(inti=0;i<n;i++){for(intj=0;j<m;j++){intu=i*m+j;// Only right and down neighborsif(i+1<n)edges.add(newint[]{Math.abs(mat[i][j]-mat[i+1][j]),u,(i+1)*m+j});if(j+1<m)edges.add(newint[]{Math.abs(mat[i][j]-mat[i][j+1]),u,i*m+j+1});}}// Sort edges by weightedges.sort((a,b)->a[0]-b[0]);DSUdsu=newDSU(total);// Connect cells using edges in increasing orderfor(int[]e:edges){intw=e[0],u=e[1],v=e[2];dsu.unite(u,v);// Check if start and end are connectedif(dsu.connected(0,total-1))returnw;}// Single cell casereturn0;}//Driver Code Startspublicstaticvoidmain(String[]args){int[][]mat={{7,2,6,5},{3,1,10,8}};System.out.println(minCostPath(mat));}}//Driver Code Ends
Python
#Driver Code Starts# DSU classclassDSU:def__init__(self,n):self.parent=list(range(n))self.rank=[0]*ndeffind(self,x):ifself.parent[x]!=x:self.parent[x]=self.find(self.parent[x])returnself.parent[x]defunite(self,x,y):px,py=self.find(x),self.find(y)ifpx==py:returnifself.rank[px]<self.rank[py]:self.parent[px]=pyelifself.rank[px]>self.rank[py]:self.parent[py]=pxelse:self.parent[py]=pxself.rank[px]+=1defconnected(self,x,y):returnself.find(x)==self.find(y)#Driver Code EndsdefminCostPath(mat):n,m=len(mat),len(mat[0])total=n*m# Store edges: (weight, cell1, cell2)edges=[]foriinrange(n):forjinrange(m):u=i*m+j# Only right and down neighborsifi+1<n:edges.append([abs(mat[i][j]-mat[i+1][j]),u,(i+1)*m+j])ifj+1<m:edges.append([abs(mat[i][j]-mat[i][j+1]),u,i*m+j+1])# Sort edges by weightedges.sort()dsu=DSU(total)# Connect cells using edges in increasing orderforw,u,vinedges:dsu.unite(u,v)# Check if start and end are connectedifdsu.connected(0,total-1):returnw# Single cell casereturn0#Driver Code Startsif__name__=='__main__':mat=[[7,2,6,5],[3,1,10,8]]print(minCostPath(mat))#Driver Code Ends
C#
//Driver Code StartsusingSystem;usingSystem.Collections.Generic;classDSU{int[]parent,rank;publicDSU(intn){parent=newint[n];rank=newint[n];for(inti=0;i<n;i++)parent[i]=i;}publicintfind(intx){if(parent[x]!=x)parent[x]=find(parent[x]);returnparent[x];}publicvoidunite(intx,inty){intpx=find(x),py=find(y);if(px==py)return;if(rank[px]<rank[py])parent[px]=py;elseif(rank[px]>rank[py])parent[py]=px;else{parent[py]=px;rank[px]++;}}publicboolconnected(intx,inty){returnfind(x)==find(y);}}classGFG{//Driver Code EndsstaticintminCostPath(int[,]mat){intn=mat.GetLength(0),m=mat.GetLength(1),total=n*m;// Store edges: {weight, cell1, cell2}List<int[]>edges=newList<int[]>();for(inti=0;i<n;i++){for(intj=0;j<m;j++){intu=i*m+j;if(i+1<n)edges.Add(newint[]{Math.Abs(mat[i,j]-mat[i+1,j]),u,(i+1)*m+j});if(j+1<m)edges.Add(newint[]{Math.Abs(mat[i,j]-mat[i,j+1]),u,i*m+j+1});}}// Sort edges by weightedges.Sort((a,b)=>a[0]-b[0]);DSUdsu=newDSU(total);// Connect cells using edges in increasing orderforeach(vareinedges){intw=e[0],u=e[1],v=e[2];dsu.unite(u,v);// Check if start and end are connectedif(dsu.connected(0,total-1))returnw;}// Single cell casereturn0;}//Driver Code StartsstaticvoidMain(){int[,]mat={{7,2,6,5},{3,1,10,8}};Console.WriteLine(minCostPath(mat));}}//Driver Code Ends
JavaScript
//Driver Code Starts// DSU classclassDSU{constructor(n){this.parent=Array.from({length:n},(_,i)=>i);this.rank=Array(n).fill(0);}find(x){if(this.parent[x]!=x)this.parent[x]=this.find(this.parent[x]);returnthis.parent[x];}unite(x,y){letpx=this.find(x),py=this.find(y);if(px===py)return;if(this.rank[px]<this.rank[py])this.parent[px]=py;elseif(this.rank[px]>this.rank[py])this.parent[py]=px;else{this.parent[py]=px;this.rank[px]++;}}connected(x,y){returnthis.find(x)===this.find(y);}}//Driver Code EndsfunctionminCostPath(mat){constn=mat.length,m=mat[0].length,total=n*m;constedges=[];// Store edges: [weight, cell1, cell2]for(leti=0;i<n;i++){for(letj=0;j<m;j++){letu=i*m+j;if(i+1<n)edges.push([Math.abs(mat[i][j]-mat[i+1][j]),u,(i+1)*m+j]);if(j+1<m)edges.push([Math.abs(mat[i][j]-mat[i][j+1]),u,i*m+j+1]);}}// Sort edges by weightedges.sort((a,b)=>a[0]-b[0]);constdsu=newDSU(total);// Connect cells using edges in increasing orderfor(consteofedges){const[w,u,v]=e;dsu.unite(u,v);// Check if start and end are connectedif(dsu.connected(0,total-1))returnw;}// Single cell casereturn0;}//Driver Code Starts// Driver Codeconstmat=[[7,2,6,5],[3,1,10,8]];console.log(minCostPath(mat));//Driver Code Ends