题目
给定一个由正整数组成且不存在重复数字的数组,找出和为给定目标正整数的组合的个数。
示例:
nums = [1, 2, 3] target = 4
所有可能的组合为: (1, 1, 1, 1) (1, 1, 2) (1, 2, 1) (1, 3) (2, 1, 1) (2, 2) (3,
1)请注意,顺序不同的序列被视作不同的组合。
因此输出为 7。
思路
这题很明显就是排列问题,再次强调一下,组合不考元素先后顺序,排列考虑元素先后顺序
动规五部曲:
- 确定dp数组和下标含义
dp[i]
表示凑成目标正整数 i 的排列个数为dp[i]
- 确定递推公式
dp[i]
(考虑了nums[j]
)可以由dp[i-nums[j]]
(不考虑nums[j]
)推导出来
求满背包有几种方法,递推公式一般都是dp[i] += dp[i - nums[j]]
- dp数组初始化
根据递推公式,dp[0]
要初始化为dp[0] = 1
,这样递归其他dp[i]
的时候才会有数值基础,对于下标非0的dp[i]
初始化为0,这样才不会影响累加所有的dp[i - nums[j]]
- 确定遍历顺序
个数不限使用->完全背包
求的是排列数->外层for遍历背包容量,内层for遍历物品(和正常的两个for循环顺序相反) - 举例推导dp数组
以nums = [1,2,3],target = 4为例
总结:
求装满背包有几种方式,递推公式都是一样的,关键在于遍历顺序,是求组合数还是排列数
java代码如下:
class Solution {
public int combinationSum(int[] nums, int target){
int[] dp = new int[target+1];
dp[0] =1;
for(int i = 0; i <= target; i++){//求排列数,先遍历背包容量
for(int j = 0; j < nums.length; j++){//再遍历物品,而且是完全背包,要正向遍历
if(i >= nums[j]){//如果背包容量能装下当前物品,即背包容量大于等于物品重量
dp[i] += dp[i - nums[j]];
}
}
}
return dp[target];
}
}