review: 动规问题解决步骤
step1: 分析题目属于哪类问题,确定dp数组含义
step2: 确定dp状态转移公式
step3: 确定dp数组初始化,尤其注意递推公式中的边界值.(初始化需要参考状态转移公式)
step4: 确定递推顺序
不管是01背包还是完全背包都会出现求背包在某容量下最大值问题/求填满背包的最少物品等最值问题 ; 或 求有多少种方法填满背包等排列或组合问题
最值问题
- 最大值问题,初始化为最小值; 最小值问题,初始化为最大值;
- 循环遍历时,比较不放物品和放物品的值那个更大,更新最大值.
// 最大值
dp = [0 for i in range(n)] // 初始化为最小值0
dp[j] = max(dp[j],dp[j-weigh[i]] + values[i]) // 状态转移方程
// 最小值
dp = [ float("INF") for i in range(n)] // 初始化为最大值INF
dp[j] = min( dp[j] , dp[j-weight[i]] + values[i])
最值公式内部比较大小的具体数值不一定是dp[j-weight[i]] + values[i],可以根据题义改成dp[j-weight[i]] + 1;
排列或组合问题
考量双层遍历顺序,先遍历物品还是先遍历背包? 背包容量从大到小遍历还是从小到大遍历?
组合问题
- 不强调元素之间的顺序
- 先遍历物品,再遍历背包
排列问题
- 强调元素之间的顺序问题
- 先遍历背包大小, 再遍历物品
不管求组和还是求排列,都是用累加公式,而不是最大值公式;
这里要和回溯问题进行区分,回溯问题需要知道排列或者组合的具体情况,动规只需要只有有几种组合即可.
0-1背包问题
物品只有放入背包和不放入背包两种状态,考量物品是否可以重复放入.
dp数组定义:
dp可以设置为二维,也可以压缩空间设置成一维
- dp[i][j]的定义为前0-i个元素可以将容量为j的背包填满的XX值(XX值是什么具体含义针对题目来定义)
- dp[j]的定义为容量为j的背包填满可以达到的XX值
状态转移方程:
for i in range(len(nums)):
for j in range(bagweights,weight[i]-1,-1)
为了避免重复放入,背包重量的遍历顺序为从最大容量到最小容量遍历
完全背包问题
物品不限个数,可以多次放入背包;
dp数组定义:
同0-1背包
状态转移方程:
for i in range(len(nums)):
for j in range(weight[i],bagweights+1)
可以重复放入,所以背包重量的遍历顺序为从最小容量到最大容量遍历
题目链接
有(完全背包/0-1背包) + (最值问题/排列/组合问题) 的组合
最值
416 分割等和子集 (0-1背包 )
1049 最后一块石头的重量II (0-1背包)
474 一和零 (0-1背包)
322 零钱兑换 (完全背包)
279 完全平方数 (完全背包)
组合问题
518 零钱兑换II(完全背包)
494 目标和(0-1背包)
排列问题
377 组合总数IV(完全背包)
70 爬楼梯