代码随想录算法训练营第四十五天
1049. 最后一块石头的重量 II
题目链接:1049. 最后一块石头的重量 II
将所有石头分成2组,两组的重量尽可能相等,差值最小。
计算石头总重,再除以2就是目标重量,求要达到该重量能装的石头的最大价值(重量)。
- 确定dp数组以及下标的含义:j为背包的最大容量,dp[j]达到j重量能装的石头的最大价值(重量)
- 确定递推公式:dp[j] = max(dp[j],dp[j-nums[i]]+nums[i])
- dp数组如何初始化:容量为0,价值(重量)为0。dp[0] = 0;
- 确定遍历顺序:从大到小遍历
- 打印dp数组。
class Solution {
public:
int lastStoneWeightII(vector<int>& stones) {
int sum = 0;
for (int& num : stones) {
sum += num;
}
int target = sum / 2;
vector<int> dp(target + 1, 0);
dp[0] = 0;
for (int i = 0; i < stones.size(); i++) {
for (int j = target; j >= stones[i]; j--) {
dp[j] = max(dp[j], dp[j - stones[i]] + stones[i]);
}
}
int result = sum - dp[target] - dp[target];
return result;
}
};
494. 目标和
题目链接:494. 目标和
将所有数字分成2组P,N,P组前面是+,N组前面是-。数组内所有元素的和sum=P+N,target=P-N。P=(sum+target)/2。问题转换为数组内满足和为P有多少种组合。
- 确定dp数组以及下标的含义:j为背包的最大容量,dp[j]当容量为j有几种组合方式
- 确定递推公式:dp[j]=dp[j]+dp[j-nums[i]],不放当前数字组成目标值的种类+必须放当前数字组成目标值的种类(为了保证一定放这个值,就要把需要的容量腾出来)
- dp数组如何初始化:容量为0,有一种放法,dp[0] = 1;
- 确定遍历顺序:从大到小遍历
- 打印dp数组。
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
int sum = 0;
for (int& num : nums) {
sum += num;
}
if ((sum + target) % 2 == 1 || sum < target)//这两种情况无解,返回0
return 0;
int s =(sum + target) / 2;
if(s<0)return 0;//这种情况无解返回0
vector<int> dp(s+1,0);
dp[0]=1;
for(int &num:nums){
for(int j = s;j>=num;j--){
dp[j]+=dp[j-num];
}
}
return dp[s];
}
};
474.一和零
题目链接:474.一和零
- 确定dp数组以及下标的含义:dp[i][j]表示有i个0,j个1,的背包,装满后的最大价值(每个字符串的价值为1,装满时最大字符串个数就等于最大价值)
- 确定递推公式:dp[i][j] = max(dp[i][j], dp[i - x_0][j - y_1] + 1);不换当前字符串的价值和换上当前字符串的价值中取较大。
- dp数组如何初始化:容量为0,价值为0。dp[0]=0
- 确定遍历顺序:从大到小遍历
- 打印dp数组。
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& str : strs) {
int x_0 = 0;
int y_1 = 0;
for (auto& c : str) {
if (c == '0')
x_0++;
else
y_1++;
}
for (int i = m; i >= x_0; i--) {
for (int j = n; j >= y_1; j--) {
dp[i][j] = max(dp[i][j], dp[i - x_0][j - y_1] + 1);
}
}
}
return dp[m][n];
}
};