Given an m x n
integers matrix
, return the length of the longest increasing path in matrix
.
From each cell, you can either move in four directions: left, right, up, or down. You may not move diagonally or move outside the boundary (i.e., wrap-around is not allowed).
Example 1:
Input: matrix = [[9,9,4],[6,6,8],[2,1,1]]
Output: 4
Explanation: The longest increasing path is [1, 2, 6, 9]
.
Example 2:
Input: matrix = [[3,4,5],[3,2,6],[2,2,1]]
Output: 4
Explanation: The longest increasing path is [3, 4, 5, 6]
. Moving diagonally is not allowed.
Example 3:
Input: matrix = [[1]] Output: 1
Constraints:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 200
0 <= matrix[i][j] <= 231 - 1
This problem asks for the length of the longest increasing path in a given matrix. We can traverse the matrix and find the longest path starting from each cell. A depth-first search (DFS) with memoization is an efficient approach.
Approach:
The core idea is to use a recursive DFS function to explore paths starting from each cell. The function dfs(i, j)
returns the length of the longest increasing path starting from cell (i, j)
.
Memoization: A 2D array f
is used to store the length of the longest path starting from each cell. This prevents redundant computations, significantly improving efficiency. f[i][j] = 0
initially indicates the cell hasn't been visited yet.
Base Case: If f[i][j]
is not 0, it means the longest path from this cell has already been calculated; we return the stored value.
Recursive Step: For each cell (i, j)
, we explore its four neighbors (up, down, left, right). If a neighbor has a larger value than the current cell, we recursively call dfs
on that neighbor.
Update Memoization: The maximum length among all neighbors is updated in f[i][j]
. We add 1 to account for the current cell itself.
Final Result: The function iterates through all cells in the matrix, calling dfs
on each one and keeping track of the maximum path length found.
Time and Space Complexity:
Time Complexity: O(M * N), where M and N are the dimensions of the matrix. Each cell is visited at most once due to memoization. The DFS exploration from each cell takes at most O(MN) in the worst case (although this is highly unlikely and memoization makes it much smaller in practice), but overall this is dominated by the O(MN) iterations.
Space Complexity: O(M * N) to store the memoization array f
and the implicit space used by the recursion stack during DFS.
Code Implementation (Python):
from functools import cache
class Solution:
def longestIncreasingPath(self, matrix: List[List[int]]) -> int:
m, n = len(matrix), len(matrix[0])
@cache
def dfs(i, j):
max_path = 1
for x, y in [(i-1, j), (i+1, j), (i, j-1), (i, j+1)]:
if 0 <= x < m and 0 <= y < n and matrix[x][y] > matrix[i][j]:
max_path = max(max_path, 1 + dfs(x, y))
return max_path
max_len = 0
for i in range(m):
for j in range(n):
max_len = max(max_len, dfs(i,j))
return max_len
The other language implementations (Java, C++, Go, TypeScript) follow the same logic and algorithmic structure, only differing in syntax and data structure handling specific to each language. The core DFS with memoization remains consistent across all solutions.