416. 分割等和子集(0-1背包)
难度中等
给你一个 只包含正整数 的 非空 数组 nums
。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
示例 1:
输入:nums = [1,5,11,5] 输出:true 解释:数组可以分割成 [1, 5, 5] 和 [11] 。
示例 2:
输入:nums = [1,2,3,5] 输出:false 解释:数组不能分割成两个元素和相等的子集。
首先回忆一下背包问题大致的描述是什么:
给你一个可装载重量为 W
的背包和 N
个物品,每个物品有重量和价值两个属性。其中第 i
个物品的重量为 wt[i]
,价值为 val[i]
,现在让你用这个背包装物品,最多能装的价值是多少?
那么对于这个问题,我们可以先对集合求和,得出 sum
,把问题转化为背包问题:
给一个可装载重量为 sum / 2
的背包和 N
个物品,每个物品的重量为 nums[i]
。现在让你装物品,是否存在一种装法,能够恰好将背包装满?
class Solution: def canPartition(self, nums: List[int]) -> bool: sums = sum(nums) if sums%2==1: return False sums = sums//2 dp = [0] * (sums+1) for i in range(len(nums)): for j in range(sums+1)[::-1]: if j - nums[i]>=0: dp[j] = max(dp[j],dp[j-nums[i]]+nums[i]) return dp[sums]==sums
class Solution { public: bool canPartition(vector<int>& nums) { int sum = 0; for(auto i : nums) { sum+=i; } if(sum%2==1) return false; sum = sum/2; int n = nums.size(); vector<vector<int>> dp = vector<vector<int>>(n+1,vector<int>(sum+1,0)); for(int i = 1; i < n+1;i++) { for(int j = 1; j < sum+1;j++) { if (j-nums[i-1]>=0) { dp[i][j] = max(dp[i-1][j], dp[i-1][j-nums[i-1]] + nums[i-1]); } else { dp[i][j] = dp[i-1][j]; } } } return dp[n][sum]==sum; } };
class Solution { public: bool canPartition(vector<int>& nums) { int sum = 0, n = nums.size(); for (int num : nums) sum += num; if (sum % 2 != 0) return false; int target = sum / 2; vector<int> dp(target + 1, 0); for (int i = 1; i <=n; i++) for (int j = target; j >= 0; j--) if (j - nums[i-1] >= 0) { dp[j] = max(dp[j],dp[j - nums[i-1]]+nums[i-1]); } else { dp[j] = dp[j]; } return dp[target]==target; } };
class Solution { public: bool canPartition(vector<int>& nums) { int sum = 0; int max_num =0; for(auto i : nums) { sum+=i; max_num = max(max_num,i); } if(sum%2==1) return false; if (max_num>sum/2) return false;//[1,2,5] sum = sum/2; int n = nums.size(); vector<vector<bool>> dp = vector<vector<bool>>(n+1,vector<bool>(sum+1,false)); //前i个背包,正好装满j的容量 //dp[..][0] = true for(int i = 0;i < n+1;i++) { dp[i][0] = true; } for(int i = 1; i < n+1;i++) { for(int j = 1; j < sum+1;j++) { if (j-nums[i-1]>=0) { dp[i][j] = dp[i-1][j] || dp[i-1][j-nums[i-1]]; } else { dp[i][j] = dp[i-1][j]; } } } return dp[n][sum]; } };