Txing

欢迎来到 | 伽蓝之堂

0%

Q329-矩阵中的最长递增路径-困难-深度优先搜索

329. 矩阵中的最长递增路径

Question

给定一个 m x n 整数矩阵 matrix ,找出其中 最长递增路径 的长度。

对于每个单元格,你可以往上,下,左,右四个方向移动。 你 不能 在 对角线 方向上移动或移动到 边界外(即不允许环绕)。

Example 1:

输入:matrix = [[9,9,4],[6,6,8],[2,1,1]] 输出:4 解释:最长递增路径为 [1, 2, 6, 9]。

Note:

  • m == matrix.length
  • n == matrix[i].length
  • 1 <= m, n <= 200
  • 0 <= <= 231 - 1

Approach 1: 记忆化深度优先搜索

将矩阵看成一个有向图,每个单元格对应图中的一个节点,如果相邻的两个单元格的值不相等,则在相邻的两个单元格之间存在一条从较小值指向较大值的有向边。问题转化成在有向图中寻找最长路径。

深度优先搜索是非常直观的方法。从一个单元格开始进行深度优先搜索,即可找到从该单元格开始的最长递增路径。对每个单元格分别进行深度优先搜索之后,即可得到矩阵中的最长递增路径的长度。

但是如果使用朴素深度优先搜索,时间复杂度是指数级,会超出时间限制,因此必须加以优化。

朴素深度优先搜索的时间复杂度过高的原因是进行了大量的重复计算,同一个单元格会被访问多次,每次访问都要重新计算。由于同一个单元格对应的最长递增路径的长度是固定不变的,因此可以使用记忆化的方法进行优化。用矩阵 作为缓存矩阵,已经计算过的单元格的结果存储到缓存矩阵中。

使用记忆化深度优先搜索,当访问到一个单元格 时,如果 ,说明该单元格的结果已经计算过,则直接从缓存中读取结果,如果 ,说明该单元格的结果尚未被计算过,则进行搜索,并将计算得到的结果存入缓存中。

遍历完矩阵中的所有单元格之后,即可得到矩阵中的最长递增路径的长度。

python中使用@lru_cache(None)可以缓存之前的计算结果,避免重复计算,提高计算效率(参考:https://www.cnblogs.com/sfencs-hcy/p/10171457.html)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution:

DIRS = [(-1, 0), (1, 0), (0, -1), (0, 1)]

def longestIncreasingPath(self, matrix: List[List[int]]) -> int:
if not matrix:
return 0

@lru_cache(None)
def dfs(row: int, column: int) -> int:
best = 1
for dx, dy in Solution.DIRS:
newRow, newColumn = row + dx, column + dy
if 0 <= newRow < rows and 0 <= newColumn < columns and matrix[newRow][newColumn] > matrix[row][column]:
best = max(best, dfs(newRow, newColumn) + 1)
return best

ans = 0
rows, columns = len(matrix), len(matrix[0])
for i in range(rows):
for j in range(columns):
ans = max(ans, dfs(i, j))
return ans

复杂度分析

  • 时间复杂度:,其中 m 和 n 分别是矩阵的行数和列数。深度优先搜索的时间复杂度是 ,其中 V 是节点数,E 是边数。在矩阵中,
  • 空间复杂度:,其中 m 和 n 分别是矩阵的行数和列数。空间复杂度主要取决于缓存和递归调用深度,缓存的空间复杂度是 ,递归调用深度不会超过 mn。