笔记:代码随想录
概述
Dynamic Programming 简称 DP。动态规划是从上一个状态推导当前状态。贪心则和上一个状态没关系。
五个步骤
- 确定dp数组以及下标的含义
- 确定递推公式
- dp数组如何初始化
- 确定遍历顺序
- 举例推导dp数组
方法
基础问题,背包问题,打家劫舍问题,股票问题,子序列问题
基础问题
1.斐波那契数
2.爬楼梯
3.使用最小花费爬楼梯
4.不同路径
5.不同路径二
6.整数拆分
7.不同的二叉搜索树
背包问题
8.0-1背包理论基础一
二维数组
做动态规划的题目,最好的过程就是自己在纸上举一个例子把对应的dp数组的数值推导一下,然后在动手写代码!
01背包和完全背包最大的不同就是每种物品完全背包有无限件。完全背包可以转化为01背包。
9.0-1背包理论基础二
一维数组(滚动数组)
10.分割等和子集
如果题目给的价值都是正整数那么非0下标都初始化为0就可以了,如果题目给的价值有负数,那么非0下标就要初始化为负无穷。
这样才能让dp数组在递推的过程中取得最大的价值,而不是被初始值覆盖了。
dp[j] = max(dp[j], dp[j - nums[i]] + nums[i])
11.最后一块石头的重量二
12.目标和
既然为target,那么就一定有 left组合 - right组合 = target。left + right = sum,而sum是固定的。right = sum - left公式来了, left - (sum - left) = target 推导出 left = (target + sum)/2 。
求组合类问题的公式,都是类似这种:
dp[j] += dp[j - nums[i]]
13.一和零
14.完全背包理论基础
每件物品都有无限个(也就是可以放入背包多次),完全背包和01背包问题唯一不同的地方就是,每种物品有无限件。在完全背包中,对于一维dp数组来说,其实两个for循环嵌套顺序是无所谓的!
15.零钱兑换二
如果求组合数就是外层for循环遍历物品,内层for遍历背包。
如果求排列数就是外层for遍历背包,内层for循环遍历物品。
16.组合总和四
17.爬楼梯
18.零钱兑换
19.完全平方数
20.单词拆分
21.多重背包理论基础
打家劫舍问题
22.打家劫舍
23.打家劫舍二
闭环了,考虑开头是nums[0]以及结尾是nums[0]的情况。
24.打家劫舍三
树形dp
股票问题
25.买卖股票的最佳时机
26.买卖股票的最佳时机二
27.买卖股票的最佳时机三
28.买卖股票的最佳时机四
29.最佳买卖股票时机含冷冻期
30.买卖股票的最佳时机含手续费
可以考虑一下为什么不从持有的时候入手减去手续费
子序列问题
31.最长上升子序列
dp经典问题
class Solution:
def lengthOfLIS(self, nums: List[int]) -> int:
dp = [1] * len(nums)
results = 1
for i in range(1, len(nums)):
for j in range(i):
if nums[i] > nums[j]:
dp[i] = max(dp[i], dp[j] + 1)
results = max(results, dp[i])
return results
32.最长连续递增序列
33.最长重复子数组
34.最长公共子序列
35.不相交的线
36.最大子序和
37.判断子序列
38.不同的子序列
如果是连续序列,可以考虑KMP
39.两个字符串的删除操作
40.编辑距离
41.回文子串
42.最长回文子序列