力扣——回溯合集

3 篇文章 0 订阅
2 篇文章 0 订阅

1. 所有子集

题目:给定一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
在这里插入图片描述
题解:求子集,且互不相同,每次dfs可以选择取当前数字取还是不取,当执行到最后一个元素时,答案终止。

class Solution {
    List<List<Integer>> ans = new ArrayList<>();
    public void dfs(int[] nums, List<Integer> tmp,int i){
        if(i==nums.length){   
            ans.add(new ArrayList<Integer>(tmp));
            return;
        } 
        tmp.add(nums[i]);
        dfs(nums,tmp,i+1);
        tmp.remove(tmp.size()-1);
        dfs(nums,tmp,i+1);
    }
    public List<List<Integer>> subsets(int[] nums) {
        List<Integer> tmp = new ArrayList<>();
        dfs(nums,tmp,0);
        return ans;
    }
}

2. 子集 II

题目:给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。
在这里插入图片描述
题解:与上一道题不同,这道题有重复元素,所以需要保证在同一层的时候,有重复元素跳过

class Solution {
    List<List<Integer>> ans = new ArrayList<>();
    List<Integer> tmp = new ArrayList<>();
    public void dfs(int[] nums,int i){
        if(i==nums.length){
            ans.add(new ArrayList<Integer>(tmp));
            return;
        }
        tmp.add(nums[i]); 
        dfs(nums,i+1); //往下取,不在同一层,无须判重
        tmp.remove(tmp.size()-1);
        while(i+1<nums.length&&nums[i+1]==nums[i]) //取当前层的下一个不重复的数
            i++;
        dfs(nums,i+1);
    }
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        Arrays.sort(nums);
        dfs(nums,0);
        return ans;
    }
}

3. 含有 k 个元素的组合

题目:给定两个整数 n 和 k,返回 1 … n 中所有可能的 k 个数的组合。
在这里插入图片描述
题解:不含重复元素,与子集问题的入口不同

class Solution {
    List<List<Integer>> ans = new ArrayList<>();
    List<Integer> tmp = new ArrayList<>();
    public void dfs(int n,int k,int cur,int cnt){
        if(cur>n+1) return;
        if(cnt==k){
            ans.add(new ArrayList<Integer>(tmp));
            return;
        }
        tmp.add(cur);
        dfs(n,k,cur+1,cnt+1);
        tmp.remove(tmp.size()-1);
        dfs(n,k,cur+1,cnt);
    }
    public List<List<Integer>> combine(int n, int k) {
        dfs(n,k,1,0);
        return ans;
    }
}

4. 组合总和

题目:给定一个无重复元素的正整数数组 candidates 和一个正整数 target ,找出 candidates 中所有可以使数字和为目标数 target 的唯一组合。candidates 中的数字可以无限制重复被选取。如果至少一个所选数字数量不同,则两种组合是不同的。 对于给定的输入,保证和为 target 的唯一组合数少于 150 个。
在这里插入图片描述
题解:与上一题相比,在于在进下一层的时候,可以从当前元素开始

class Solution {
    List<List<Integer>> ans = new ArrayList<>();
    List<Integer> tmp = new ArrayList<>();
    public void dfs(int[] candidates, int target,int i,int sum){
        if(sum>=target){
            if(sum==target)
                ans.add(new ArrayList<Integer>(tmp));
            return;
        }
        if(i==candidates.length){
            return;
        }
        tmp.add(candidates[i]);
        dfs(candidates,target,i,sum+candidates[i]);//这里有区别
        tmp.remove(tmp.size()-1);
        dfs(candidates,target,i+1,sum);

    }
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        dfs(candidates,target,0,0);
        return ans;
    }
}

5. 组合总和 II

题目:给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。candidates 中的每个数字在每个组合中只能使用 一次 。注意:解集不能包含重复的组合。
在这里插入图片描述
题解:与上一道题有两个不同,第一,每个数字只能使用一次,第二,数组中包含重复元素

