Leetcode 416. 分割等和子集 (动态规划-01背包问题)
原题链接:Leetcode 416. 分割等和子集
下面参考官解:分割等和子集
这个题目的隐藏含义是:判断是否可以从数组中选出一些数字,使得这些数字的和等于整个数组的元素和的一半
创建二维数组 dp,包含 n 行 target+1 列,其中 dp[i][j] 表示从数组的 [0,i] 下标范围内选取若干个正整数(可以是 0 个),是否存在一种选取方案使得被选取的正整数的和等于 j。初始时,dp 中的全部元素都是 false。
初始化(很重要!!!):
- 前 i 个元素中如果不选取任何正整数,则他们的和等于 0 ,即存在这种情况 dp[i][0]=true
状态转移方程:
dp[i][j] = dp[i-1][j] || dp[i-1][j-nums[i-1]];
- 不选当前 i , 和为j ,则看是否有 dp[i-1][j]=true的情况
- 选当前 i , 和为j , 即看是否有 dp[i-1][j-nums[i-1]]=true的情况
- 用“或”连接这两种情况
class Solution {
public:bool canPartition(vector<int>& nums) {int n=nums.size();if(n==1) return false;int sum=0;int max_num=0;for(auto x:nums) {sum+=x;max_num=max(max_num,x);}if(sum%2!=0) return false;int target = sum/2;if(max_num>target) return false;// dp[i][j] 表示前i个元素的和是否可以==jvector<vector<bool>> dp(n+1,vector<bool>(target+1,false));for(int i=0;i<=n;i++){dp[i][0]=true;}for(int i=1;i<=n;i++){for(int j=1;j<=target;j++){dp[i][j]= dp[i-1][j];if(j>=nums[i-1]){dp[i][j] = dp[i][j] || dp[i-1][j-nums[i-1]];}}}return dp[n][target];}
};
空间优化:
class Solution {
public:bool canPartition(vector<int>& nums) {int n=nums.size();if(n==1) return false;int sum=0;int max_num=0;for(auto x:nums) {sum+=x;max_num=max(max_num,x);}if(sum%2!=0) return false;int target = sum/2;if(max_num>target) return false;// dp[j] 表示数组的子数组的和是否可以==jvector<bool> dp(target+1,false);dp[0]=true;for(int i=0;i<n;i++){for(int j=target;j>=nums[i];j--){dp[j] = dp[j] || dp[j-nums[i]];}}return dp[target];}
};