目录
前沿:撰写博客的目的是为了再刷时回顾和进一步完善,其次才是以教为学,所以如果有些博客写的较简陋,是为了保持进度不得已而为之,还请大家多多见谅。
预:看到题目后的思路和实现的代码。
见:参考答案展示。
感思:对比答案后的思考,与之前做过的题目是否有关联。
行:
(1)对于没做出来的题目,阅读答案后重新做一遍;
(2)下次做题可以尝试改善的方向;
(3)有助于理解的相关的题目
优先级:做题进度>学习&总结>默写回顾>做题数量
题目回顾
动态规划相关章节
动态规划五步法:
- 确定dp数组以及下标的含义
确定递推公式
dp数组如何初始化
确定遍历顺序
举例推导dp数组
1.分割等和子集
题目链接:416. 分割等和子集
思路:
判断是否能转换成0-1背包问题:
- 分割等和子集→目标值target=所有子集和÷2
- 每次选完子集便不能重复→适用0-1背包,而不是完全背包问题
- 每个子集值又是重量也是价值,当刚好背包重量为目标值时,此时若子集获取价值也为目标值,则认为是可分割的。
过滤条件:若target为非正整数,则子集不可能分割成非正整数(都为正整数)。
动态规划五步法:
- dp[j]表示当背包重量为j时,能够获得的最大价值。
- 递推公式:dp[j] = max(dp[j],dp[j-i]+values[i])
- 初始化设置为0,因为递推公式取最大 and 数组只包含正整数(nums[i]>0)
- dp[j]是滚动数组0-1背包形式,先对物品遍历,再对背包重量逆序遍历。
- 若背包重量先遍历,则会导致每个重量的背包都只能选择一个物品就遍历完了。
- 背包重量必须从大到小遍历,因为本质上还是二维数组遍历,需保证上层的值不变的情况下实现递推,否则将会重复背包。
- 略(实际做题时必须验证!)
class Solution {
public boolean canPartition(int[] nums) {
if(nums.length == 1){
return false;
}
int len = nums.length;
int target = 0;
for(int i = 0;i < len;i++){
target += nums[i];
}
if(target - (target/2)*2 != 0){
return false;
}
target /= 2;
int[] result = new int[target+1];
for(int i = 1;i < len;i++){
for(int j = target;j > 0;j--){
if(j >= nums[i]){
result[j] = Math.max(result[j],result[j-nums[i]]+nums[i]);
}
}
}
if(result[target] == target){
return true;
}else{
return false;
}
}
}
参考答案中对背包重量的优化:
for(int j = target;j >= nums[i];j--){
dp[j] = Math.max(dp[j],dp[j-nums[i]]+nums[i]);
}
2.最后一块石头的重量 II
题目链接:1049. 最后一块石头的重量 II
思路
两个石子相撞是重量相减得到差的过程 那么取出任意两个石子去碰撞 就可以将较大重量的石子作为正数 较小重量作为负数 则可以将所有石子分成正号堆和负号堆两堆 最终的结果就可以表示为给石头数组中的数字添加正负号来使得形成的计算表达式的绝对值最小 此时这道题就和 目标和 那道题一样了
3.目标和
题目链接:494. 目标和
思路:组合0-1背包问题
- dp[j]含义:填满j这么大容积的包,有dp[j]个方法
- 推导公式:dp[j] = dp[j-nums[i]]
- 求填满j容积包的方法,当前物品重量为nums[i],若要添加上nums[i]刚好填满,则需要前面除去nums[i]重量时存在有满足填满[j-nums[i]]的方法。
- 因为是从物品0遍历到物品i,每次新增的物品若存在满足[j-nums[i]]的方法,则都能作为新的满足填满j容积的方法。
- 初始化:dp[0] = 1,因为填满0容积的包,无论加减都至少能有一种方法。
- 遍历顺序就是常规0-1背包顺序
- 举例推导
3.一和零
题目链接:474. 一和零
class Solution {
public int findMaxForm(String[] strs, int m, int n) {
int[][] weight = getWeight(strs);
int[][] dp = new int[m+1][n+1];
for(int i = 0;i < weight.length;i++){
for(int j = m;j >= weight[i][0];j--){
for(int k = n;k >= weight[i][1];k--){
dp[j][k] = Math.max(dp[j][k],dp[j-weight[i][0]][k-weight[i][1]]+1);
}
}
}
return dp[m][n];
}
int[][] getWeight(String[] strs){
int slen = strs.length;
int[][] weight = new int[slen][2];
for(int i = 0;i < slen;i++){
for(int j = 0;j < strs[i].length();j++){
// System.out.println(strs[i].charAt(j) == '0');
if(strs[i].charAt(j) == '0'){
weight[i][0]++;
}else{
weight[i][1]++;
}
}
// System.out.println(strs[i].charAt(j) == '0');
}
return weight;
}
}