Day 23|回溯(全排列)

回溯算法

视频讲解
在这里插入图片描述
回溯是一个增量构造答案的过程(这个过程用递归实现) i i i表示大于等于 i i i
i

所有回溯法的问题都可以抽象为树形结构!
回溯三部曲:
1.进行选择 2.递归 3.撤回选择

Leecode题目

491. 递增子序列

而本题求自增子序列,是不能对原数组进行排序的
本题求子序列,很明显一个元素不能重复使用,所以需要startIndex
这个讲解的很好,利用HashSet去重

class Solution {
    public List<List<Integer>> findSubsequences(int[] nums) {
     HashSet<List<Integer>> r = new HashSet<>();
     LinkedList<Integer> path = new LinkedList<>();
     backtracking(r,path,nums,0);
     List<List<Integer>> res = new ArrayList(r);
     return res;
    }

    private void backtracking(HashSet<List<Integer>> res,LinkedList<Integer> path ,int[] nums, int start){
     if(path.size()>=2){
         res.add(new ArrayList(path));
     }

     for(int i = start;i<nums.length;i++){
         if(path.size()==0||path.getLast()<=nums[i]){
             path.add(nums[i]);
             backtracking(res,path,nums,i+1);
             path.removeLast();
         }
     }
    }
}

46. 全排列

讲得很好,我听懂了

class Solution {
    public List<List<Integer>> permute(int[] nums) {
    int len = nums.length;
    List<List<Integer>> res = new ArrayList<>();
    Deque<Integer> stack = new ArrayDeque<>();
    boolean[] used = new boolean[len]; //初始化默认全是false;表示都没有被用过
    if(len == 0){
        return res;
    }
    dfs(stack,used,nums,res,0,len);
    return res;
    } 


    public void dfs(Deque<Integer> stack, boolean[] used, int[] nums, List<List<Integer>> res,int depth, int len){ 
        //终止条件
    if(depth == len){
        res.add(new ArrayList<>(stack));
         return;
         }

         //1.选择(用for循环)
         for(int i=0;i<len;i++){
          if(!used[i]){
              stack.push(nums[i]);   // stack 又名 path, 这里还可以改写为 path.addLast(nums[i])
              used[i]=true;//添加到路径中就表示已经被使用了
              //2.递归
            dfs(stack,used,nums,res,depth+1,len);
            //3.撤回选择
            used[i]=false;
            stack.pop();   // // stack 又名 path, 这里还可以改写为 path.removeLast()
          }
         }
    }
}

s t a c k stack stack 又名 p a t h path path:
s t a c k . p u s h ( n u m s [ i ] ) stack.push(nums[i]) stack.push(nums[i]) 改写为 p a t h . a d d L a s t ( n u m s [ i ] ) path.addLast(nums[i]) path.addLast(nums[i])
s t a c k . p o p ( ) stack.pop() stack.pop()改写为 p a t h . r e m o v e L a s t ( ) path.removeLast() path.removeLast()
其中的depth其实就是stack的大小

class Solution {

    List<List<Integer>> result = new ArrayList<>();// 存放符合条件结果的集合
    LinkedList<Integer> path = new LinkedList<>();// 用来存放符合条件结果
    boolean[] used;
    public List<List<Integer>> permute(int[] nums) {
        if (nums.length == 0){
            return result;
        }
        used = new boolean[nums.length];
        permuteHelper(nums);
        return result;
    }

    private void permuteHelper(int[] nums){
        if (path.size() == nums.length){
            result.add(new ArrayList<>(path));
            return;
        }
        for (int i = 0; i < nums.length; i++){
            if (used[i]){
                continue;
            }
            used[i] = true;
            path.add(nums[i]);
            permuteHelper(nums);
            path.removeLast();
            used[i] = false;
        }
    }
}

47. 全排列

这一道题与46的区别:需要去重代码随想录的解析
对于同一树层,不能出现相同的元素(used[i-1]==false,因为回溯之后会把对应的used设为false)

class Solution {
    public List<List<Integer>> permuteUnique(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        Arrays.sort(nums);
        int len = nums.length;
        Deque<Integer>  path = new ArrayDeque<>();
        boolean[] used = new boolean[len];
         if(len==0){
            return res;
        }
        dfs(path,res,nums,used);
        return res;
    }

    private void dfs( Deque<Integer>  path,  List<List<Integer>> res, int[] nums,boolean[] used){
        if(path.size()==nums.length){
            res.add(new ArrayList<>(path));
            return;
        }
        
        // 1.选择,树的第一层
        for(int i=0;i<nums.length;i++){
         //去重,树层中不可以有相同的元素
         if(i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false){
             continue; //表示相同的元素上一个用过了
         }
         // 树枝处理开始(从没有用过的开始放入树枝)
         if(!used[i]){
             path.addLast(nums[i]);
             used[i]=true;
             dfs(path,res,nums,used);
             path.removeLast();
             used[i]=false;
         }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值