给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
示例 1:
输入:nums = [1,5,11,5]
输出:true
解释:数组可以分割成 [1, 5, 5] 和 [11] 。
示例 2:
输入:nums = [1,2,3,5]
输出:false
解释:数组不能分割成两个元素和相等的子集。
cpp
bool canPartition(int* nums, int numsSize) {
int sum = 0;
for(int i=0;i<numsSize;i++){
sum+=nums[i];
}
int target = sum/2;
if(sum%2!=0)
return false;
bool* dp = (bool*)malloc(sizeof(bool)*(target+1));//覆盖0->target所有情况
//dp[i]:可以从数组中取出元素和 = i吗?
dp[0] = true;
for(int i=1;i<=target;i++){
dp[i] = false;
}
//dp[target]表示能从数组中选出元素和为target
// bool choose = dp[target-nums[i]];//物品遍历到nums[i]且选择这个物品,那dp[target]取决于dp[target-nums[i]]了
//bool notchoose = dp[target]//不选nums[i]
for(int i=0;i<numsSize;i++){
for(int j=target;j>=nums[i];j--){
dp[j] = dp[j] || dp[j-nums[i]];
}
}
return dp[target];
}
初始状态(处理任何元素前)
dp 数组长度 = 12(0~11),初始值:dp = [true, false, false, false, false, false, false, false, false, false, false, false](只有 dp 0=true,其余都是 false)
第一轮:处理第一个元素 current_num=1
遍历 j 的顺序:j=11 → 10 → 9 → ... → 2 → 1(倒序)逐个处理每个 j,记录 dp 变化:
表格
| j 值 | not_choose(不选 1) | choose(选 1,即 dp j-1) | dp j 更新后 | 关键说明 |
|---|---|---|---|---|
| 11 | false | dp10=false | false | 无变化 |
| 10 | false | dp9=false | false | 无变化 |
| 9 | false | dp8=false | false | 无变化 |
| 8 | false | dp7=false | false | 无变化 |
| 7 | false | dp6=false | false | 无变化 |
| 6 | false | dp5=false | false | 无变化 |
| 5 | false | dp4=false | false | 无变化 |
| 4 | false | dp3=false | false | 无变化 |
| 3 | false | dp2=false | false | 无变化 |
| 2 | false | dp1=false | false | 无变化 |
| 1 | false | dp0=true | true | 唯一更新 |
本轮结束后 dp 数组 :dp = [true, true, false, false, false, false, false, false, false, false, false, false]→ 此时 dp 11 还是 false!因为只处理了 1,凑不出 11。
第二轮:处理第二个元素 current_num=5
遍历 j 的顺序:j=11 → 10 → ... → 5(j≥5)逐个处理:
表格
| j 值 | not_choose(不选 5) | choose(选 5,即 dp j-5) | dp j 更新后 | 关键说明 |
|---|---|---|---|---|
| 11 | false | dp6=false | false | 无变化 |
| 10 | false | dp5=false | false | 无变化 |
| 9 | false | dp4=false | false | 无变化 |
| 8 | false | dp3=false | false | 无变化 |
| 7 | false | dp2=false | false | 无变化 |
| 6 | false | dp1=true | true | 选 5+1=6 |
| 5 | false | dp0=true | true | 选 5=5 |
本轮结束后 dp 数组 :dp = [true, true, false, false, false, true, true, false, false, false, false, false]→ dp 11 依然 false!但 dp 5、dp 6 变成 true(为后续铺路)。
第三轮:处理第三个元素 current_num=11
遍历 j 的顺序:j=11(只有 j≥11,所以只遍历 j=11)处理:
表格
| j 值 | not_choose(不选 11) | choose(选 11,即 dp j-11) | dp j 更新后 | 关键说明 |
|---|---|---|---|---|
| 11 | false | dp0=true | true | 选 11=11 |
本轮结束后 dp 数组 :dp = [true, true, false, false, false, true, true, false, false, false, false, true]→ 终于!dp 11 变成 true 了。