416. 分割等和子集
题目链接:力扣
题目要求:
给你一个 只包含正整数 的 非空 数组 nums
。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
示例 1:
输入:nums = [1,5,11,5] 输出:true 解释:数组可以分割成 [1, 5, 5] 和 [11] 。
1 <= nums.length <= 200
1 <= nums[i] <= 100
总结:
这题可以把其抽象为背包问题,如果数组能将大小为数组总和一半的背包正好装满,值也为数组总和一半,说明可以分割成两个子集,这里数组的每个元素代表每个商品,其值既是大小,又是价值。用一维数组来实现背包问题,d[j]代表背包大小为j,能装的最大价值,一维数组在内循环之所以用逆序遍历,是因为如果正序,会把原理上上一层的数据给更改为新的数值,每个dp[j]都是由上一层的值来确定的,这里因为省去了数组的维数,每个层的数据共享了一层的位置,所以需要逆序遍历,这样上一层的数据再利用的时候才不会被修改。
class Solution {
public boolean canPartition(int[] nums) {
int n = nums.length;
int sum =0;
for(int num : nums){
sum += num;
}
//如果数组总和为奇数,则不能分出两个值一样的子集
if(sum % 2 == 1){
return false;
}
//dp[j]代表大小为j的背包,能装的最大价值为多少(这里最大价值即是数值总和)
int target = sum / 2;
int[] dp = new int[target+1];
for(int i = 0;i < n;i++){
for(int j = target;j >= nums[i];j--){
dp[j] = Math.max(dp[j],dp[j-nums[i]]+nums[i]);
}
}
return dp[target] == target;
}
}