一、题目描述
给你一个由 不同 整数组成的数组 nums ,和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。
题目数据保证答案符合 32 位整数范围。

提示:
1 <= nums.length <= 200
1 <= nums[i] <= 1000
nums 中的所有元素 互不相同
1 <= target <= 1000
二、解题思路
注意分析,本题虽然说的是组合,但是不同的序列被视为不同的组合,所以这里其实求的是排列数,这与我的57_零钱兑换II中组合问题不同(关于组合还是排列问题在57_零钱兑换II有介绍)。
动规五部曲:
第一步:确定dp数组以及下标的含义
dp[i]: 凑成⽬标正整数为i的排列个数为dp[i]
第二步:确定递推公式
dp[i] += dpp[i-nums[j]]
在57_零钱兑换II有详细介绍关于完全背包问题的递推
第三步:dp数组如何初始化
动态规划的边界是dp[0]=1。只有当不选取任何元素时,元素之和才为 0,因此只有 1 种方案。
第四步:确定遍历顺序
个数可以不限使⽤,说明这是⼀个完全背包。得到的集合是排列,说明需要考虑元素之间的顺序。
本题要求的是排列,那么这个for循环嵌套的顺序可以有说法了。
在我的LeetCode题目:57_零钱兑换II中就已经讲过了。
-
如果求组合数就是外层for循环遍历物品,内层for遍历背包。
-
如果求排列数就是外层for遍历背包,内层for循环遍历物品。
如果把遍历nums(物品)放在外循环,遍历target的作为内循环的话,举⼀个例⼦:计算dp[4]的时候,结果集只有 {1,3} 这样的集合,不会有{3,1}这样的集合,因为nums遍历放在外层,3只能出现在1后⾯!所以本题遍历顺序最终遍历顺序:target(背包)放在外循环,将nums(物品)放在内循环,内循环从前到后遍历。
代码如下:
for(int i=0; i<=target; i++){ //遍历背包
for(int j=0; j<nums.length; j++){ //遍历物品
if(i-nums[j]>=0){
dp[i] += dp[i-nums[j]];
}
}
}
第五步:举例来推导dp数组

三、代码演示
class Solution {
public int combinationSum4(int[] nums, int target) {
//定义dp
int[] dp = new int[target+1];
//dp初始化
dp[0] = 1;
//组合问题:先遍历背包再遍历物品
for(int i=0; i<=target; i++){ //遍历背包
for(int j=0; j<nums.length; j++){ //遍历物品
if(i-nums[j]>=0){
dp[i] += dp[i-nums[j]];
}
}
}
return dp[target];
}
}
该博客介绍了如何运用动态规划解决寻找数组中元素组合成特定目标值的排列问题。文章详细阐述了解题思路,包括确定dp数组的意义、递推公式、初始化dp数组、遍历顺序,并给出了具体的代码实现。此外,还强调了排列与组合问题的区别,并通过实例解释了dp数组的推导过程。
31万+

被折叠的 条评论
为什么被折叠?



