LeetCode刷题笔记 回溯算法集合

组合总和

给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的数字可以无限制重复被选取。

class Solution {
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> listAll = new ArrayList<>();
        List<Integer> list = new ArrayList<>();
        Arrays.sort(candidates);
        
        find(listAll, list, candidates, target, 0);
        return listAll;
    }
    
    public void find(List<List<Integer>> listAll, List<Integer> temp, int[] candidates, int target, int index) {
        if(target == 0) {
            listAll.add(temp);
            return;
        }
        if(target < candidates[0]) return;
        for(int i = index; i < candidates.length && candidates[i] <= target; i++) {
            List<Integer> list = new ArrayList<>(temp);
            list.add(candidates[i]);
            find(listAll, list, candidates, target-candidates[i], i);
        }
    }
}

组合总和 II

给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用一次。

class Solution {
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        Arrays.sort(candidates);
        List<List<Integer>> res = new ArrayList<>();
        find(res, 0, 0, new ArrayList<Integer>(), candidates, target);
        return res;
    }
    
    public void find(List<List<Integer>> res, int index, int sum, List<Integer> tmp_list, int[] candidates, int target) {
        if(sum == target) {
            res.add(new ArrayList<>(tmp_list));
            return;
        }
        for(int i = index; i < candidates.length; i++) {
            if (sum + candidates[i] > target) break;
            if (i > index && candidates[i] == candidates[i - 1]) continue;  //去重
            tmp_list.add(candidates[i]);
            find(res, i+1, sum + candidates[i], tmp_list, candidates, target);
            tmp_list.remove(tmp_list.size()-1);		//去重,防止一个组合里面有相同的数,上面是防止有两个相同的数组
        }
    }
}

组合总和 III

找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。

class Solution {
    public List<List<Integer>> combinationSum3(int k, int n) {
        int[] nums = new int[]{1,2,3,4,5,6,7,8,9};
        List<List<Integer>> ans = new ArrayList<List<Integer>>();
        dfs(nums,0,n,k,new ArrayList<Integer>(),ans);
        return ans;
    }
    private void dfs(int[] nums,int i,int left,int k,ArrayList<Integer> cur,List<List<Integer>> ans) {
        if (left < 0) return ;
        if (k == 0) {
            if (left == 0) {
                ans.add(new ArrayList<Integer>(cur));
                return ;            
            } else return ;
        }
         
        
        for (int j = i;j < nums.length;j++) {
            if (nums[j] > left) break;
            cur.add(nums[j]);
            dfs(nums,j+1,left - nums[j],k-1,cur,ans);
            cur.remove(cur.size()-1);
        }

    }
}

全排列

给定一个没有重复数字的序列,返回其所有可能的全排列。

class Solution {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        List<Integer> t = new ArrayList<>();
        for(int i = 0; i < nums.length; i++) {
            t.add(nums[i]);
            find(res, t, nums);
            t.remove(0);
        }    
        return res;
    }
    
    private void find(List<List<Integer>> res, List<Integer> tmp, int[] nums) {
        if(tmp.size() == nums.length) {           
            res.add(new ArrayList<>(tmp));
            return;
        }
        for(int i = 0; i < nums.length; i++) {
            if(!tmp.contains(nums[i])) {
                tmp.add(nums[i]);
                find(res, tmp, nums);
                tmp.remove(tmp.size()-1);                
            }
        }
    }
}

/* 方法二:不对数组进行加减操作,而是交换,这种方法更快 ----------------------------------*/
class Solution {
    public List<List<Integer>> permute(int[] nums) {
       //思路:运用递归的方法,
        int len=nums.length;//记录数组的长度
        int first=0;//
        List<List<Integer>> output=new LinkedList<List<Integer>>();//建立一个输出的数组
        //将数组转换成链表的形式,是因为定义的输出数组中的元素要求List类型的。
        ArrayList<Integer> nums_li=new ArrayList<Integer>();
        for(int num:nums){
            nums_li.add(num);
        }
        digui(len,output,nums_li,first);//调用递归函数
        return output;
    }
    //递归函数
    public static void helper(int len,List<List<Integer>> output
    							,ArrayList<Integer>nums_li,int first){
        //结束条件:当到数组中的最后一个元素时,即已经排列组合完毕,则输出
        if(first==len){
            output.add(new ArrayList<Integer>(nums_li));
        }
        int i;
        for(i=first;i<len;i++){
            Collections.swap(nums_li,first,i);
            helper(len,output,nums_li,first+1);
            Collections.swap(nums_li,first,i);
        }
    }
}
/* 方法三: 三个for循环,其实和for循环很像 -------------------------------------*/
class Solution {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        List<Integer> l1 = new ArrayList<Integer>();
        l1.add(nums[0]);
        result.add(l1);
        for(int i = 1;i<nums.length;i++){
            List<List<Integer>> resultx = new ArrayList<List<Integer>>();
            for(List<Integer> list:result){
                // System.out.println(list);
                for(int j =0;j<=list.size();j++ ){
                    List<Integer> list2 = new ArrayList<Integer>();
                    list2.addAll(list);
                    list2.add(j,nums[i]);              
                    resultx.add(list2);
                }   
            }
            result = resultx;
        }
        return result;        
    }
}