class Solution {
    List<List<Integer>> ans = new ArrayList<>();
    List<Integer> tmp = new ArrayList<>();
    public void dfs(int[] candidates, int target,int i,int sum){
        if(sum>=target){
            if(sum==target)
                ans.add(new ArrayList<Integer>(tmp));
            return;
        }
        if(i==candidates.length){
            return;
        }
        tmp.add(candidates[i]);
        dfs(candidates,target,i+1,sum+candidates[i]);//第一个差异
        tmp.remove(tmp.size()-1);
        while(i+1<candidates.length&&candidates[i+1]==candidates[i]){//第二个差异
            i++;
        }
        dfs(candidates,target,i+1,sum);

    }
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        Arrays.sort(candidates);
        dfs(candidates,target,0,0);
        return ans;
    }
}

这种方式与上一个类似,只不过换成了循环的方式

class Solution {
    List<List<Integer>> ans = new ArrayList<>();
    List<Integer> tmp = new ArrayList<>();
    public void dfs(int[] candidates, int target,int index,int sum){
        if(target<sum) return;
        if(target==sum)
             ans.add(new ArrayList<Integer>(tmp));
        
        for(int i = index;i<candidates.length;i++){//i=index 保证下面一层取,从index开始
            if(i>index&&candidates[i]==candidates[i-1])//保证在同一级递归中两个数不重复
                continue;
            tmp.add(candidates[i]);
            dfs(candidates,target,i+1,sum+candidates[i]);
            tmp.remove(tmp.size()-1);
        }
    }
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        Arrays.sort(candidates);
        dfs(candidates,target,0,0);
        return ans;
    }
}

6. 没有重复元素集合的全排列

题目:给定一个不含重复数字的整数数组 nums ,返回其 所有可能的全排列 。可以 按任意顺序 返回答案。
在这里插入图片描述
题解:全排列问题,每一次可以选择所有元素,不需要按照数组顺序,需要用一个数组去重

class Solution {
    List<List<Integer>> ans = new ArrayList<>();
    List<Integer> tmp = new ArrayList<>();
    Map<Integer,Integer> mp = new HashMap<Integer,Integer>();
    public void dfs(int[] nums){
        if(tmp.size()==nums.length){
            ans.add(new ArrayList<Integer>(tmp));
            return;
        }
        for(int i=0;i<nums.length;i++){
            if(mp.get(nums[i])!=null)
                continue;
            tmp.add(nums[i]);
            mp.put(nums[i],1);
            dfs(nums);
            tmp.remove(tmp.size()-1);
            mp.remove(nums[i]);
        }
    }
    public List<List<Integer>> permute(int[] nums) {
        dfs(nums);
        return ans;
    }
}

7. 含有重复元素集合的全排列

题目:给定一个可包含重复数字的整数集合 nums ,按任意顺序 返回它所有不重复的全排列。
在这里插入图片描述
题解:与上一题相比,含有重复元素,需要再每一层的时候取到不相同的元素,用
(i>0&&nums[i]==nums[i-1]&&mp.get(i-1)!=null) 保证

class Solution {
    List<List<Integer>> ans = new ArrayList<>();
    List<Integer> tmp = new ArrayList<>();
    Map<Integer,Integer>mp = new HashMap<Integer,Integer>();
    public void dfs(int[] nums){
        if(tmp.size()==nums.length){
            ans.add(new ArrayList<Integer>(tmp));
            return;
        }
        for(int i=0;i<nums.length;i++){
            //如果当前位置使用过,则跳过
            //如果当前位置没有使用过,但是当前元素等于前一个元素,且前一个元素,则跳过
            if(mp.get(i)!=null||(i>0&&nums[i]==nums[i-1]&&mp.get(i-1)!=null)) continue;
        
            tmp.add(nums[i]);
            mp.put(i,1);
            dfs(nums);
            tmp.remove(tmp.size()-1);
            mp.remove(i);
        }
    }
    public List<List<Integer>> permuteUnique(int[] nums) {
        Arrays.sort(nums);
        dfs(nums);
        return ans;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值