组合总和
给定一个无重复元素的数组 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]
]
提示:
- 1 <= candidates.length <= 30
- 1 <= candidates[i] <= 200
- candidate中的每个元素都是独一无二的。 1 <= target <= 500
根据题目的描述可知,要求从候选数组中选择多个数字,使得它们之和等于给定的target。由于数组中元素无重复,因此需要考虑所有可能的组合形式,最后从中得到复合要求的结果。这是典型回溯思路的题目,解题之前首先需要明白回溯问题的三大核心要素:
- 选择列表:当前已经选择的数字,且它们之和不应该大于target
- 可选择列表:当前选择位置及之后位置数组的元素,由于题目中说明了数字可以无限制的重复选取,那么在选择完当前某位置元素后,下一次的选择仍然可以从当然位置开始,只要选择列表中的数字之和不大于target就可
- 终止条件:选择列表中数字之和等于target,这里我们使用减法,每次选择一个合法的数字后,target就减去相应的值,最后只需判断target是否为0即可
同时在枚举的过程中还需要剪枝,下面的两种情况下需要进行剪枝操作:
- 当前已经选到了数组的最后一个位置
- 当前位置的数组元素比target还要大
如果明白了上述的算法流程后,根据回溯问题的解题思路,代码就好写了。
Java解题代码:
class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> results = new LinkedList<>();
LinkedList<Integer> track = new LinkedList<>();
Arrays.sort(candidates);
if (candidates.length == 0 || candidates[0] > target){
return results;
}
dfs(track, candidates, target, results, 0);
results.forEach(System.out :: println);
return results;
}
private void dfs(LinkedList<Integer> track, int[] candidates, int target, List<List<Integer>> results, int start) {
if(target == 0){
results.add(new LinkedList<>(track));
return;
}
for (int i = start; i < candidates.length; i++) {
if (i == candidates.length || candidates[i] > target){
break;
}
// 做出选择
track.add(candidates[i]);
dfs(track, candidates, target - candidates[i], results, i);
track.removeLast();
}
}
}
Python解题代码:
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
if candidates == [] or min(candidates) > target:
return []
length = len(candidates)
results = []
def dfs(candidates, target, track):
if target == 0:
results .append(track.copy())
return
for i in range(len(candidates)):
if i == length or candidates[i] > target:
break
track.append(candidates[i])
# python中数组的切片很方便,这里就不再记录当前选择的位置i
dfs(candidates[i:], target - candidates[i], track)
track.pop()
candidates = sorted(candidates)
dfs(candidates, target, [])
return results