题目描述
给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
示例 1:
输入:nums = [1,5,11,5] 输出:true 解释:数组可以分割成 [1, 5, 5] 和 [11] 。
示例 2:
输入:nums = [1,2,3,5] 输出:false 解释:数组不能分割成两个元素和相等的子集。
提示:
1 <= nums.length <= 200 1 <= nums[i] <= 100
来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/pa… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路
01背包🎒问题-存在性解
将题目转换为01背包🎒问题是本题难点; 题目理解:
-
是否可以将数组元素分割成两个子集,numsA numsB 且res=numsA-numsB;res===0;
-
同理是求 sum=numsA+numsB; 是否存在一个子集,其和为weight=sum/2;
动态规划四部曲:
- 确定dp数组含义:
- dp[j]是否存在子集其和为j;false/true
- 确定递推公式:
- 假设子集加num[i],和等于j,满足假设,只要dp[j - nums[i]]存在
- 假设子集不加num[i],和等于j,满足假设,只要dp[j]存在
- 因此递推公式为:
- dp[j]=dp[j]||dp[j-nums[i]]
- dp数组初始化: * dp[0]=true;不需要任何元素,题目非空数组,仅作为递推基础;
- 确定遍历顺序
- 01背包🎒问题:
- 01背包一定是外层for循环遍历物品,内层for循环遍历背包容量且从后向前遍历!
代码
/**
* @param {number[]} nums
* @return {boolean}
*/
var canPartition = function(nums) {
let sum=0;
for(let item of nums){
sum+=item;
}
if(sum&1===1){ // 奇偶判断,奇数一定无法进行等分;
return false;
}
let weight=Math.floor(sum/2);
let dp=new Array(weight+1).fill(false);
dp[0]=true;
for(let i=0;i<nums.length;i++){
for(let j=weight;j>=nums[i];j--){
dp[j]=dp[j]||dp[j-nums[i]]
}
}// end of for ;
console.log(dp,dp[weight]);
return dp[weight]
};
完全背包🎒问题
【温故知新】322. 零钱兑换
动画演示-完全背包问题最小解-动态规划实现
【温故知新】518. 零钱兑换 II
完全背包问题组合解-动态规划实现
【温故知新】377. 组合总和 Ⅳ
完全背包问题排列解-动态规划实现
01背包🎒问题
【温故知新】474. 一和零
01背包🎒问题最大解-动态规划实现