Leetcoe高频题(七) 我就不信邪了 LeetCode 回溯法

参考 手把手教你中的回溯算法

leetcode回溯法欣赏


78. 子集

在这里插入图片描述

//1.暴力法

  //1.暴力法
    public List<List<Integer>> subsets(int[] nums) {
    
    
       List<List<Integer>> res=new ArrayList<>();
       res.add(new ArrayList<>());

       for(int num:nums){
    
    
           int resLength=res.size();
           for(int i=0;i<resLength;i++){
    
    
               List<Integer> cur=new ArrayList<>(res.get(i));
               cur.add(num);
               res.add(cur);
           }
       }
           return res; 
    }

//2.dfs

  List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> subsets(int[] nums) {
    
    
        res.add(new ArrayList<>());
        //回溯算法的模板
        List<Integer> track = new ArrayList<>();
        backtrack(nums,0,track);
        return res;
    }
    //每一个数都有两种选择:要或不要
    private void backtrack(int[] nums,int start,List<Integer> track){
    
    
        for(int i=start;i<nums.length;i++){
    
    
            track.add(nums[i]);
            res.add(new ArrayList<>(track));
            backtrack(nums,i+1,track);
            track.remove(track.size()-1);
        }
    }


90. 子集 II

在这里插入图片描述

//1.扩展法

  public List<List<Integer>> subsetsWithDup(int[] nums) {
    
    
       List<List<Integer>> res=new ArrayList<>();
       res.add(new ArrayList<>());

      Arrays.sort(nums);

       for(int i=0;i<nums.length;i++){
    
    
           int resLength=res.size();
           for(int j=0;j<resLength;j++){
    
    
               List<Integer> cur=new ArrayList<>(res.get(j));
               cur.add(nums[i]);
               res.add(cur);
           }
       }
     HashSet<List<Integer>> set=new HashSet<>(res);
     return new ArrayList<>(set); 
   
    }

//2.深度优先

   List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> subsetsWithDup(int[] nums) {
    
    

     Arrays.sort(nums); 
     res.add(new ArrayList<>());
        //回溯算法的模板
        List<Integer> track = new ArrayList<>();
        backtrack(nums,0,track);
        return res;
    }

    private void backtrack(int[] nums,int start,List<Integer> track){
    
    
        for(int i=start;i<nums.length;i++){
    
    
         //去充条件:i>start&&nums[i]==nums[i-1]
            if(i>start&&nums[i]==nums[i-1]) continue;
            track.add(nums[i]);
            res.add(new ArrayList<>(track));
            backtrack(nums,i+1,track);
            track.remove(track.size()-1);
        } 
    }




46. 全排列

在这里插入图片描述

backtrack的公式:

result = []
def backtrack(路径, 选择列表):
    if 满足结束条件:
        result.add(路径)
        return
    
    for 选择 in 选择列表:
        做选择
        backtrack(路径, 选择列表)
        撤销选择

     
    List<List<Integer>> res=new ArrayList<>();
    public List<List<Integer>> permute(int[] nums) {
    
    
      List<Integer> list=new ArrayList<>();
      backtrack(res,list,nums);
      return res;     
    }


 public void backtrack(List<List<Integer>> res, 
 List<Integer> list, int[] nums) {
    
    
    if(list.size()==nums.length){
    
    
        res.add(new ArrayList<>(list));
        return;
    }
    for(int num:nums){
    
    
         if(!list.contains(num)){
    
    
            list.add(num);
            backtrack(res,list,nums);
            list.remove(list.size()-1);
        }
      }
}

47. 全排列 II

在这里插入图片描述

class Solution {
    
    
    public List<List<Integer>> permuteUnique(int[] nums) {
    
    
        List<List<Integer>> res = new ArrayList<>(); // 记录最终答案
        if (nums == null || nums.length == 0) return res; 
        // visited[i] == 0时,未访问;== 1时,已访问
        int[] visited = new int[nums.length]; 
        Arrays.sort(nums); // 排序后容易去重
        backTrack(res, nums, new ArrayList<Integer>(), visited);
        return res;
    }

    private void backTrack(List<List<Integer>> res, int[] nums, List<Integer> list, int[] visited) {
    
    
        // 列表长度为数组长度时,拷贝列表到结果列表中
        if (list.size() == nums.length) {
    
    
            res.add(new ArrayList<>(list));
            return ;
        }
        for (int i = 0; i < nums.length; i++) {
    
    
            if (visited[i] == 1) continue; // 已访问过,跳过这层循环
            // 如果数组相连元素相等,没有先访问后面的元素,就不会存在重复
            if (i > 0 && nums[i] == nums[i - 1] && visited[i - 1] == 0){
    
    
                continue;
            }
            // 加入列表中,标记为已访问,回溯求值
            list.add(nums[i]);
            visited[i] = 1;
            backTrack(res, nums, list, visited);
            // 回溯后,重新标记为未访问,删掉最后一个元素
            visited[i] = 0;
            list.remove(list.size() - 1);
        }
    }
}

77. 组合

在这里插入图片描述

//递归
class Solution {
    
    
    public List<List<Integer>> combine(int n, int k) {
    
    
        List<List<Integer>> res = new ArrayList<>();
        //边界条件判断
        if (n < k || k == 0)
            return res;
        // 选择第n个,从前面n-1个数字中选择k-1个构成一个集合
        res = combine(n - 1, k - 1);
        //如果res是空,添加一个空的集合
        if (res.isEmpty())
            res.add(new ArrayList<>());
        //然后在前面选择的集合res中的每个子集合的后面添加一个数字n
        for (List<Integer> list : res)
            list.add(n);
        //res中不光要包含选择第n个数字的集合,也要包含不选择第n
        //个数字的集合
        res.addAll(combine(n - 1, k));
        return res;
    }
 
}
//回溯
 public List<List<Integer>> combine(int n, int k) {
    
    
        List<List<Integer>> list = new LinkedList<>();
        backtrack(list, n, k, 1, new ArrayList<>());
        return list;
    }

    private void backtrack(List<List<Integer>> list, int n, int k, int start, List<Integer> tempList) {
    
    
        //终止条件,找到一对组合
        if (k == 0) {
    
    
            list.add(new LinkedList<>(tempList));
            return;
        }
        //注意这里的i不能从0开始,如果从0开始会出现重复的,比如[1,2]和[2,1]
        for (int i = start; i <= n - k + 1; i++) {
    
    
            //把当前值添加到集合中
            tempList.add(i);
            //递归调用,继续下一个分支
            backtrack(list, n, k - 1, i + 1, tempList);
            //从当前分支跳到下一个分支的时候要把之前添加的值给移除
            tempList.remove(tempList.size() - 1);
        }
    }
 

猜你喜欢

转载自blog.csdn.net/qq_38847154/article/details/109015635