视频讲解:
动态规划之背包问题,装满这个背包最多用多少个物品?| LeetCode:474.一和零_哔哩哔哩_bilibili
动态规划之背包问题,装满背包有多少种方法?| LeetCode:494.目标和_哔哩哔哩_bilibili
动态规划之背包问题,这个背包最多能装多少?LeetCode:1049.最后一块石头的重量II_哔哩哔哩_bilibili
1049. 最后一块石头的重量
思路:本题和划分子集的思想也是一致,但是需要额外主要的就是我们是以石头重量总和一半为目标,全力去凑,希望可以访问半数石头总和这样大小的背包,因而在最后的结果上,我们是将将dp的最后一个元素,需要用石头重量总和减去dp数组的最后元素作为结果。
// 时间复杂度O(n^2)
// 空间复杂度O(n)
class Solution {
public int lastStoneWeightII(int[] stones) {
// 本题形成了划分两堆石头的思路,那么本题就和划分子集一样
int sum = 0;
for(int i:stones)
sum+=i;
int target = sum >> 1;
int[] dp = new int[target+1];
for(int i=0; i<stones.length; i++){
for(int j=target; j>0; j--){
if(j >= stones[i])
dp[j] = Math.max(dp[j], dp[j-stones[i]]+stones[i]);
}
}
return sum-2*dp[target];
}
}
494. 目标和
思路:处理两堆子集的思想,将目标和氛围A堆和与B堆和,利用A+B=target, A-B=sum,来总结A为(sum+target)/2,从而确定此时背包的目标容量。另外特殊情况就是target远在sum之外,需要额外讨论。
// 时间复杂度O(n^2)
// 空间复杂度O(n)
class Solution {
public int findTargetSumWays(int[] nums, int target) {
int sum = 0;
for(int i:nums)
sum+=i;
if((sum+target)%2 == 1)
return 0;
if(sum < Math.abs(target))
return 0;
int tar = Math.abs((sum+target)/2);
int[] dp = new int[tar+1];
// 和为零的只有一种,
dp[0] = 1;
for(int i=0; i<nums.length; i++){
for(int j=tar; j>=0; j--){
if(j>=nums[i])
dp[j] += dp[j-nums[i]];
}
}
return dp[tar];
}
}
474. 一和零
class Solution {
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];
}
}