算法:
相比于上一题,数组candidates有重复元素,而要求不能有重复的组合,所以相对于39.组合总和 (opens new window)难度提升了不少。
如何去重?
先把candidates排序,让重复的元素都在一起
单层递归时,
if ( i > startindex && candidates[i] == candidates[i - 1] ) {
continue;
}
调试过程:
class Solution {
//全局变量path和result
List<List<Integer>> result = new LinkedList<>();
List<Integer> path = new LinkedList<>();
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
//`int[] candidates` 表示一个整数数组,可以包含多个整数元素。你可以通过`candidates[0]`、`candidates[1]`等方式访问数组中的不同元素。
//int target` 则表示一个单独的整数变量,只能存储一个整数值。
if (candidates == null) return result;
Arrays.sort(candidates);
backtracking(candidates, target, 0, 0);
return result;
}
void backtracking(int[] candidates, int target, int sum, int startindex){
//确定终止条件
if (sum > target) return;
if (sum == target) {
result.add(new LinkedList(path));
return;
}
//单层递归逻辑
for (int i = startindex; i < candidates.length && sum <= target; i++){
if (i > startindex && candidates[i] == candidates[i-1]) continue;
path.add(candidates[i]);
sum += candidates[i];
backtracking(candidates, target, sum, i);
//回溯
sum -= candidates[i];
path.removeLast();
}
}
}
原因:没去重
单层递归中,应该改成i+1了
backtracking(candidates, target, sum, i+1);
正确代码:
class Solution {
//全局变量path和result
List<List<Integer>> result = new LinkedList<>();
List<Integer> path = new LinkedList<>();
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
//`int[] candidates` 表示一个整数数组,可以包含多个整数元素。你可以通过`candidates[0]`、`candidates[1]`等方式访问数组中的不同元素。
//int target` 则表示一个单独的整数变量,只能存储一个整数值。
if (candidates == null) return result;
//排序
Arrays.sort(candidates);
backtracking(candidates, target, 0, 0);
return result;
}
void backtracking(int[] candidates, int target, int sum, int startindex){
//确定终止条件
if (sum > target) return;
if (sum == target) {
result.add(new LinkedList(path));
return;
}
//单层递归逻辑
for (int i = startindex; i < candidates.length && sum <= target; i++){
//去重
if (i > startindex && candidates[i] == candidates[i-1]) continue;
path.add(candidates[i]);
sum += candidates[i];
backtracking(candidates, target, sum, i+1);
//回溯
sum -= candidates[i];
path.removeLast();
}
}
}
时间空间复杂度:
- 时间复杂度: O(n * 2^n),注意这只是复杂度的上界,因为剪枝的存在,真实的时间复杂度远小于此
- 空间复杂度: O(target)