組合總數
注: 寫這篇博客只是覺得自己記憶力不行,這道題很典型,剪枝實現,寫成博客也只是爲了每次看到能觸發記憶點,提醒提醒自己。
題目描述:
- 題目鏈接: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];
}