全排列 II

给定一个可包含重复数字的序列,返回所有不重复的全排列。

class Solution {
    public List<List<Integer>> permuteUnique(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        Arrays.sort(nums);
        // 添加visited数组,区分相等数字,以及同一排列里面相等但不相同的数字
        int[] visited = new int[nums.length];
        backtrack(res, nums, visited, new ArrayList<Integer>());
        return res;

    }

    private void backtrack(List<List<Integer>> res, int[] nums, int[] visited, ArrayList<Integer> tmp) {
        if (tmp.size() == nums.length) {
            res.add(new ArrayList<>(tmp));
            return;
        }
        for (int i = 0; i < nums.length; i++) {
            if (visited[i] == 1 || (i > 0 && visited[i - 1] == 0 && nums[i - 1] == nums[i])) continue;
            visited[i] = 1;
            tmp.add(nums[i]);
            backtrack(res, nums, visited, tmp);
            tmp.remove(tmp.size() - 1);
            visited[i] = 0;
        }
    }
} 

子集

给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        ArrayList<List<Integer>> res = new ArrayList<>();
        subsetsCore(res, new ArrayList<Integer>(), nums, 0);
        return res;
    }

    private void subsetsCore(ArrayList<List<Integer>> res, ArrayList<Integer> list, int[] nums, int index) {
        
        res.add(new ArrayList<>(list));
        
        for (int i = index; i < nums.length; i++) {
            list.add(nums[i]);
            subsetsCore(res, list, nums, i + 1);
            list.remove(list.size() - 1);
        }
    }
}
/* 方法二: 两个for循环完成 -------------------------------------*/
class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        result.add(new ArrayList<>());
        for(int n : nums){
            int size = result.size();
            for(int i=0; i<size; i++){
                List<Integer> subset = new ArrayList<>(result.get(i));
                subset.add(n);
                result.add(subset);
            }
        }
        return result;
    }
}

子集 II

给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

说明:解集不能包含重复的子集。

class Solution {
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        Arrays.sort(nums);
        backTrack(res,nums,new ArrayList<Integer>(),0);
        return res;
    }
    
    public void backTrack(List<List<Integer>> res,int []nums,List<Integer>tmp,int start){
        res.add(new ArrayList<>(tmp));
        for(int i=start;i<nums.length;i++){
            if(i > start && nums[i] == nums[i-1]) continue;
            tmp.add(nums[i]);
            backTrack(res,nums,tmp,i+1);
            tmp.remove(tmp.size()-1);
        }
    }
}

组合

给定两个整数 n 和 k,返回 1 … n 中所有可能的 k 个数的组合。

class Solution {
    public List<List<Integer>> combine(int n, int k) {
        List<List<Integer>> res = new ArrayList<>();
        helper(n, k, 1, res, new ArrayList<Integer>());
        
        return res;
    }
    
    private void helper(int n, int k, int start, List<List<Integer>> res, List<Integer> temp) {
        if(temp.size() == k) {
            res.add(new ArrayList<>(temp));
            return;
        }
        
        for(int j = start; j <= n - (k - temp.size()) + 1; j++) {
            temp.add(j);
            helper(n, k, j+1, res, temp);
            temp.remove(temp.size()-1);
        }   
    }
}

93. 复原IP地址

给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。

class Solution {
    public List<String> restoreIpAddresses(String s) {
        List<String> res = new ArrayList<>();
        helper(0, "", 4, s, res, s.length());        
        return res;
    }
    
    private void helper(int start, String temp, int flag, String s, List<String> list, int len) {
        if(start==len && flag==0) {
            list.add(temp.substring(0, temp.length()-1));   //-1是为了把最后的"."去掉
            return;
        }
        if(flag < 0) return;
        for(int i = start; i < start+3; i++) {
            if(i < len) {
                if(start==i && s.charAt(i)=='0') {  //如果是子字符串的首位且为0
                    helper(i+1, temp+s.charAt(i)+".", flag-1, s, list, len);
                    break;
                }
                if(Integer.parseInt(s.substring(start, i+1)) <= 255) 
                    helper(i+1, temp+s.substring(start, i+1)+".", flag-1, 
                           s, list, len);                
            }
        }
    }
}

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/permutation-sequence

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值