329. 矩阵中的最长递增路径 (关键词:最长)
难度困难726
给定一个 m x n 整数矩阵 matrix ,找出其中 最长递增路径 的长度。
对于每个单元格,你可以往上,下,左,右四个方向移动。 你 不能 在 对角线 方向上移动或移动到 边界外(即不允许环绕)。
示例 1:
![](https://i-blog.csdnimg.cn/blog_migrate/9ee5cd3ba564e13d43080371dceaf007.jpeg)
输入:matrix = [[9,9,4],[6,6,8],[2,1,1]]
输出:4
解释:最长递增路径为 [1, 2, 6, 9]。
示例 2:
![](https://i-blog.csdnimg.cn/blog_migrate/ca21394bfd62b2157e1f603f32bf91e9.jpeg)
输入:matrix = [[3,4,5],[3,2,6],[2,2,1]]
输出:4
解释:最长递增路径是 [3, 4, 5, 6]。注意不允许在对角线方向上移动。
示例 3:
输入:matrix = [[1]]
输出:1
提示:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 200
0 <= matrix[i][j] <= 231 - 1
#解题思路:
这个题目肯定要遍历grid里面的所有点。对于每个点而言,要单独对这个点进行dfs,看这个点所在的位置能够达到的最长路径是多少。
那么假如这个点是最大值,例如说9,对于9而言,它的最长路径是多少呢?因为9不能到达任何位置,所以它的最长路径就是它本身,即为1。这个就是我们的base case,即没有任何点能够触达,那么这个点的最长路径就是1。
那么如何存储每个点的最长路径呢?提供以下两种思路:
1.哈希表 (key:点坐标 value:最长路径)
2.数组 m * n 的dp数组,每个坐标初始化为1
#思路一:使用字典作为memo,记忆化递归
遍历grid上面的所有点,分别对每个点进行dfs
dfs的返回值应该是当前点能够到达的最长路径
dfs的传入参数是 matrix 以及 当前的 点坐标 r 和 c
dfs的返回条件:1. 当坐标已经存在于字典内时,直接返回对应的value 2. 如果不存在,让这个坐标对应的值为1
dfs的递归写法:遍历dir数组,求出代表了四个方向的坐标 (new_x, new_y):1.新坐标必须在board里面同时 2. 新坐标对应的值必须大于当前坐标对应的值: 满足以上两个条件之后,就是我们最关键,最核心的代码:
最后一行,返回取完最大值之后的 self.memo[(x,y)]
self.memo[(x,y)] = max( self.memo[(x,y)], 1+ self.dfs(matrix, new_x, new_y ))
class Solution(object):
def longestIncreasingPath(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: int
"""
# 创建一个 memo - 可以是 array,可以是 dic,用于记录每个点的最长递增长度
# 遍历每一个点,对每个点进行dfs,传入参数(矩阵,该点坐标)
# 遍历dir,产生四个方向的新坐标
# 对这个新坐标进行判断:如果坐标已经有值,直接返回这个值 -- 这个是最难理解的部分
# 如果坐标在界内,才继续对下一个坐标进行探索
self.memo = {}
self.dir = [(0,1),(0,-1),(1,0),(-1,0)]
m = len(matrix)
n = len(matrix[0])
res = float('-inf')
for i in range(m):
for j in range(n):
res = max(res, self.dfs(matrix, i, j)) # res 写错了,写成了 min ... 想四
return res
def dfs(self, matrix, x, y):
if (x,y) in self.memo: return self.memo[(x,y)]
if (x,y) not in self.memo: self.memo[(x,y)] = 1
for dx, dy in self.dir:
new_x, new_y = x + dx, y + dy
if 0 <= new_x < len(matrix) and 0 <= new_y < len(matrix[0]) and matrix[x][y] < matrix[new_x][new_y]:
self.memo[(x,y)] = max( self.memo[(x,y)], 1+ self.dfs(matrix, new_x, new_y ))
return self.memo[(x,y)]
#思路二:使用数组作为memo,记忆化递归
class Solution:
def longestIncreasingPath(self, matrix) :
# try to calculate the longest path for each point and add it up
# can use a dp array to store the value
m = len(matrix)
n = len(matrix[0])
dp = [[1 for _ in range(n)] for _ in range(m)]
# print(dp)
def dfs(r,c,prev_val):
if r < 0 or c < 0 or r >= len(matrix) or c >= len(matrix[0]) or matrix[r][c] <= prev_val:
return 0
if dp[r][c] != 1: # if it is already visited, return this value
return dp[r][c] # where do you initialize the res?
dp[r][c] = max(dp[r][c], dfs(r+1,c,matrix[r][c]) + 1)
dp[r][c] = max(dp[r][c], dfs(r-1,c,matrix[r][c]) + 1)
dp[r][c] = max(dp[r][c], dfs(r,c+1,matrix[r][c]) + 1)
dp[r][c] = max(dp[r][c], dfs(r,c-1,matrix[r][c]) + 1)
return dp[r][c]
res = float('-inf')
for i in range(m):
for j in range(n):
res = max (res, dfs(i,j,-1)) # prev_val set as -1
return res
#时空复杂度
时间复杂度:O(mn),其中 m 和 n 分别是矩阵的行数和列数。深度优先搜索的时间复杂度是 O(V+E),其中 V 是节点数,E 是边数。
空间复杂度:O(mn),其中 m 和 n 分别是矩阵的行数和列数。空间复杂度主要取决于缓存和递归调用深度,缓存的空间复杂度是 O(mn),递归调用深度不会超过 mn。
#复习感受
之前做过的题目满满的能够串联起来了,
google之前还考过一个lc1048, 其中的核心代码和这个题很像!
https://leetcode.com/problems/longest-string-chain/description/