代码随想录算法训练营第四十五天
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)//这两种情况无解,返回0return 0;int s =(sum + target) / 2;if(s<0)return 0;//这种情况无解返回0vector<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++;elsey_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];}
};