回溯算法 + 剪枝
JDK 1.8新特性,可以对list集合去重,若算完再去重会超时,所以在深度优先遍历过程中就剪枝去重
result = result.stream().distinct().collect((Collectors.toList()));
Solution039
class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
int len = candidates.length;
List<List<Integer>> res = new ArrayList<>();
if (len == 0) {
return res;
}
// 排序是剪枝的前提
Arrays.sort(candidates);
Deque<Integer> path = new ArrayDeque<>();
dfs(candidates, 0, len, target, path, res);
return res;
}
private void dfs(int[] candidates, int begin, int len, int target, Deque<Integer> path, List<List<Integer>> res) {
// 由于进入更深层的时候,小于 0 的部分被剪枝,因此递归终止条件值只判断等于 0 的情况
if (target == 0) {
res.add(new ArrayList<>(path));
return;
}
for (int i = begin; i < len; i++) {
// 重点理解这里剪枝,前提是候选数组已经有序,
if (target - candidates[i] < 0) {
break;
}
path.addLast(candidates[i]);
dfs(candidates, i, len, target - candidates[i], path, res);
path.removeLast();
}
}
}
Solution040
class Solution {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
int length = candidates.length;
List<List<Integer>> result = new ArrayList<>();
if (length == 0) {
return result;
}
Arrays.sort(candidates);
Deque<Integer> path = new ArrayDeque<>();
dfs(candidates, target, 0, length, path, result);
return result;
}
public void dfs(int[] candidates, int target, int begin, int length, Deque<Integer> path, List<List<Integer>> result) {
if (target == 0) {
result.add(new ArrayList<>(path));
return;
}
for (int i = begin; i < length; ++i) {
//大剪枝
//target为负值,直接排除这种情况
if (target - candidates[i] < 0) {
break;
}
//小剪枝
//i > begin表示在数组起始位置之后选择,且选择的第i个第i - 1个是一样的数字,就剪枝
//continue表示还可以选择后边不一样的数字
if (i > begin && candidates[i] == candidates[i - 1]) {
continue;
}
path.addLast(candidates[i]);
dfs(candidates, target - candidates[i], i + 1, length, path, result);
path.removeLast();
}
}
}
来源:LeetCode——liweiwei1419