题目与题解
1049. 最后一块石头的重量
题目链接:1049. 最后一块石头的重量
代码随想录题解:1049. 最后一块石头的重量
视频讲解:动态规划之背包问题,这个背包最多能装多少?LeetCode:1049.最后一块石头的重量II_哔哩哔哩_bilibili
解题思路:
看答案
看完代码随想录之后的想法
核心思想是要尽可能分成两堆大小相差较小的石块,最终结果就是两堆石块的相减重量最小。
那就转变为,对石块总数求和sum,背包大小为sum/2,有价值和重量都为nums[i]的石块装入背包,如何装价值最大。
class Solution {
public int lastStoneWeightII(int[] stones) {
int sum = 0;
for (int i = 0; i < stones.length; i++) {
sum += stones[i];
}
int target = sum/2;
int[] dp = new int[target+1];
for (int i = 0; i < stones.length; i++) {
for (int j = target; j >= stones[i] ; j--) {
dp[j] = Math.max(dp[j], dp[j - stones[i]] + stones[i]);
}
}
return sum - dp[target] - dp[target];
}
}
遇到的困难
应用题转到背包问题真是想不到。
494. 目标和
题目链接:494. 目标和
代码随想录题解:494. 目标和
解题思路:
看答案
看完代码随想录之后的想法
本题要如何使表达式结果为target,既然为target,那么就一定有 left组合 - right组合 = target。left + right = sum,而sum是固定的。right = sum - left
公式来了, left - (sum - left) = target 推导出 left = (target + sum)/2 。
target是固定的,sum是固定的,left就可以求出来。
此时问题就是在集合nums中找出和为left的组合。
此外,还要排除掉sum + target为奇数的情况,否则就没有结果。
class Solution {
public int findTargetSumWays(int[] nums, int target) {
int sum = 0;
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
}
if (target > sum || target < -sum) return 0;
if ((sum+target) % 2 == 1) return 0;
int left = (sum+target)/2;
int[] dp = new int[left+1];
dp[0] = 1;
for (int i = 0; i < nums.length; i++) {
for (int j = left; j >= nums[i]; j--) {
dp[j] += dp[j - nums[i]];
}
}
return dp[left];
}
}
遇到的困难
一开始想用二维数组解决,用两重循环,实际上就是求累加和,如果上一行dp[i-1][j+nums[i]]或dp[i-1][j-nums[i]]存在,下一行就直接累加即可。
但是这样做存在一些问题,当nums中存在0时会出错,nums中只有一个数字好像也不对,估计是初始化的锅,先把错误答案放着,后面有机会再看看怎么改
class Solution {
public int findTargetSumWays(int[] nums, int target) {
int sum = 0;
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
}
if (target > sum || target < -sum) return 0;
int[][] dp = new int[nums.length][2*sum + 1];
dp[0][sum+1-nums[0]] = 1;
dp[0][sum+1+nums[0]] = 1;
for (int i = 1; i < nums.length; i++) {
for (int j = 0; j < 2*sum+1 - nums[i]; j++) {
dp[i][j] += dp[i-1][j+nums[i-1]];
}
for (int j = nums[i]; j < 2*sum+1; j++) {
dp[i][j] += dp[i-1][j-nums[i-1]];
}
}
return dp[nums.length-1][target + sum + 1];
}
}
474.一和零
题目链接:474.一和零
代码随想录题解:474.一和零
视频讲解:动态规划之背包问题,装满这个背包最多用多少个物品?| LeetCode:474.一和零_哔哩哔哩_bilibili
解题思路:
相比一般的01背包问题,这题每个物品多了一重value的计算,本质上还是01背包问题。
看完代码随想录之后的想法
相比之下,dp要多一重value的计算,物品还是一维的。其value就是每个str的0的数量和1的数量
class Solution {
public int findMaxForm(String[] strs, int m, int n) {
int[][] dp = new int[m+1][n+1];
for (String str:strs) {
int zeroNum = 0;
int oneNum = 0;
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) == '0') zeroNum++;
if (str.charAt(i) == '1') oneNum++;
}
for (int i = m; i >= zeroNum; i--) {
for (int j = n; j >= oneNum ; j--) {
dp[i][j] = Math.max(dp[i][j], dp[i-zeroNum][j-oneNum]+1);
}
}
}
return dp[m][n];
}
}
遇到的困难
想不到
今日收获
又多了一些自闭的理由,背包问题好难好难。