給定一個無重複元素的數組 candidates 和一個目標數 target ,找出 candidates 中所有可以使數字和爲 target 的組合。
candidates 中的數字可以無限制重複被選取。
說明:
- 所有數字(包括
target
)都是正整數。 - 解集不能包含重複的組合。
示例 1:
輸入: candidates =[2,3,6,7],
target =7
, 所求解集爲: [ [7], [2,2,3] ]
示例 2:
輸入: candidates = [2,3,5], target = 8,
所求解集爲:
[
[2,2,2,2],
[2,3,3],
[3,5]
]
去重複
在搜索的時候,需要設置搜索起點的下標 begin ,由於一個數可以使用多次,下一層的結點從這個搜索起點開始搜索;
在搜索起點 begin 之前的數因爲以前的分支搜索過了,所以一定會產生重複。
剪枝提速
如果一個數位搜索起點都不能搜索到結果,那麼比它還大的數肯定搜索不到結果,基於這個想法,我們可以對輸入數組進行排序,以減少搜索的分支;
排序是爲了提高搜索速度,非必要;
搜索問題一般複雜度較高,能剪枝就儘量需要剪枝。把候選數組排個序,遇到一個較大的數,如果以這個數爲起點都搜索不到結果,後面的數就更搜索不到結果了。
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque;
import java.util.List;
class Solution {
public static List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> list = new ArrayList<List<Integer>>();
Arrays.sort(candidates);
def(new ArrayDeque<>(), 0, 0, target, candidates, list);
return list;
}
/**
* @param candidates 數組輸入
* @param now 當前值
* @param target 目標值
* @param begin 本輪搜索的起點下標
* @param path 從根結點到任意結點的路徑
* @param list 結果集變量
*/
private static void def(Deque<Integer> path, int begin, int now ,int target, int[] candidates ,List<List<Integer>> list) {
if(now == target) {
list.add(new ArrayList<Integer>(path));
return;
}
for (int i = begin ; i < candidates.length ; i++) {
//剪枝
if(now + candidates[i] > target) {
break;
}
path.addLast(candidates[i]);
def(path , i ,now + candidates[i] ,target ,candidates ,list);
path.removeLast();
}
}
}