4.组合总和
思路:抽象成树结构,因为本题中的题目描述中写道,每次枚举的时候都是从自己开始,某一个数字能不能被选择关键在于candidates[i]+sum<=target,如果满足的话就可以添加进去。
回溯三部曲:
- 递归函数参数
public void dfs(int[] candidates,int start,int sum,int target){
}
- 递归终止条件
if(sum == target){
res.add(new ArrayList(path));
return ;
}
- 单层搜索的逻辑
for(int i = start;i<candidates.length&&candidates[i]+sum<=target;i++){
path.add(candidates[i]);
dfs(candidates,i,sum+candidates[i],target);
path.remove(path.size()-1);
}
代码实现:
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
Arrays.sort(candidates);
dfs(candidates,0,0,target);
return res;
}
public void dfs(int[] candidates,int start,int sum,int target){
if(sum == target){
res.add(new ArrayList(path));
return ;
}
for(int i = start;i<candidates.length&&candidates[i]+sum<=target;i++){
path.add(candidates[i]);
dfs(candidates,i,sum+candidates[i],target);
path.remove(path.size()-1);
}
}
}
5.组合总和II
思路:
- 先排序,让重复的元素都聚在一起
- 当我们枚举组合时,每一个数只能枚举一次,遇到重复的就跳过即可。
抽象成树结构
回溯三部曲:
- 递归函数参数
public void dfs(int[] nums, int start, int sum,int target){
}
- 递归终止条件
if(i > start && nums[i] == nums[i - 1]){
// 保证每一个数只能选一次
continue;
}
- 单层搜索的逻辑
for(int i = start; i < nums.length && sum + nums[i] <= target; i ++){
if(i > start && nums[i] == nums[i - 1]){
// 保证每一个数只能选一次
continue;
}
path.add(nums[i]);
dfs(nums, i + 1, sum + nums[i],target);// 下一次从i + 1开始
path.remove(path.size() - 1);
}
代码实现:
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
Arrays.sort(candidates);
dfs(candidates, 0, 0,target);
return res;
}
public void dfs(int[] nums, int start, int sum,int target){
if(sum == target){
res.add(new ArrayList(path));
return ;
}
for(int i = start; i < nums.length && sum + nums[i] <= target; i ++){
if(i > start && nums[i] == nums[i - 1]){
// 保证每一个数只能选一次
continue;
}
path.add(nums[i]);
dfs(nums, i + 1, sum + nums[i],target);// 下一次从i + 1开始
path.remove(path.size() - 1);
}
}
}
补充:
对于(2 2 3 和 3 2 2)是同一个组合,但不是同一个序列。
used[i-1]=0------树层去重
used[i-1]=1------树枝去重
6.组合总和III
思路:
k控制树的深度–递归的深度
n控制树的宽度–for循环的范围
代码实现:
class Solution {
List<List<Integer>> result = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();
public List<List<Integer>> combinationSum3(int k, int n) {
dfs(n,k,0,1);
return result;
}
public void dfs(int targetSum,int k,int sum,int startIndex){
//剪枝
if(sum>targetSum){
return;
}
//终止条件
if(path.size()==k){
if(sum==targetSum) result.add(new ArrayList<>(path));
return;
}
//单层逻辑
for(int i = startIndex; i <= 9 - (k - path.size()) + 1;i++){
path.add(i);
dfs(targetSum,k,sum+i,i+1);
path.removeLast();
}
}
}