01背包题解
https://blog.csdn.net/qq_52934831/article/details/120102264?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163885949416780265422628%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=163885949416780265422628&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_v2~rank_v29-1-120102264.pc_v2_rank_blog_default&utm_term=DP&spm=1018.2226.3001.4450
Leetcode 416分割等和子集
地址
https://leetcode-cn.com/problems/partition-equal-subset-sum/
描述
思想
代码
class Solution {
public:
bool canPartition(vector<int>& nums) {
int n=nums.size(),m=0;
//求出所有正整数的和
for(auto x:nums) m+=x;
//假如m是奇数,说明没办法对半分,直接return false
if(m%2==1) return false;
//否则将数组对半分,每部分容量为m的一半
else m/=2;
vector<bool> f(m+1);
f[0]=true;
for(int i=1;i<nums.size();i++){
int x=nums[i];
for(int j=m;j>=x;j--){
//dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i]];
f[j]=f[j]||f[j-x];
}
}
return f[m];
}
};
Leetcode 494 目标和(01背包变形,offset偏移量的运用)
地址
https://leetcode-cn.com/problems/target-sum/submissions/
描述
思想
注释代码
//160 ms, 44.39%; 38.7 MB,7.40%
// y总讲解 二维解法:其中 f[i][j]中j的范围,设置为了[0, 2 * Offset]
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int S) {
// 由于题目里说数组里总和最多只有1000,所以只能做[-1000,+1000],如果S不在这个范围就直接返回
if (abs(S) > 1000) return 0; // S < -1000 || S > 1000
int n = nums.size(), Offset = 1000; // 因为有负数,所以这里用一个偏移量,所有的j放到f里都要加上这个偏移量
vector<vector<int>> f(n + 1, vector<int>(2 * Offset + 1));
f[0][0 + Offset] = 1; // 选0个数,总和也是0的情况(因为在f数组里所以加上了一个偏移量Offset)
for (int i = 1; i <= n; i ++ ) {
// 本来 j范围是[-Offset, Offset],加上偏移量之后变为[-Offset + Offset, Offset + Offset], 即[0, 2* Offset]
for (int j = 0; j <= 2 * Offset; j ++ ) {
// f[i][j] 第二维下标 的范围要在 [0, 2*Offset] 之内
// 注意:因为nums的下标是从0开始的,所以这里要用nums[i - 1]
// a[i]取正数,0 <= j - nums[i - 1] <= 2*Offset, 因为 j~[0, 2*Offset]且nums[i]非负,所以肯定满足右半边不等式
if (j - nums[i - 1] >= 0) // 只约束左半边不等式即可
f[i][j] += f[i - 1][j - nums[i - 1]];
// a[i]取负数,0 <= j + nums[i - 1] <= 2*Offset, 因为 j~[0, 2*Offset]且nums[i]非负,所以肯定满足 左半边不等式
if (j + nums[i - 1] <= 2 * Offset) // 只约束右半边不等式即可
f[i][j] += f[i - 1][j + nums[i - 1]];
}
}
return f[n][S + Offset]; // 在前n个数里选,总和是S的方案数
}
};
代码
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int s) {
int n=nums.size(),offset=1000;
//题目给出0 <= sum(nums[i]) <= 1000
if(abs(s)>offset) return 0;//一定不可能达到
vector<vector<int>> f(n+1,vector<int>(2*offset+1));
f[0][0+offset]=1;
for(int i=1;i<=n;i++){
for(int j=0;j<=2*offset;j++){
if(j-nums[i-1]>=0){
f[i][j]+=f[i-1][j-nums[i-1]];
}
if(j+nums[i-1]<=2*offset){
f[i][j]+=f[i-1][j+nums[i-1]];
}
}
}
return f[n][s+offset]; 在前n个数里选,总和是S的方案数
}
};