1049. 最后一块石头的重量 II
本题和上一题子集和比较类似,就是比较难想到用背包问题解题,写代码过程还是很顺畅的。。
一维01背包解题思路:
本题可以看成容量为target=sum/2的背包,尽可能往里装石头,石头的重量和价值都为stones【i】,最多可以装dp[j]的石头,则剩下了sum-dp[target]的石头,最后两者取差值,即为结果。
因为sum/2为向下取整,因此dp[target]<=sum/2,因此sum-dp-dp即为本题结果。
public int lastStoneWeightII(int[] stones) {
int sum=0;
for(int i:stones){
sum+=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. 目标和
。。。让我学会放弃,快哭了
这个题解挺清晰的,我大概能看懂,但是她的数组定义区间为0-i,就让我我看不懂初始化的过程和为什么是nums[i-1],然后我自己尝试转化成]0i-1]出错了,真挺崩的,哈哈。
说一下我理解的解题思路:
nums数组中,所有i的和为sum,所有整整数和为A,负整数(取绝对值)和为B。那么可以得出:
①A+B=sum ②A-B=target
综上所述,可得A=(sum+target)/2
因此可将本题转化为,[0,i]个物品,每个物品重量为nums[i],使其和为(sum+target)/2共有多少种取法(有多少种方法能将容量为A的背包填满)?
注意:sum和target都为正整数,因此和一定为偶数,若target+sum不为偶数,直接返回0即可。
dp[i][j]含义:从[0,i]中取数,和为j,有dp[i][j]种取法。
每次有两种选择:
①取
dp[i][j] = dp[i - 1][j] + dp[i - 1][j - nums[i]]; //不取的方法+取的方法总和
②不取(j<nums[i-1])
dp[i][j] = dp[i - 1][j]
代码我就贴个正确版。。照抄的。。自己没做出来。。
public int findTargetSumWays(int[] nums, int target)
{
int sum = 0;
for (int num : nums) {
sum += num;
}
int bagSize = (target + sum) / 2;
if (bagSize < 0) bagSize = -bagSize;
//如果target + sum为奇数,则无解
if ((target + sum) % 2 == 1) return 0;
int[][] dp = new int[nums.length + 1][bagSize + 1];
for (int i = 0; i <= nums.length; i++) {
dp[i][0] = 1;
}
for (int i = 1; i <= nums.length; i++) {
for (int j = 0; j <= bagSize; j++) {
if (j >= nums[i - 1])
dp[i][j] = dp[i - 1][j] + dp[i - 1][j - nums[i - 1]];
//很多人不理解这里为什么是nums[i - 1]
// 这是因为第一层for中的i从1开始,i-1是为了让nums[]从第一个元素开始遍历,是对齐操作
else
dp[i][j] = dp[i - 1][j];
}
}
return dp[nums.length][bagSize];
}
474.一和零
题我是真看不太明白。。看代码都没看懂。。看题解也没看懂。。真让我有点怀疑自己了救命。。希望二刷能弄清楚
01背包解题思路:
本题可以看作是有两个维度的背包问题。
dp[i][j]:最多有i个0和j个1的strs的最大子集的大小为dp[i][j]。
我这里是真看不懂。。二刷让我把数组都推一遍。。。
public int findMaxForm(String[] strs, int m, int n) {
//dp[i][j]表示i个0和j个1时的最大子集
int[][] dp = new int[m + 1][n + 1];
int oneNum, zeroNum;
for (String str : strs) {
oneNum = 0;
zeroNum = 0;
for (char ch : str.toCharArray()) {
if (ch == '0') {
zeroNum++;
} else {
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];
}