Given a matrix with n rows and m columns. The task is to find the length of the longest increasing path in the matrix, here increasing path means that the value in the specified path increases. For example, if a path of length k has values a1, a2, a3, .... ak, then for every i from [2,k] this condition must hold ai > ai-1. No cell should be revisited in the path.
From each cell, we can either move in four directions: left, right, up, or down. We are not allowed to move diagonally or move outside the boundary.
Examples:
Input: matrix[][] = [[1 2 3], [4 5 6], [7 8 9]] Output: 5 Explanation: One such path is 1 → 2 → 3 → 6 → 9, where each number is strictly greater than the previous and movement is allowed in four directions (up, down, left, right).
Input: matrix[][] = [[3 4 5], [6 2 6], [2 2 1]] Output: 4 Explanation: The longest increasing path is 3→4→5 →6, where each number is strictly greater than the previous and movement is allowed in four directions (up, down, left, right).
[Naive Approach] Using Recursion - O(4^(m*n)) Time and O(m*n) Space
The idea is to recursively check the longest paths from each cell. For each cell, initialize the answer to 1. Recursively process all the four directions (first check if the cells are valid and then check that their value is greater than current cell value) and set answer to the maximum of the four directions. Return the calculated answer.
C++
// Recursive c++ program to find// longest incresing path in matrix#include<bits/stdc++.h>usingnamespacestd;// Function which checks if the cell is valid// and its value is greater than previous cell.boolvalidCell(inti,intj,vector<vector<int>>&matrix,intn,intm,intprev){if(i>=0&&i<n&&j>=0&&j<m&&matrix[i][j]>prev)returntrue;returnfalse;}intpathRecur(inti,intj,vector<vector<int>>&matrix,intn,intm){// include current cell in answerintans=1;// direction vector to move in 4 directionsvector<vector<int>>dir={{1,0},{-1,0},{0,1},{0,-1}};for(autod:dir){intx=i+d[0],y=j+d[1];if(validCell(x,y,matrix,n,m,matrix[i][j])){ans=max(ans,1+pathRecur(x,y,matrix,n,m));}}returnans;}intlongIncPath(vector<vector<int>>&matrix){intn=matrix.size();intm=matrix[0].size();intans=0;// Check longest increasing path// for each cell.for(inti=0;i<n;i++){for(intj=0;j<m;j++){ans=max(ans,pathRecur(i,j,matrix,n,m));}}returnans;}intmain(){vector<vector<int>>matrix={{1,2,3},{4,5,6},{7,8,9}};cout<<longIncPath(matrix)<<endl;return0;}
Java
// Java program to find// longest increasing path in matriximportjava.util.*;classGfG{// Function which checks if the cell is valid// and its value is greater than previous cell.staticbooleanvalidCell(inti,intj,int[][]matrix,intn,intm,intprev){return(i>=0&&i<n&&j>=0&&j<m&&matrix[i][j]>prev);}staticintpathRecur(inti,intj,int[][]matrix,intn,intm){// include current cell in answerintans=1;// direction vectors to move in 4 directionsint[][]dir={{1,0},{-1,0},{0,1},{0,-1}};for(int[]d:dir){intx=i+d[0],y=j+d[1];// Check if the cell is validif(validCell(x,y,matrix,n,m,matrix[i][j])){ans=Math.max(ans,1+pathRecur(x,y,matrix,n,m));}}returnans;}staticintlongIncPath(int[][]matrix){intans=0;intn=matrix.length;intm=matrix[0].length;// Check longest increasing path// for each cell.for(inti=0;i<n;i++){for(intj=0;j<m;j++){ans=Math.max(ans,pathRecur(i,j,matrix,n,m));}}returnans;}publicstaticvoidmain(String[]args){int[][]matrix={{1,2,3},{4,5,6},{7,8,9}};System.out.println(longIncPath(matrix));}}
Python
# Python program to find# longest increasing path in matrixdefvalidCell(i,j,matrix,n,m,prev):returni>=0andi<nandj>=0andj<m \
andmatrix[i][j]>prevdefpathRecur(i,j,matrix,n,m):# include current cell in answerans=1# direction vectors to move in 4 directionsdir=[(1,0),(-1,0),(0,1),(0,-1)]fordindir:x,y=i+d[0],j+d[1]# Check if the cell is validifvalidCell(x,y,matrix,n,m,matrix[i][j]):ans=max(ans,1+pathRecur(x,y,matrix,n,m))returnansdeflongIncPath(matrix):ans=0n=len(matrix)m=len(matrix[0])# Check longest increasing path# for each cell.foriinrange(n):forjinrange(m):ans=max(ans,pathRecur(i,j,matrix,n,m))returnansif__name__=="__main__":matrix=[[1,2,3],[4,5,6],[7,8,9]]print(longIncPath(matrix))
C#
// C# program to find// longest increasing path in matrixusingSystem;classGfG{// Function which checks if the cell is valid// and its value is greater than previous cell.staticboolvalidCell(inti,intj,int[,]matrix,intn,intm,intprev){return(i>=0&&i<n&&j>=0&&j<m&&matrix[i,j]>prev);}staticintpathRecur(inti,intj,int[,]matrix,intn,intm){// include current cell in answerintans=1;// direction vectors to move in 4 directionsint[,]dir={{1,0},{-1,0},{0,1},{0,-1}};for(intd=0;d<4;d++){intx=i+dir[d,0],y=j+dir[d,1];// Check if the cell is validif(validCell(x,y,matrix,n,m,matrix[i,j])){ans=Math.Max(ans,1+pathRecur(x,y,matrix,n,m));}}returnans;}staticintlongIncPath(int[,]matrix){intans=0;intn=matrix.GetLength(0);intm=matrix.GetLength(1);// Check longest increasing path// for each cell.for(inti=0;i<n;i++){for(intj=0;j<m;j++){ans=Math.Max(ans,pathRecur(i,j,matrix,n,m));}}returnans;}staticvoidMain(string[]args){int[,]matrix={{1,2,3},{4,5,6},{7,8,9}};Console.WriteLine(longIncPath(matrix));}}
JavaScript
// JavaScript program to find// longest increasing path in matrixfunctionvalidCell(i,j,matrix,n,m,prev){return(i>=0&&i<n&&j>=0&&j<m&&matrix[i][j]>prev);}functionpathRecur(i,j,matrix,n,m){// include current cell in answerletans=1;// direction vectors to move in// 4 directionsconstdir=[[1,0],[-1,0],[0,1],[0,-1]];for(constdofdir){constx=i+d[0],y=j+d[1];// Check if the cell is validif(validCell(x,y,matrix,n,m,matrix[i][j])){ans=Math.max(ans,1+pathRecur(x,y,matrix,n,m));}}returnans;}functionlongIncPath(matrix){letans=0;letn=matrix.length;letm=matrix[0].length;// Check longest increasing path// for each cell.for(leti=0;i<n;i++){for(letj=0;j<m;j++){ans=Math.max(ans,pathRecur(i,j,matrix,n,m));}}returnans;}constmatrix=[[1,2,3],[4,5,6],[7,8,9]];console.log(longIncPath(matrix));
Output
5
[Expected Approach 1] Using Top-Down DP (Memoization) - O(m*n) Time and O(m*n) Space
The idea is to use Dynamic Programming in the first approach. For a given cell, store its result in the 2D array so that if this cell is again called, we can simply return the value stored in the 2D array.
1. Optimal Substructure: The longest increasing path from a given cell depends on the optimal solutions of its four neighboring cells. By combining these optimal substructures, we can efficiently calculate longest increasing path starting from given cell.
2. Overlapping Subproblems: We can observe that a cell can be a neighbour of multiple cells and multiple calls can be made for it.
There are two parameters: i and j (cell indices) that changes in the recursive solution. So create a 2D array of size n*m (where n is the number of rows and m is the number of columns in the matrix).
Initiate all values in the 2D array as -1 to indicate nothing is computed yet.
Check the longest increasing path for each cell (i, j). If the value in array for given cell is -1, then only make the recursive calls for the neighboring cells and store the result in the array. Otherwise, simply return the value stored in the array.
C++
// c++ program to find// longest incresing path in matrix#include<bits/stdc++.h>usingnamespacestd;// Function which checks if the cell is valid// and its value is greater than previous cell.boolvalidCell(inti,intj,vector<vector<int>>&matrix,intprev){if(i>=0&&i<matrix.size()&&j>=0&&j<matrix[0].size()&&matrix[i][j]>prev)returntrue;returnfalse;}intpathRecur(inti,intj,vector<vector<int>>&matrix,vector<vector<int>>&memo){// If answer exists in memo table.if(memo[i][j]!=-1)returnmemo[i][j];// include current cell in answerintans=1;// direction vector to move in 4 directionsvector<vector<int>>dir={{1,0},{-1,0},{0,1},{0,-1}};for(autod:dir){intx=i+d[0],y=j+d[1];// Check if the cell is validif(validCell(x,y,matrix,matrix[i][j])){ans=max(ans,1+pathRecur(x,y,matrix,memo));}}// Memoize the answer and return it.returnmemo[i][j]=ans;}intlongIncPath(vector<vector<int>>&matrix,intn,intm){intans=0;// Initialize dp tablevector<vector<int>>memo(n,vector<int>(m,-1));// Check longest increasing path// for each cell.for(inti=0;i<n;i++){for(intj=0;j<m;j++){ans=max(ans,pathRecur(i,j,matrix,memo));}}returnans;}intmain(){intn=3,m=3;vector<vector<int>>matrix={{1,2,3},{4,5,6},{7,8,9}};cout<<longIncPath(matrix,n,m)<<endl;return0;}
Java
// Java program to find// longest increasing path in matrixclassGfG{// Function which checks if the cell is valid// and its value is greater than previous cell.staticbooleanvalidCell(inti,intj,int[][]matrix,intprev){return(i>=0&&i<matrix.length&&j>=0&&j<matrix[0].length&&matrix[i][j]>prev);}staticintpathRecur(inti,intj,int[][]matrix,int[][]memo){// If answer exists in memo table.if(memo[i][j]!=-1)returnmemo[i][j];// include current cell in answerintans=1;// direction vector to move in 4 directionsint[][]dir={{1,0},{-1,0},{0,1},{0,-1}};for(int[]d:dir){intx=i+d[0],y=j+d[1];// Check if the cell is validif(validCell(x,y,matrix,matrix[i][j])){ans=Math.max(ans,1+pathRecur(x,y,matrix,memo));}}// Memoize the answer and return it.memo[i][j]=ans;returnans;}staticintlongIncPath(int[][]matrix,intn,intm){intans=0;// Initialize dp tableint[][]memo=newint[n][m];for(inti=0;i<n;i++){for(intj=0;j<m;j++){memo[i][j]=-1;}}// Check longest increasing path// for each cell.for(inti=0;i<n;i++){for(intj=0;j<m;j++){ans=Math.max(ans,pathRecur(i,j,matrix,memo));}}returnans;}publicstaticvoidmain(String[]args){intn=3,m=3;int[][]matrix={{1,2,3},{4,5,6},{7,8,9}};System.out.println(longIncPath(matrix,n,m));}}
Python
# Python program to find# longest increasing path in matrixdefvalidCell(i,j,matrix,prev):returni>=0andi<len(matrix)andj>=0and\
j<len(matrix[0])andmatrix[i][j]>prevdefpathRecur(i,j,matrix,memo):# If answer exists in memo table.ifmemo[i][j]!=-1:returnmemo[i][j]# include current cell in answerans=1# direction vectors to move in# 4 directionsdir=[(1,0),(-1,0),(0,1),(0,-1)]fordindir:x,y=i+d[0],j+d[1]# Check if the cell is validifvalidCell(x,y,matrix,matrix[i][j]):ans=max(ans,1+pathRecur(x,y,matrix,memo))# Memoize the answer and return it.memo[i][j]=ansreturnansdeflongIncPath(matrix,n,m):ans=0# Initialize dp tablememo=[[-1]*mfor_inrange(n)]# Check longest increasing path# for each cell.foriinrange(n):forjinrange(m):ans=max(ans,pathRecur(i,j,matrix,memo))returnansif__name__=="__main__":n,m=3,3matrix=[[1,2,3],[4,5,6],[7,8,9]]print(longIncPath(matrix,n,m))
C#
// C# program to find// longest increasing path in matrixusingSystem;classGfG{// Function which checks if the cell is valid// and its value is greater than previous cell.staticboolvalidCell(inti,intj,int[,]matrix,intprev){return(i>=0&&i<matrix.GetLength(0)&&j>=0&&j<matrix.GetLength(1)&&matrix[i,j]>prev);}staticintpathRecur(inti,intj,int[,]matrix,int[,]memo){// If answer exists in memo table.if(memo[i,j]!=-1)returnmemo[i,j];// include current cell in answerintans=1;// direction vectors to move in 4 directionsint[,]dir={{1,0},{-1,0},{0,1},{0,-1}};for(intd=0;d<4;d++){intx=i+dir[d,0],y=j+dir[d,1];// Check if the cell is validif(validCell(x,y,matrix,matrix[i,j])){ans=Math.Max(ans,1+pathRecur(x,y,matrix,memo));}}// Memoize the answer// and return it.memo[i,j]=ans;returnans;}staticintlongIncPath(int[,]matrix,intn,intm){intans=0;// Initialize dp tableint[,]memo=newint[n,m];for(inti=0;i<n;i++){for(intj=0;j<m;j++){memo[i,j]=-1;}}// Check longest increasing path// for each cell.for(inti=0;i<n;i++){for(intj=0;j<m;j++){ans=Math.Max(ans,pathRecur(i,j,matrix,memo));}}returnans;}staticvoidMain(string[]args){intn=3,m=3;int[,]matrix={{1,2,3},{4,5,6},{7,8,9}};Console.WriteLine(longIncPath(matrix,n,m));}}
JavaScript
// JavaScript program to find// longest increasing path in matrixfunctionvalidCell(i,j,matrix,prev){returni>=0&&i<matrix.length&&j>=0&&j<matrix[0].length&&matrix[i][j]>prev;}functionpathRecur(i,j,matrix,memo){// If answer exists in memo table.if(memo[i][j]!==-1)returnmemo[i][j];// include current cell in answerletans=1;// direction vectors to move in 4 directionsconstdir=[[1,0],[-1,0],[0,1],[0,-1]];for(constdofdir){constx=i+d[0],y=j+d[1];// Check if the cell is validif(validCell(x,y,matrix,matrix[i][j])){ans=Math.max(ans,1+pathRecur(x,y,matrix,memo));}}// Memoize the answer and return it.memo[i][j]=ans;returnans;}functionlongIncPath(matrix,n,m){letans=0;// Initialize dp tableconstmemo=Array.from({length:n},()=>Array(m).fill(-1));// Check longest increasing path// for each cell.for(leti=0;i<n;i++){for(letj=0;j<m;j++){ans=Math.max(ans,pathRecur(i,j,matrix,memo));}}returnans;}constn=3,m=3;constmatrix=[[1,2,3],[4,5,6],[7,8,9]];console.log(longIncPath(matrix,n,m));
Output
5
[Expected Approach 2] Using Kahn's algorithm - O(m*n) Time and O(n*m) Space
Each cell in the matrix is treated as a node, and there's a directed edge from a cell to its neighboring cell if the neighbor has a greater value. The graph formed this way is a directed acyclic graph and this problem reduces to longest path in a directed acyclic graph. We can find the longest path using Topological Sorting. We have used Kahn's algorithm in the below implementation.
To implement Kahn's algorithm, we first compute the in-degree of each cell (i.e., the number of smaller neighbors pointing into it), which helps identify the starting points of increasing paths (cells with in-degree 0). These starting cells are enqueued, and we perform a level-order traversal (BFS), where each level represents one step further in the increasing sequence. For each cell we process, we update the in-degree of its larger neighbors, and if their in-degree becomes 0, we enqueue them as they are ready to be part of the path. The number of BFS levels we process gives us the maximum path length.
C++
// C++ program to find the longest increasing path in a matrix using BFS (Topological Sort)#include<bits/stdc++.h>usingnamespacestd;// Function to find the longest increasing path in a matrixintlongIncPath(vector<vector<int>>&matrix){intn=matrix.size();intm=matrix[0].size();// Direction vectors for moving right, down, left, and upvector<pair<int,int>>dir={{0,1},{1,0},{0,-1},{-1,0}};// Create an in-degree matrix (used to count number// of smaller neighbors for each cell)vector<vector<int>>degree(n+1,vector<int>(m+1,0));// Compute the in-degree for each cellfor(inti=0;i<n;i++){for(intj=0;j<m;j++){for(autoit:dir){intx=i+it.first;inty=j+it.second;// If neighboring cell is within bounds // and has a smaller valueif(x>=0&&x<n&&y>=0&&y<m&&matrix[x][y]<matrix[i][j])degree[i][j]++;// Increase in-degree count}}}// Add all cells with in-degree 0 to the // queue (they are starting points)queue<pair<int,int>>q;for(inti=0;i<n;i++)for(intj=0;j<m;j++)if(degree[i][j]==0)q.push({i,j});intans=0;// This will count the number// of levels processed (i.e., // length of path)// Perform BFS level-by-levelwhile(!q.empty()){ans++;intl=q.size();for(inti=0;i<l;i++){intx1=q.front().first;inty1=q.front().second;q.pop();// Explore all four directionsfor(autoit:dir){intx=x1+it.first;inty=y1+it.second;// If neighboring cell has greater // value (valid increasing move)if(x>=0&&x<n&&y>=0&&y<m&&matrix[x][y]>matrix[x1][y1]){degree[x][y]--;if(degree[x][y]==0){q.push({x,y});}}}}}// Return the total number of BFS levels = length// of the longest increasing pathreturnans;}intmain(){vector<vector<int>>matrix={{1,2,3},{4,5,6},{7,8,9}};cout<<longIncPath(matrix)<<endl;return0;}
Java
importjava.util.*;classGfG{// Function to find the longest increasing path in a matrixstaticintlongIncPath(int[][]matrix){intn=matrix.length;intm=matrix[0].length;// Direction vectors: right, down, left, upint[][]dir={{0,1},{1,0},{0,-1},{-1,0}};// In-degree matrixint[][]degree=newint[n][m];// Compute in-degreesfor(inti=0;i<n;i++){for(intj=0;j<m;j++){for(int[]d:dir){intx=i+d[0];inty=j+d[1];if(x>=0&&x<n&&y>=0&&y<m&&matrix[x][y]<matrix[i][j]){degree[i][j]++;}}}}// Enqueue all 0 in-degree cellsQueue<int[]>q=newLinkedList<>();for(inti=0;i<n;i++){for(intj=0;j<m;j++){if(degree[i][j]==0){q.offer(newint[]{i,j});}}}intans=0;// BFS level-by-levelwhile(!q.isEmpty()){ans++;intsize=q.size();for(inti=0;i<size;i++){int[]cell=q.poll();intx1=cell[0],y1=cell[1];for(int[]d:dir){intx=x1+d[0];inty=y1+d[1];if(x>=0&&x<n&&y>=0&&y<m&&matrix[x][y]>matrix[x1][y1]){degree[x][y]--;if(degree[x][y]==0){q.offer(newint[]{x,y});}}}}}returnans;}publicstaticvoidmain(String[]args){int[][]matrix={{1,2,3},{4,5,6},{7,8,9}};System.out.println(longIncPath(matrix));}}
Python
fromcollectionsimportdeque# Function to find the longest increasing path in a matrixdeflongIncPath(matrix):n=len(matrix)m=len(matrix[0])# Direction vectors: right, down, left, updir=[(0,1),(1,0),(0,-1),(-1,0)]# In-degree matrixdegree=[[0for_inrange(m)]for_inrange(n)]# Compute in-degreesforiinrange(n):forjinrange(m):fordx,dyindir:x,y=i+dx,j+dyif0<=x<nand0<=y<mandmatrix[x][y]<matrix[i][j]:degree[i][j]+=1# Enqueue all 0 in-degree cellsq=deque()foriinrange(n):forjinrange(m):ifdegree[i][j]==0:q.append((i,j))# BFS level-by-levelans=0whileq:ans+=1for_inrange(len(q)):x1,y1=q.popleft()fordx,dyindir:x,y=x1+dx,y1+dyif0<=x<nand0<=y<mandmatrix[x][y]>matrix[x1][y1]:degree[x][y]-=1ifdegree[x][y]==0:q.append((x,y))returnans# Example usageif__name__=="__main__":matrix=[[1,2,3],[4,5,6],[7,8,9]]print(longIncPath(matrix))
C#
usingSystem;usingSystem.Collections.Generic;classGfG{// Function to find the longest increasing path in a matrixstaticintlongIncPath(int[,]matrix){intn=matrix.GetLength(0);intm=matrix.GetLength(1);// Direction vectors: right, down, left, upint[,]dir={{0,1},{1,0},{0,-1},{-1,0}};// In-degree matrixint[,]degree=newint[n,m];// Step 1: Compute in-degreesfor(inti=0;i<n;i++){for(intj=0;j<m;j++){for(intd=0;d<4;d++){intx=i+dir[d,0];inty=j+dir[d,1];if(x>=0&&x<n&&y>=0&&y<m&&matrix[x,y]<matrix[i,j]){degree[i,j]++;}}}}// Step 2: Enqueue all 0 in-degree cellsQueue<(int,int)>q=newQueue<(int,int)>();for(inti=0;i<n;i++){for(intj=0;j<m;j++){if(degree[i,j]==0){q.Enqueue((i,j));}}}intans=0;// Step 3: BFS level-by-levelwhile(q.Count>0){ans++;intsize=q.Count;for(inti=0;i<size;i++){var(x1,y1)=q.Dequeue();for(intd=0;d<4;d++){intx=x1+dir[d,0];inty=y1+dir[d,1];if(x>=0&&x<n&&y>=0&&y<m&&matrix[x,y]>matrix[x1,y1]){degree[x,y]--;if(degree[x,y]==0){q.Enqueue((x,y));}}}}}returnans;}staticvoidMain(){int[,]matrix={{1,2,3},{4,5,6},{7,8,9}};Console.WriteLine(longIncPath(matrix));}}
JavaScript
// Function to find the longest increasing path in a matrixfunctionlongIncPath(matrix){constn=matrix.length;constm=matrix[0].length;// Direction vectors: right, down, left, upconstdir=[[0,1],[1,0],[0,-1],[-1,0]];// In-degree matrixconstdegree=Array.from({length:n},()=>Array(m).fill(0));// Compute in-degreesfor(leti=0;i<n;i++){for(letj=0;j<m;j++){for(const[dx,dy]ofdir){constx=i+dx;consty=j+dy;if(x>=0&&x<n&&y>=0&&y<m&&matrix[x][y]<matrix[i][j]){degree[i][j]++;}}}}// Enqueue all 0 in-degree cellsconstq=[];for(leti=0;i<n;i++){for(letj=0;j<m;j++){if(degree[i][j]===0){q.push([i,j]);}}}// BFS level-by-levelletans=0;while(q.length>0){ans++;constsize=q.length;for(leti=0;i<size;i++){const[x1,y1]=q.shift();for(const[dx,dy]ofdir){constx=x1+dx;consty=y1+dy;if(x>=0&&x<n&&y>=0&&y<m&&matrix[x][y]>matrix[x1][y1]){degree[x][y]--;if(degree[x][y]===0){q.push([x,y]);}}}}}returnans;}// Driver Codeconstmatrix=[[1,2,3],[4,5,6],[7,8,9]];console.log(longIncPath(matrix));