Day9: GG高频面经 | L329. 矩阵中的最长递增路径 |记忆化递归,动态规划,哈希表,数组| sundri

329. 矩阵中的最长递增路径 (关键词:最长)

难度困难726

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

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

示例 1:

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

示例 2:

输入: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/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值