1 題目描述
給定一個無重複元素的數組 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]
]
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/combination-sum
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
2 解題思路
- 方法:回溯法+剪枝
思路:根據示例 1:輸入: candidates = [2,3,6,7],target = 7。
候選數組裏有 2 ,如果找到了 7 - 2 = 5 的所有組合,再在之前加上 2 ,就是 7 的所有組合;
同理考慮 3,如果找到了 7 - 3 = 4 的所有組合,再在之前加上 3 ,就是 7 的所有組合,依次這樣找下去;
上面的思路就可以畫成下面的樹形圖。
說明:
藍色結點表示:嘗試找到組合之和爲該數的所有組合,怎麼找呢?逐個減掉候選數組中的元素即可;
- 以 target = 7 爲根結點,每一個分支做減法;
- 減到 0 或者負數的時候,到了葉子結點;
- 減到 0 的時候結算,這裏 “結算” 的意思是添加到結果集;
- 從根結點到葉子結點(必須爲 0)的路徑,就是題目要我們找的一個組合。
代碼來自評論區,感覺大佬的代碼還是有待於學習,後面會認真學習觀看哦
作者:liweiwei1419
鏈接:https://leetcode-cn.com/problems/combination-sum/solution/hui-su-suan-fa-jian-zhi-python-dai-ma-java-dai-m-2/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
3 解決代碼
- 方法:回溯法+剪枝《不排序Java代碼》–評論區
class Solution {
//全局變量,格式根據結果的需求來確定
List<List<Integer>> res = new ArrayList<>();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
if(candidates == null){
return res;
}
dfs(target, 0, new Stack<Integer>(), candidates);
return res;
}
//dfs函數,要注意傳的參數
public void dfs(int target, int index, Stack<Integer> stack, int[] candidates){
//如果等於0的話,就是我們要的結果,將stack添加add到結果集res後面
if(target == 0){
res.add(new ArrayList<> (stack));
return;
}
//主要內容,遍歷,index爲本分支上一節點減數的下標
for(int i = index; i < candidates.length; i++){
if(candidates[i] <= target){
//小於的話就入棧,大的就不要了,有剪枝效果
stack.push(candidates[i]);
//目標值減去元素值
dfs(target - candidates[i], i, stack, candidates);
//操作的最後,每次回溯都要將上次最後加入的元素刪掉
stack.pop();
}
}
}
}
- 方法:回溯法+剪枝《排序Java代碼》–
public class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> res = new ArrayList<>();
int len = candidates.length;
// 排序是爲了提前終止搜索
Arrays.sort(candidates);
dfs(candidates, len, target, 0, new ArrayDeque<>(), res);
return res;
}
/**
* @param candidates 數組輸入
* @param len 輸入數組的長度,冗餘變量
* @param residue 剩餘數值
* @param begin 本輪搜索的起點下標
* @param path 從根結點到任意結點的路徑
* @param res 結果集變量
*/
private void dfs(int[] candidates,
int len,
int residue,
int begin,
Deque<Integer> path,
List<List<Integer>> res) {
if (residue == 0) {
// 由於 path 全局只使用一份,到葉子結點的時候需要做一個拷貝
res.add(new ArrayList<>(path));
return;
}
for (int i = begin; i < len; i++) {
// 在數組有序的前提下,剪枝
if (residue - candidates[i] < 0) {
break;
}
path.addLast(candidates[i]);
dfs(candidates, len, residue - candidates[i], i, path, res);
path.removeLast();
}
}
}