1049.最后一块石头的重量II
和昨天的分割等和子集几乎一样。
dp[j]:容量为j的时候,能装下石头重量的最大值。
递推公式: dp[j] = Math.max(dp[j], dp[j - stones[i]] + stones[i]);
第一个stones代表重量,第二个代表价值。
初始化:dp[0]初始化为0就好。
遍历顺序:先遍历物品,再遍历空间。遍历空间的时候从大到小,避免重复添加。
class Solution {
public int lastStoneWeightII(int[] stones) {
int sum = 0;
for(int i :stones){
sum += i;
}
int n = sum/2;
int[] dp = new int[n + 1];
for(int i = 0; i < stones.length; i++){
for(int j = n; j>=stones[i]; j--){
dp[j] = Math.max(dp[j], dp[j - stones[i]] + stones[i]);
}
}
int res = sum - 2 * dp[n];
return res;
}
}
494、目标和
思路:sum是固定的,target也是固定的,所以求出正数集合的值也是固定的。
dp[j]:容量为j的时候,能装满背包的的方法数。
递推公式: dp[j] += dp[j - nums[i]];
初始化:dp[0]初始化为1。
遍历顺序:先遍历元素,再遍历空间。遍历空间的时候从大到小,避免重复添加。
这里一度想只遍历最后一个。结果显然是不行的,因为下一层的更新依赖于上一层的每一个数。
class Solution {
public int findTargetSumWays(int[] nums, int target) {
int sum = 0;
int count = 0;
for(int i :nums){
sum += i;
}
if((sum + target)%2 !=0){
return 0;
}
//如果目标的绝对值大于sum,说明即便全部取正或者负都凑不了
if(Math.abs(target) > sum) 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];
}
}
474、一和零
这题用的虽然是二维数组,但是多的一个维度是背包容量,实际思想仍然是滚动数组的逻辑。
dp[i][j] = 背包容量为可以装i个0,j个1的最大子集长度。
递推公式: dp[i][j] = Math.max(dp[i][j],dp[i-x][j-y]+1);
其中x,y是当前元素中0,和1的个数。这里的value值就是1,因为单个元素就只会让长度增加1.
遍历顺序:先取每个元素出来并且统计0和1的个数。然后空间从大到小遍历,如果任何一个维度的容量不够,就进入下一个元素。
class Solution {
public int findMaxForm(String[] strs, int m, int n) {
int[][] dp = new int[m+1][n+1];
for(String elem: strs){
int x = 0,y=0;
char[] str = elem.toCharArray();
for(int k = 0; k < str.length; k++){
if(str[k] == '0'){
x++;
}else{
y++;
}
}
for(int i = m; i >=x; i--){
for(int j = n; j>=y; j--){
dp[i][j] = Math.max(dp[i][j],dp[i-x][j-y]+1);
}
}
}
return dp[m][n];
}
}