组合总数
注: 写这篇博客只是觉得自己记忆力不行,这道题很典型,剪枝实现,写成博客也只是为了每次看到能触发记忆点,提醒提醒自己。
题目描述:
- 题目链接:https://leetcode-cn.com/problems/combination-sum
- 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
- candidates 中的数字可以无限制重复被选取。
说明:
- 所有数字(包括 target)都是正整数。
- 解集不能包含重复的组合。
代码实现
class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
dfs(candidates,0,target,new ArrayList<Integer>());
return result;
}
private List<List<Integer>> result=new ArrayList();
public void dfs(int[]candidates,int index,int target,List<Integer>list){
if(target<0){
return;
}
if(target==0){
result.add(new ArrayList<Integer>(list));
}else{
/*
* 设置索引index,并让i从index开始,是为了在凑target的时候能够避免重复组合的出现
*/
for(int i=index;i<candidates.length;i++){
list.add(candidates[i]);
dfs(candidates,i,target-candidates[i],list);
list.remove(list.size()-1);
}
}
}
}
题目变体:求数字和为target有多少中组合
这则可以使用动态规划的方式来做,把题目看作一个揹包问题:
- i:代表可以使用的数字个数
- j:代表当前所求的数字和target
public static int combinationSum(int[] candidates, int target) {
Arrays.sort(candidates);
int n=candidates.length;
int[][]dp=new int[n+1][target+1];
for(int i=1;i<=n;i++){
for(int j=0;j<=target;j++){
if(j>=candidates[i-1])
if(j==candidates[i-1]){
//j==candidates[i-1]则代表当前目标和刚好等于candidates中的一个值,则dp[i][j]的值分为两部分:
//a. 由 包含 candidates[i-1]的数字组合构成,其实就只有1种可能,即candidates[i-1] 本身
//b. 由不包含candidates[i-1]元素的数字组合构成,即dp[i-1][j].
dp[i][j]=dp[i-1][j]+1;
}else
dp[i][j]=dp[i-1][j]+dp[i][j-candidates[i-1]];
else{
dp[i][j]=dp[i-1][j];
}
}
}
return dp[n][target];
}