LeetCode1049最后一块石头的重量2
class Solution {
public int lastStoneWeightII(int[] stones) {
/** 第三遍:将数组分成两堆,是的两堆之间的差最小。
按照总和的一半分成两堆,看看容量为sum/2的背包能装多少,再用剩下的减去背包里面的就是结果
dp[j] : 背包重量为i,能装多大价值的石头
dp[j] = Math.max(dp[j], dp[j-weight[i] + value[i]])
初始化:全为0
循环方向:01背包经典方向
外层从前到后
内层从后到前
*/
int size = stones.length;
int sum = 0;
for(int i=0;i<size;i++){
sum += stones[i];
}
int target = sum / 2;
int[] dp = new int[target+1];
for(int i=0;i<size;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];
}
}
LeetCode494目标和
难点在于递推公式的理解。
class Solution {
public int findTargetSumWays(int[] nums, int target) {
/**第二遍
组合问题,所以递推公式变了
这里的递推公式是关键
dp[i]:装满容量为i的背包有dp[j]种方法
递推公式:dp[j] += dp[j-nums[i]]//类似爬楼梯理解,之前前一个台阶的方法,再加上到达这一层台阶有多少方法就可以了。
举例:
按照示例1 求dp[4];
现在L里面已经有一个物品nums[0]的话那么方法就是dp[3],而dp[3]又可以拆成1个和dp[2] 一次类推。dp[i] = dp[i]+ dp[i-1]
用dp[i][j]会比较好理解:i-->nums j-->L
对于选了nums[i],dp[i][j] = dp[i-1][j]+dp[i-1][j-nums[i]]
前一项表示不加nums[i]这个数;那就是之前的方法个数,
后一项表示有几种方法可以加上这个数nums[i]。
两者一加,得到一共需要多少方法。
按照,二维数组写可以但是要注意循环都是从前到后,且第二个循环里要判断j<nums[i]
*/
int size = nums.length;
int sums = 0;
int L =0;
for(int i=0;i<size;i++){
sums += nums[i];
}
if(Math.abs(target) > sums){
return 0;
}
if((sums+target)%2 == 1){
return 0;
}else{
L = (sums+target)/2;
}
int[] dp = new int[L+1];
dp[0] = 1; // 注意初始化必须有
for(int i=0;i<size;i++){
for(int j=L;j>=nums[i];j--){
dp[j] += dp[j-nums[i]]; // 递推公式改变
}
}
return dp[L];
}
}