文章目录
- 前言
- 动态规知识点
- 动规五部曲
- 一、1049. 最后一块石头的重量 II
- 二、494. 目标和
- 三、474. 一和零
- 总结
前言
一个本硕双非的小菜鸡,备战24年秋招,计划二刷完卡子哥的刷题计划,加油!
二刷决定精刷了,于是参加了卡子哥的刷题班,训练营为期60天,我一定能坚持下去,迎来两个月后的脱变的,加油!
推荐一手卡子哥的刷题网站,感谢卡子哥。代码随想录
动态规知识点
终于来到了守关boss。。。
动态规划中每一个状态一定是由上一个状态推导出来的
动规是由前一个状态推导出来的,而贪心是局部直接选最优的。
动规五部曲
动态规划一般分为如下五步:
- 确定dp数组(dp table)以及下标的含义
- 确定递推公式
- dp数组如何初始化
- 确定遍历顺序
- 举例推导dp数组
//1. 确定dp数组(dp table)以及下标的含义//2. 确定递推公式//3. dp数组如何初始化//4. 确定遍历顺序//5. 举例推导dp数组
解题时候多把dp数组打印出来,看看究竟是不是按照自己思路推导的。
写代码之前一定要把状态转移在dp数组的上具体情况模拟一遍,心中有数,确定最后推出的是想要的结果。
然后再写代码,如果代码没通过就打印dp数组,看看是不是和自己预先推导的哪里不一样。
如果打印出来和自己预先模拟推导是一样的,那么就是自己的递归公式、初始化或者遍历顺序有问题了。
如果和自己预先模拟推导的不一样,那么就是代码实现细节有问题。
一、1049. 最后一块石头的重量 II
1049. 最后一块石头的重量 II
Note:01背包系列
class Solution {
public:int lastStoneWeightII(vector<int>& stones) {int sum = 0;for (int i = 0; i < stones.size(); i++)sum += stones[i];int target = sum / 2;//1. 确定dp数组(dp table)以及下标的含义//最多可以粉碎一半的石头重量vector<int> dp(15001, 0);//2. 确定递推公式//dp[j] = max(dp[j], dp[j - stones[i] + stones[i]])//3. dp数组如何初始化//4. 确定遍历顺序for (int i = 0; i < stones.size(); i++) {for (int j = target; j >= stones[i]; j--) {dp[j] = max(dp[j], dp[j - stones[i]] + stones[i]);}}//5. 举例推导dp数组return sum - dp[target] - dp[target];}
};
二、494. 目标和
494. 目标和
Note:01背包系列,有点压力了
class Solution {
public:int findTargetSumWays(vector<int>& nums, int target) {int sum = 0;for (int i = 0; i < nums.size(); i++)sum += nums[i];//两种没有方案的情况//(1)奇数个if ((target + sum) % 2 == 1) return 0;//(2)目标大于输入数组if (abs(target) > sum) return 0;int bagSize = (target + sum) / 2;//1. 确定dp数组(dp table)以及下标的含义//dp[j] 表示:填满j(包括j)这么大容积的包,有dp[j]种方法vector<int> dp(bagSize + 1, 0);//2. 确定递推公式//dp[j] += dp[j - nums[i]]//3. dp数组如何初始化dp[0] = 1;//4. 确定遍历顺序for (int i = 0; i < nums.size(); i++) {for (int j = bagSize; j >= nums[i]; j--) {dp[j] += dp[j - nums[i]];}}//5. 举例推导dp数组return dp[bagSize];}
};
三、474. 一和零
474. 一和零
Note:01背包系列,确实有难度
class Solution {
public:int findMaxForm(vector<string>& strs, int m, int n) {//1. 确定dp数组(dp table)以及下标的含义//最多有i个0和j个1的strs的最大子集的大小为dp[i][j]。vector<vector<int>> dp(m + 1, vector<int> (n + 1, 0));//2. 确定递推公式//dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1)//3. dp数组如何初始化//4. 确定遍历顺序for (string str : strs) {int oneNum = 0, zeroNum = 0;for (char c : str) {if (c == '0') zeroNum++;else oneNum++;}for (int i = m; i >= zeroNum; i--) {for (int j = n; j >= oneNum; j--) {dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);}}}//5. 举例推导dp数组return dp[m][n];}
};
总结
动态规划法,和分治法极其相似。区别就是,在求解子问题时,会保存该子问题的解,后面的子问题求解时,可以直接拿来计算。