Given an m x n integers matrix, return the length of the longest increasing path inmatrix.
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).
We want to find the longest increasing path starting from every cell. To avoid recalculating results for the same cell, we store the answer for each cell after computing it once. This way, if another path reaches the same cell, we can reuse the result instantly. For example, if we’ve already found the longest path from (2,1), we don’t need to recompute it when another path passes through.
classSolution {
public:int longestIncreasingPath(vector<vector<int>>& matrix) {
int m = matrix.size(), n = matrix[0].size(), ans =0;
vector<vector<int>> cache(m, vector<int>(n));
vector<pair<int, int>> dirs = {{1,0},{-1,0},{0,1},{0,-1}};
function<int(int,int)> dfs = [&](int i, int j) {
if (cache[i][j]) return cache[i][j];
int res =1;
for (auto& d : dirs) {
int x = i + d.first, y = j + d.second;
if (x >=0&& x < m && y >=0&& y < n && matrix[x][y] > matrix[i][j]) {
res = max(res, 1+ dfs(x, y));
}
}
return cache[i][j] = res;
};
for (int i =0; i < m; ++i)
for (int j =0; j < n; ++j)
ans = max(ans, dfs(i, j));
return ans;
}
};
classSolution {
privatestaticfinalint[][] dirs = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
publicintlongestIncreasingPath(int[][] matrix) {
int m = matrix.length, n = matrix[0].length, ans = 0;
int[][] cache =newint[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
ans = Math.max(ans, dfs(matrix, i, j, cache));
}
}
return ans;
}
privateintdfs(int[][] matrix, int i, int j, int[][] cache) {
if (cache[i][j]!= 0) return cache[i][j];
int m = matrix.length, n = matrix[0].length, res = 1;
for (int[] d : dirs) {
int x = i + d[0], y = j + d[1];
if (x >= 0 && x < m && y >= 0 && y < n && matrix[x][y]> matrix[i][j]) {
res = Math.max(res, 1 + dfs(matrix, x, y, cache));
}
}
return cache[i][j]= res;
}
}
classSolution {
privateval dirs = arrayOf(intArrayOf(1,0), intArrayOf(-1,0), intArrayOf(0,1), intArrayOf(0,-1))
funlongestIncreasingPath(matrix: Array<IntArray>): Int {
val m = matrix.size
val n = matrix[0].size
val cache = Array(m) { IntArray(n) }
var ans = 0fundfs(i: Int, j: Int): Int {
if (cache[i][j] !=0) return cache[i][j]
var res = 1for (d in dirs) {
val x = i + d[0]
val y = j + d[1]
if (x in0 until m && y in0 until n && matrix[x][y] > matrix[i][j]) {
res = maxOf(res, 1 + dfs(x, y))
}
}
cache[i][j] = res
return res
}
for (i in0 until m) for (j in0 until n) ans = maxOf(ans, dfs(i, j))
return ans
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
classSolution:
deflongestIncreasingPath(self, matrix: list[list[int]]) -> int:
m, n = len(matrix), len(matrix[0])
cache: list[list[int]] = [[0]*n for _ in range(m)]
dirs = [(1,0),(-1,0),(0,1),(0,-1)]
defdfs(i: int, j: int) -> int:
if cache[i][j]: return cache[i][j]
res =1for dx, dy in dirs:
x, y = i+dx, j+dy
if0<=x<m and0<=y<n and matrix[x][y] > matrix[i][j]:
res = max(res, 1+dfs(x, y))
cache[i][j] = res
return res
return max(dfs(i, j) for i in range(m) for j in range(n))
impl Solution {
pubfnlongest_increasing_path(matrix: Vec<Vec<i32>>) -> i32 {
let m = matrix.len();
let n = matrix[0].len();
letmut cache =vec![vec![0; n]; m];
let dirs = [(1,0),(-1,0),(0,1),(0,-1)];
fndfs(i: usize, j: usize, m: usize, n: usize, matrix: &Vec<Vec<i32>>, cache: &mut Vec<Vec<i32>>, dirs: &[(i32,i32);4]) -> i32 {
if cache[i][j] !=0 { return cache[i][j]; }
letmut res =1;
for&(dx, dy) in dirs {
let x = i asi32+ dx;
let y = j asi32+ dy;
if x>=0&& x<m asi32&& y>=0&& y<n asi32&& matrix[x asusize][y asusize] > matrix[i][j] {
res = res.max(1+ dfs(x asusize, y asusize, m, n, matrix, cache, dirs));
}
}
cache[i][j] = res;
res
}
letmut ans =0;
for i in0..m {
for j in0..n {
ans = ans.max(dfs(i, j, m, n, &matrix, &mut cache, &dirs));
}
}
ans
}
}
Instead of searching from every cell, we process cells in decreasing order of their values. By always updating from higher to lower, we ensure that when we process a cell, all possible longer paths from its neighbors have already been computed. This is similar to topological sorting, but we use a max-heap (priority queue) to always pick the largest unprocessed cell.
#include<vector>#include<queue>usingnamespace std;
classSolution {
public:int longestIncreasingPath(vector<vector<int>>& matrix) {
int m = matrix.size(), n = matrix[0].size(), ans =0;
vector<vector<int>> dp(m, vector<int>(n, 1));
auto cmp = [&](const pair<int,int>& a, const pair<int,int>& b) {
return matrix[a.first][a.second] < matrix[b.first][b.second];
};
priority_queue<pair<int,int>, vector<pair<int,int>>, decltype(cmp)> pq(cmp);
for (int i =0; i < m; ++i)
for (int j =0; j < n; ++j)
pq.emplace(i, j);
vector<pair<int,int>> dirs = {{1,0},{-1,0},{0,1},{0,-1}};
while (!pq.empty()) {
auto [i, j] = pq.top(); pq.pop();
for (auto& d : dirs) {
int x = i + d.first, y = j + d.second;
if (x >=0&& x < m && y >=0&& y < n && matrix[x][y] < matrix[i][j]) {
dp[x][y] = max(dp[x][y], dp[i][j] +1);
}
}
ans = max(ans, dp[i][j]);
}
return ans;
}
};
import java.util.PriorityQueue
classSolution {
privateval dirs = arrayOf(intArrayOf(1,0), intArrayOf(-1,0), intArrayOf(0,1), intArrayOf(0,-1))
funlongestIncreasingPath(matrix: Array<IntArray>): Int {
val m = matrix.size
val n = matrix[0].size
val dp = Array(m) { IntArray(n) { 1 } }
val pq = PriorityQueue<Pair<Int,Int>>(compareByDescending { (i,j) -> matrix[i][j] })
for (i in0 until m) for (j in0 until n) pq.add(i to j)
var ans = 0while (pq.isNotEmpty()) {
val(i, j) = pq.poll()
for (d in dirs) {
val x = i + d[0]
val y = j + d[1]
if (x in0 until m && y in0 until n && matrix[x][y] < matrix[i][j]) {
dp[x][y] = maxOf(dp[x][y], dp[i][j]+1)
}
}
ans = maxOf(ans, dp[i][j])
}
return ans
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import heapq
classSolution:
deflongestIncreasingPath(self, matrix: list[list[int]]) -> int:
m, n = len(matrix), len(matrix[0])
dp = [[1]*n for _ in range(m)]
heap = [(-matrix[i][j], i, j) for i in range(m) for j in range(n)]
heapq.heapify(heap)
dirs = [(1,0),(-1,0),(0,1),(0,-1)]
ans =0while heap:
val, i, j = heapq.heappop(heap)
for dx, dy in dirs:
x, y = i+dx, j+dy
if0<=x<m and0<=y<n and matrix[x][y] < matrix[i][j]:
dp[x][y] = max(dp[x][y], dp[i][j]+1)
ans = max(ans, dp[i][j])
return ans
use std::collections::BinaryHeap;
impl Solution {
pubfnlongest_increasing_path(matrix: Vec<Vec<i32>>) -> i32 {
let m = matrix.len();
let n = matrix[0].len();
letmut dp =vec![vec![1; n]; m];
letmut heap = BinaryHeap::new();
for i in0..m { for j in0..n { heap.push((matrix[i][j], i, j)); } }
let dirs = [(1,0),(-1,0),(0,1),(0,-1)];
letmut ans =0;
whilelet Some((val, i, j)) = heap.pop() {
for (dx, dy) in dirs.iter() {
let x = i asi32+ dx;
let y = j asi32+ dy;
if x>=0&& x<m asi32&& y>=0&& y<n asi32&& matrix[x asusize][y asusize] < val {
let (x, y) = (x asusize, y asusize);
if dp[x][y] < dp[i][j]+1 {
dp[x][y] = dp[i][j]+1;
}
}
}
if dp[i][j] > ans { ans = dp[i][j]; }
}
ans
}
}