回溯法求解Leetcode经典组合问题(Leetcode17、39、40、216、77、78、90、131)

写在前面:

求解组合问题常用的方法是回溯,回溯类似于DFS(深度优先遍历),实际是一个暴力搜索的过程,把所有的组合都列举出来,找出符合题意的组合。

1、Leetcode 17. Letter Combinations of a Phone Number

思路:

参考高赞回答

class Solution {
    public List<String> letterCombinations(String digits) {
        List<String> res=new ArrayList<>();
        if(digits==null||digits.length()==0){
            return res;
        }
        char[][] map={{},{},{'a','b','c'},{'d','e','f'},{'g','h','i'},{'j','k','l'},{'m','n','o'},{'p','q','r','s'},{'t','u','v'},{'w','x','y','z'}};
        backtrack(digits,new StringBuilder(),map,0,res);
        return res;
    }
    public void backtrack(String digits,StringBuilder sb,char[][] map,int start,List<String > res){
        if(start==digits.length()){
            res.add(new String(sb));
            //因为StringBuilder传的是引用,所以要new一个来传值
            return;
        }
            
        int num=digits.charAt(start)-'0';
        for(int i=0;i<map[num].length;i++){
            sb.append(map[num][i]);
            backtrack(digits,sb,map,start+1,res);
            sb.deleteCharAt(sb.length()-1);
        }
    }
}

2、39. Combination Sum

思路:

参考A general approach to backtracking questions in Java (Subsets, Permutations, Combination Sum, Palindrome Partitioning),这篇高赞回答非常棒,总结了回溯问题的通用解法。

class Solution {
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> res=new ArrayList<List<Integer>>();
        backtrack(candidates,res,new ArrayList<>(),0,target,0);
        return res;
    }
    public void backtrack(int[] candidates,List<List<Integer>> res,List<Integer> list,int curSum,int target,int start){
        if(curSum>target){
            return;
        }
        if(curSum==target){
            res.add(new ArrayList(list));
            return;
        }
        for(int i=start;i<candidates.length;i++){//i从start开始,只往前不往后
            list.add(candidates[i]);
            backtrack(candidates,res,list,curSum+candidates[i],target,i);
            //不是i+1因为一个元素可以取多次
            list.remove(list.size()-1);
        }
    }
}

3、40. Combination Sum II

思路

剪枝参考高赞回答

class Solution {
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        List<List<Integer>> res=new ArrayList<List<Integer>>();
        Arrays.sort(candidates);//元素相同顺序不同只能视为一种解法
        backtrack(candidates,res,new ArrayList<>(),0,target,0);
        return res;
    }
    public void backtrack(int[] candidates,List<List<Integer>> res,List<Integer> list,int curSum,int target,int start){
        if(curSum>target){
            return;
        }
        if(curSum==target){
            res.add(new ArrayList(list));
            return;
        }
        for(int i=start;i<candidates.length;i++){//i从start开始,只往前不往后
            if(i>start&&candidates[i]==candidates[i-1]){
                //这一步的剪枝参考https://leetcode-cn.com/problems/combination-sum-ii/solution/hui-su-suan-fa-jian-zhi-python-dai-ma-java-dai-m-3/
                continue;
            }
            list.add(candidates[i]);
            backtrack(candidates,res,list,curSum+candidates[i],target,i+1);
            //从i+1开始因为每个元素只能取一次
            list.remove(list.size()-1);
        }
    }
}

4、216. Combination Sum III

class Solution {
    public List<List<Integer>> combinationSum3(int k, int n) {
        List<List<Integer>> res=new ArrayList<>();
        backtrack(res,new ArrayList<>(),k,n,0,1);
        return res;
    }
    public void backtrack(List<List<Integer>> res,List<Integer> list,int k,int n,int curSum,int start){
        if(list.size()==k&&curSum==n){
            res.add(new ArrayList<Integer>(list));
            return;
        }
        for(int i=start;i<=9;i++){
            if(curSum>n||list.size()>k){
                break;
            }
            list.add(i);
            backtrack(res,list,k,n,curSum+i,i+1);
            list.remove(list.size()-1);
        }
    }
}

5、77. Combinations

class Solution {
    public List<List<Integer>> combine(int n, int k) {
        List<List<Integer>> res=new ArrayList<List<Integer>>();
        backtrack(res,new ArrayList<>(),n,k,1);
        return res;
    }
    public void backtrack(List<List<Integer>> res,List<Integer> list,int n,int k,int start){
        if(list.size()==k){
            res.add(new ArrayList(list));//ArrayList传的是引用,所以要复制一个新的ArrayList
            return;
        }
        for(int i=start;i<=n;i++){
            list.add(i);
            backtrack(res,list,n,k,i+1);
            list.remove(list.size()-1);//回溯
        }
    }
}

6、78. Subsets

class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> res=new ArrayList<List<Integer>>();
        for(int i=0;i<=nums.length;i++){
            backtrack(res,new ArrayList<>(),nums,0,i);
        }
        return res;
    }
    public void backtrack(List<List<Integer>> res,List<Integer> list,int[] nums,int start,int size){
        if(list.size()==size){
            res.add(new ArrayList(list));//ArrayList传的是引用,所以要复制一个新的ArrayList
        }
        for(int i=start;i<nums.length;i++){
            list.add(nums[i]);
            backtrack(res,list,nums,i+1,size);
            list.remove(list.size()-1);//回溯
        }
    }
}

7、90. Subsets II

class Solution {
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        List<List<Integer>> res=new ArrayList<List<Integer>>();
        Arrays.sort(nums);
        for(int i=0;i<=nums.length;i++){
            backtrack(res,new ArrayList<>(),nums,0,i);
        }
        return res;
    }
     public void backtrack(List<List<Integer>> res,List<Integer> list,int[] nums,int start,int size){
        if(list.size()==size){
            res.add(new ArrayList(list));//ArrayList传的是引用,所以要复制一个新的ArrayList
        }
        for(int i=start;i<nums.length;i++){
            if(i>start&&nums[i]==nums[i-1]){
                continue;//剪枝
            }
            list.add(nums[i]);
            backtrack(res,list,nums,i+1,size);
            list.remove(list.size()-1);//回溯
        }
    }
}

8、131. Palindrome Partitioning

class Solution {
    public List<List<String>> partition(String s) {
        List<List<String>> res=new ArrayList<>();
        backtrack(res,new ArrayList<>(),s,0);
        return res;
    }
    public void backtrack(List<List<String>> res,List<String> list,String s,int start){
        if(start==s.length()){
            res.add(new ArrayList<>(list));
            return;
        }
        for(int i=start;i<s.length();i++){
            if(isPalindrome(s,start,i)){
                list.add(s.substring(start,i+1));
                backtrack(res,list,s,i+1);
                list.remove(list.size()-1);
            }
        }
    }
    public boolean isPalindrome(String s,int start,int end){
        while(start<end){
            if(s.charAt(start)!=s.charAt(end)){
                return false;
            }
            start++;
            end--;
        }
        return true;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值