【温故知新】`416. 分割等和子集`01背包🎒问题存在解-动态规划实现

861 阅读2分钟

题目描述

给你一个 只包含正整数 的 非空 数组 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… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路

image.png

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背包🎒问题最大解-动态规划实现

【温故知新】494. 目标和 表达式转化为01背包🎒问题-动态规划实现

【温故知新】1049. 最后一块石头的重量 II 最小重量转化为01背包🎒问题最大解-动态规划实现