1049.最后一块石头的重量II
尽可能装满
class Solution {
public int lastStoneWeightII(int[] stones) {
//分成两个尽量相等的等份就可以使剩下的石头尽可能的小。
//dp[] 最后的出来的是最接近一半的偏小的那部分
//dp[j] 表示能装i的背包里面能装的最大价值(重量)
//dp[j] = Math.max(dp[i],dp[j - stones[i]] + stones[i])
//初始化。dp[j] = 0
//从j = 0遍历,内部背包,外部物品
//内部要反着遍历
int sum = 0;
for(int i = 0;i < stones.length;i++){
sum += stones[i];
}
int[] dp = new int[(sum / 2) + 1];
for(int i = 0;i < stones.length;i++){
for(int j = sum / 2;j >= 0;j--){
if(j >= stones[i])
dp[j] = Math.max(dp[j],dp[j - stones[i]] +stones[i]);
}
}
return sum - dp[sum / 2] - dp[sum / 2];
}
}
494.目标和
class Solution {
public int findTargetSumWays(int[] nums, int target) {
//左子树-右子树 = target,如何确定左右子树有哪些数字
//left - right = target,一个数是奇数(sum),那么他只能拆为奇数加偶数, 二者之差为奇数(target)。 sum + target为偶数
//一个数是偶数,那么他能拆为两个奇数或两个偶数,二者之差为偶数。
//同样 sum + target
//所以sum + target必须是偶数
//left + right = sum
//left = (sum + target) / 2
//从num中找出等于left的数量
//dp[j]代表装满j的最大组合数量。
//dp[j] += dp[j - nums[i]];
//dp[0] = 1;
int sum = 0;
for(int i = 0;i < nums.length;i++){
sum += nums[i];
}
if(target < 0 && sum < -target || target > 0 && sum < target)return 0;
if((sum + target) % 2 != 0)return 0;
int size = (sum + target) / 2;
int[] dp = new int[size + 1];
dp[0] = 1;
for(int i = 0;i < nums.length;i++){
for(int j = size;j >= nums[i];j--){
dp[j] += dp[j - nums[i]];
}
}
return dp[size];
}
}
474.一和零
class Solution {
public int findMaxForm(String[] strs, int m, int n) {
//dp[i][j] 表示背包容量为ij时的最大子集个数 i个0,j个1
//dp[i][j] = max(dp[i][j],dp[i - numsi][j - numj] + 1)
//全部初始化为0
//先遍历物品,再遍历背包
int [][] dp = new int[m + 1][n + 1];
for(String s : strs){
//计算这个物品的重量(几个i 几个 j)
int num0 = 0;
int num1 = 0;
for(int i = 0;i < s.length();i++){
if(s.charAt(i) == '0')num0++;
else if(s.charAt(i) == '1')num1++;
}
for(int i = m;i >= num0;i--){
for(int j = n;j >= num1;j--){
dp[i][j] = Math.max(dp[i][j],dp[i - num0][j - num1] + 1);
}
}
}
return dp[m][n];
}
}