1.最后一块石头的重量 II
其核心思路就是将一堆石头分为两堆,这两堆石头的重量尽可能相近,这样相互抵消得到的结果就是符合题目要求的。
那么这个问题就可以变成背包问题,我们拥有一个容量为石头质量总和一半的背包,那么只要知道这个背包最大能放入最多多重的石头堆即可。
class Solution {
public:
int lastStoneWeightII(vector<int>& stones) {
int sum = 0;
for(int i=0;i<stones.size();i++)
sum+=stones[i];
vector<int> dp(1501,0);
for(int i=0;i<stones.size();i++)
{
for(int j=sum/2;j>=stones[i];j--)
{
dp[j]=max(dp[j],stones[i]+dp[j-stones[i]]);
}
}
return sum-dp[sum/2]-dp[sum/2];
}
};
2.目标和
1.dp[j]:背包j容量所能达到要求的种类个数
2.dp[i]为i容量下的种类个数,其实有i种可能:当质量为1的物品放进去dp[i-1]有几种,当质量为2的物品放进去dp[i-2]有几种...当质量为i-1的物品放进去dp[1]有几种,这些情况相加。那么我们知道所谓的条件就是:dp[j] += dp[j - nums[i]];
3.初始化,dp[0]=1;因为dp[1]条件是dp[0]推出来的,如果dp[0]为0,后面都会变为0。
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
int sum = 0;
for (int i = 0; i < nums.size(); i++)
sum += nums[i];
if ((sum + target) % 2 == 1 || sum < abs(target))
return 0;
int num = (sum + target) / 2;
vector<int> dp(20001, 0);
dp[0] = 1;
for (int i = 0; i < nums.size(); i++)
{
for (int j = num; j >= nums[i]; j--)
{
dp[j] += dp[j - nums[i]];
}
}
return dp[num];
}
};
3.一和零
1.由于想要根据 子集中 最多 有
m
个0
和n
个1
来判断得到的子集最大数。那么我们能清楚所谓的背包容量由之前的一个维度,变为了两个维度。想要同时判断0和1的个数情况来求。所以dp数组也需要二维或者使用三维。2.dp[i][j]:i个0,j个1的情况下,对应的最多子集是多少个。
3.循环,在以前的背包容量为一个维度时,循环有两层:物件和容量;现在的容量为两个维度,那么循环有三层:物件和两个容量。
4.dp条件为:面对一个string时,我们可以得到它对应的num0和num1,dp[i][j]数组在上一次的dp[i][j]和当前的dp[i-num0][j-num1]+1)中得到较大的值,dp[i][j]=max(dp[i][j],dp[i-num0][j-num1]+1);
class Solution {
public:
int findMaxForm(vector<string>& strs, int m, int n) {
vector<vector<int>>dp(m+1,vector<int>(n+1,0));
for(auto e:strs)
{
int num0 = 0,num1 = 0;
for(auto f:e)
{
if(f=='0')
num0++;
else
num1++;
}
for(int i=m;i>=num0;i--)
{
for(int j=n;j>=num1;j--)
dp[i][j]=max(dp[i][j],dp[i-num0][j-num1]+1);
}
}
return dp[m][n];
}
};