【温故知新】`377. 组合总和 Ⅳ` 完全背包问题排列解-动态规划实现

1,081 阅读1分钟

题目描述

给你一个由 不同 整数组成的数组 nums ,和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。

题目数据保证答案符合 32 位整数范围。

 

示例 1:

输入:nums = [1,2,3], target = 4 输出:7 解释: 所有可能的组合为: (1, 1, 1, 1) (1, 1, 2) (1, 2, 1) (1, 3) (2, 1, 1) (2, 2) (3, 1) 请注意,顺序不同的序列被视作不同的组合。 示例 2:

输入:nums = [9], target = 3 输出:0  

提示:

1 <= nums.length <= 200 1 <= nums[i] <= 1000 nums 中的所有元素 互不相同 1 <= target <= 1000  

进阶:如果给定的数组中含有负数会发生什么?问题会产生何种变化?如果允许负数出现,需要向题目中添加哪些限制条件?

来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/co… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路

image.png 完全背包🎒问题典型特点:数量不限;

  • 定义dp[j]含义:dp[j]代表组成目标整数j的元素排列个数总和;
  • 递推公式:
    • dp[j]可以由dp[j-nums[i]]加上dp[j]上次推导结果
    • 将背包填满的递推公式:dp[j]+=dp[j-nums[i]]
  • 初始化:
    • 从题意入手,dp[0]代表组成目标整数位0的排列个数1;
    • dp[0]=1,没有意义,但是推导的基础;
    • 下标非0的dp[j],应初始化为0,这样在计算dp[j]+dp[j-[i]]不会影响到dp的初始计算;
  • 遍历物品还是背包容量的for循环顺序,是否影响结果; 假设nums=[1,2],先遍历容量再遍历物品的代码:
     for(let j=0;j<=amount;j++){ // 先遍历容量
       for(let i=0;i<nums.length;i++){  // 后遍历物品
          if(j-coins[i]>=0){
              dp[j]+=dp[j-coins[i]]
            }
        }
      } 
    

这时候计算出来的每一个容量dp[j],都包含{1,2}和{2,1}这样的排列之和的计算;

总结

在求装满背包🎒问题顺序关键在于:

如果求组合数就是外层for循环遍历物品,内层for遍历背包。 如果求排列数就是外层for遍历背包,内层for循环遍历物品。

代码

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var combinationSum4 = function(nums, target) {
   // 动态规划4步曲
   // 1、确认dp[j]的含义:凑足容量为j的排列个数为dp[j]
   // 1、初始化dp
  let  dp= new Array(target+1).fill(0);
       dp[0]=1;
    // 2、遍历顺序;
    for(let j=1;j<=target;j++){ // 先遍历容量
        // 后遍历物品;
        for(let i=0;i<nums.length;i++){
            if(j>=nums[i]){
                dp[j]+=dp[j-nums[i]]
            }
            
        }//

    }// end of for 
    console.log(dp)
    return dp[target]

};

完全背包🎒问题

【温故知新】322. 零钱兑换 动画演示-完全背包问题最小解-动态规划实现

【温故知新】518. 零钱兑换 II 完全背包问题组合解-动态规划实现