跳过正文
  1. 全部/
  2. 笔记/
  3. LeetCode/

023 动态规划

53. 最大子数组和 给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组,返回其最大和。 问:为什么不能用「选或不选 nums[i]」的思路做? 答:选或不选无法保证子数组是连续的

  1. 选或不选适用于子序列问题(例如 0-1 背包问题)
  2. 对于子数组问题,更适合用「拼接」的思路,即如果 nums[i] 左边的子数组元素和是负的,就不用和左边的子数组拼在一起了。

300. 最长递增子序列 问:什么样的题目适合「选或不选」,什么样的题目适合「枚举选哪个」? 答:我分成两类问题:

  1. 相邻无关子序列问题(比如 0-1 背包),适合「选或不选」。每个元素互相独立,只需依次考虑每个元素选或不选。
  2. 相邻相关子序列问题(比如本题),适合「枚举选哪个」。我们需要知道子序列中的相邻两个数的关系。对于本题来说,枚举 nums[i] 必选,然后枚举前一个必选的数,方便比大小。如果硬要用「选或不选」,需要额外记录上一个选的数的下标,算法总体的空间复杂度为 O(n 2 ),而枚举选哪个只需要 O(n) 的空间。

完全背包

dp[i][j] = min(dp[i-1][j], dp[i][j-coins[i-1]]+1)

func coinChange(coins []int, amount int) int {
    m, n := len(coins)+1, amount+1
    dp := make([][]int, m)
    for i := range m {
        dp[i] = make([]int, n)
    }
    for j := range n {
        dp[0][j] = math.MaxInt32
    }
    dp[0][0] = 0
    for i := 1; i < m; i++ {
        for j := 1; j < n; j++ {
            if coins[i-1] > j {
                dp[i][j] = dp[i -1][j]
            } else {
                dp[i][j] = min(dp[i-1][j], dp[i][j-coins[i-1]]+1)
            }
        }
    }
    if dp[m-1][n-1] > math.MaxInt32/2 {
        return -1
    }
    return dp[m-1][n-1]
}
Reply by Email