题目描述
给你一个由 不同 整数组成的数组 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… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路
完全背包🎒问题典型特点:数量不限;
- 定义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]
};