The problem
Given an m x n integer 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.lengthn == matrix[i].length1 <= m, n <= 2000 <= matrix[i][j] <= 2^31 - 1
Explanation
I assume that you have read the description of the problem; if not, please do so and come back. Let’s look at the first example. You can see that:
-
we can start creating a path from any position
-
we must include only unique values — duplicates are not allowed
-
the next value must be greater than the previous one (I know that it is obvious, but I will leave it here because sometimes I am so focused on solving the problem that I miss key details)
-
we are allowed to move only in four directions (top, left, right, bottom); we are not allowed to move diagonally or out of bounds
Dynamic Programming (Top-Down) Solution
Explanation
When we are solving path problems, we can use the DFS algorithm to walk in different directions.
To solve this problem efficiently, we are going to create a grid with matrix dimensions where we will store our result.
If we start from the top-left corner with value 9:
- We can’t go to the top or to the left because those cells are out of bounds.
- If we try to go right, we find that the values in both cells are equal
9 == 9, therefore we are not allowed to increase the path. - If we try to go down, we find that the value below
6is less than the current value9, therefore we can’t increase our path, and as a result, we would put one in our result grid.
If we start from the cell at position (0, 1) with value 9, we can’t go in any of the four directions because:
- If we try to go up, we would be out of bounds.
- If we try to go left, the values would be equal
9 == 9. - If we try to go right, the value would be less than the current value
4 < 9; the same goes for the bottom value. As a result, we would put one in our grid.
If we start from the next cell (0, 2) with value 4:
- We are allowed to go left as
9 > 4, and we are allowed to go down for the same reason8 > 4. - Next, we are going to try to find the longest path from positions with greater values, and as a result, we are going to put a maximum value of two in our grid.
We are going to continue executing the algorithm until we have visited every cell, and as a result, we are going to find and return the maximum value from our grid.
func longestIncreasingPath(_ matrix: [[Int]]) -> Int {
let rows = matrix.count
let cols = matrix[0].count
struct Key: Hashable {
let r: Int
let c: Int
}
var cache: [Key: Int] = [:]
func dfs(_ r: Int, _ c: Int, _ prevVal: Int) -> Int {
if (r < 0 || r == rows ||
c < 0 || c == cols ||
matrix[r][c] <= prevVal
) {
return 0
}
if let cached = cache[Key(r: r, c: c)] {
return cached
}
var res = 1
res = max(res, 1 + dfs(r + 1, c, matrix[r][c]))
res = max(res, 1 + dfs(r - 1, c, matrix[r][c]))
res = max(res, 1 + dfs(r , c + 1, matrix[r][c]))
res = max(res, 1 + dfs(r , c - 1, matrix[r][c]))
cache[Key(r: r, c: c)] = res
return res
}
var res = 0
for r in 0 ..< rows {
for c in 0 ..< cols {
res = max(res, dfs(r, c, -1))
}
}
return res
}
Time/ Space complexity
- Time complexity: O(m*n)
- Space complexity: O(m*n)