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.
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.
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.