给你一个 只包含正整数 的 非空 数组 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 | dp[10]=false | false | 无变化 |
| 10 | false | dp[9]=false | false | 无变化 |
| 9 | false | dp[8]=false | false | 无变化 |
| 8 | false | dp[7]=false | false | 无变化 |
| 7 | false | dp[6]=false | false | 无变化 |
| 6 | false | dp[5]=false | false | 无变化 |
| 5 | false | dp[4]=false | false | 无变化 |
| 4 | false | dp[3]=false | false | 无变化 |
| 3 | false | dp[2]=false | false | 无变化 |
| 2 | false | dp[1]=false | false | 无变化 |
| 1 | false | dp[0]=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 | dp[6]=false | false | 无变化 |
| 10 | false | dp[5]=false | false | 无变化 |
| 9 | false | dp[4]=false | false | 无变化 |
| 8 | false | dp[3]=false | false | 无变化 |
| 7 | false | dp[2]=false | false | 无变化 |
| 6 | false | dp[1]=true | true | 选 5+1=6 |
| 5 | false | dp[0]=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 | dp[0]=true | true | 选 11=11 |
本轮结束后 dp 数组 :dp = [true, true, false, false, false, true, true, false, false, false, false, true]→ 终于!dp [11] 变成 true 了。