DP专题9 - leetcode329. Longest Increasing Path in a Matrix/322. Coin Change -经典

329. Longest Increasing Path in a Matrix - 记忆化搜索DP

题目描述

给定一个正整数矩阵,找出最长递增路径的长度。
第每个格子,你可以向四个方向移动(上下左右),不能对角线或移出边界。

例子
Example 1:

Input: nums =
[
[9,9,4],
[6,6,8],
[2,1,1]
]
Output: 4

Explanation: The longest increasing path is [1, 2, 6, 9].

Example 2:

Input: nums =
[
[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.

思想
dp[i][j]表示到达(i, j)时的最大长度。
状态方程:有四种状态(a, b)可以到达(i, j),若当前matrix[i][j]比前一个格子大,则更新matrix[i][j] = max(matrix[i][j], dp(a, b)] + 1)
采取记忆化搜索递归的方法,如果当前点更新过了dp[i][j] != 1,则无需状态转移。

解法
递归。复杂度 - 时间O(n^2), 空间O(n^2)。

class Solution(object):
    def longestIncreasingPath(self, matrix):
        """
        :type matrix: List[List[int]]
        :rtype: int
        """
        if not matrix or not matrix[0]:
            return 0
        
        m, n = len(matrix), len(matrix[0])
        dp = [[1] * n for _ in range(m)]    # dp[i][j]以matrix[i][j]结尾的LIS
        dxy = [(-1, 0), (0, -1), (1, 0), (0, 1)]
        
        def dfs(x, y):
            if dp[x][y] != 1:
                return dp[x][y]
            
            for dx, dy in dxy:
                nx, ny = x + dx, y + dy
                if 0 <= nx < m and 0 <= ny < n and matrix[x][y] > matrix[nx][ny]:
                    dp[x][y] = max(dp[x][y], dfs(nx, ny) + 1)
            return dp[x][y]
        
        res = 1
        for i in range(m):
            for j in range(n):
                res = max(res, dfs(i, j))
        return res

(简化版)

class Solution(object):
    def longestIncreasingPath(self, matrix):
        """
        :type matrix: List[List[int]]
        :rtype: int
        """
        if not matrix or not matrix[0]:
            return 0
        m, n = len(matrix), len(matrix[0])
        dp = [[1] * n for _ in range(m)]
        
        def dfs(i, j):
            if dp[i][j] == 1:
                dp[i][j] = 1 + max(dfs(i-1, j) if i > 0 and matrix[i][j] > matrix[i-1][j] else 0,
                                  dfs(i+1, j) if i < m-1 and matrix[i][j] > matrix[i+1][j] else 0,
                                  dfs(i, j-1) if j > 0 and matrix[i][j] > matrix[i][j-1] else 0,
                                  dfs(i, j+1) if j < n-1 and matrix[i][j] > matrix[i][j+1] else 0)
            return dp[i][j]
        
        return max(dfs(i, j) for i in range(m) for j in range(n))

322. Coin Change

题目描述

给定不同面值的硬币和总钱数amount。求得到总钱数所需的最小硬币数。如果无法得到总钱数,返回-1。
假设每种硬币有无限个。

例子
Example 1:

Input: coins = [1, 2, 5], amount = 11
Output: 3

Explanation: 11 = 5 + 5 + 1

Example 2:

Input: coins = [2], amount = 3
Output: -1

思想
(DP - 背包问题)用amount+1标记无穷。
初始化:前0种组成价值0所需数目为0, 前0种组成价值j(j>0)所需数目为无穷。
转移方程
当j >= coins[i-1]时,至少取一个coins[i-1]:dp[i][j - coins[i-1]] + 1;或一次也不取coins[i-1]:dp[i-1][j]。即dp[i][j] = min(dp[i][j - coins[i-1]] + 1, dp[i-1][j]);
当j < coins[i-1]时,只能一次也不取coins[i-1]:dp[i-1][j]。即dp[i][j] = dp[i-1][j]。
(优化)
索引coins时的优化和空间优化

解法1
DP。复杂度:时间 - O(mn),空间-O(mn)

class Solution(object):
    def coinChange(self, coins, amount):
        """
        :type coins: List[int]
        :type amount: int
        :rtype: int
        """
        n = len(coins)
        dp = [[amount+1] * (amount+1) for _ in range(n+1)]    # dp[i][j]表示用前i种coins组成价值j所需的最小数量
        dp[0][0] = 0
        
        for i in range(1, n+1):
            for j in range(amount+1):
                if j >= coins[i-1]:
                    dp[i][j] = min(dp[i][j - coins[i-1]] + 1, dp[i-1][j])# 至少用一次coin[i-1]/一次也不用
                else:
                    dp[i][j] = dp[i-1][j]
        return -1 if dp[-1][-1] == amount+1 else dp[-1][-1]

解法2 - 优化
DP。复杂度:时间 - O(mn),空间-O(mn)

class Solution(object):
    def coinChange(self, coins, amount):
        """
        :type coins: List[int]
        :type amount: int
        :rtype: int
        """
        n = len(coins)
        dp = [amount+1] * (amount+1)
        dp[0] = 0
        
        for coin in coins:
            for j in range(amount+1):
                if j >= coin:
                    dp[j] = min(dp[j-coin] + 1, dp[j])
        return dp[-1] if dp[-1] != amount + 1 else -1

你可能感兴趣的:(Leetcode)