递归回溯求重复元素的子集问题和求重复元素的全排列问题

有重复元素的求子集问题和全排列问题,两者都要去重剪枝,全排列是定义一个数组,来标记是否访问过。而子集没有用到数组。两者的共同点都是要先对题目给的数组排序。

求重复元素的子集问题:
在这里插入图片描述代码:

class Solution {
    List<List<Integer>> res=new ArrayList<List<Integer>>();
    List<Integer> List=new ArrayList<Integer>();


    public List<List<Integer>> subsetsWithDup(int[] nums) {
        //添加空集合
        res.add(new ArrayList<>());

        //先对数组排好序,以便去重
        Arrays.sort(nums);

        //递归回溯
        dfs(nums,0);

        return res;

    }
    public void dfs(int[] nums,int start){
        //递归结束条件
        if(start>=nums.length) return;

       

        for(int i=start;i<nums.length;i++){

             //剪枝去重
        if( i>start && nums[i]==nums[i-1]) continue;


            list.add(nums[i]);
            res.add(new ArrayList<>(list)); //注意这里是新创建集合,再复制,否则为空集合

            dfs(nums,i+1);
            list.remove(list.size()-1);
        }

    }
}

求重复元素的全排列问题

在这里插入图片描述
代码

class Solution {

   List<List<Integer>> res=new ArrayList<List<Integer>>();
    
    List<Integer> curr=new ArrayList<Integer>();

    //标记元素是否被访问,0未,1是
    int[] visited;
    public List<List<Integer>> permuteUnique(int[] nums) {
        if(nums==null || nums.length==0) return res;

        this.visited=new int[nums.length];//标记数组的长度和数组序列长度相等
        Arrays.sort(nums);//对数组排好序,以便减枝
        def(nums);

        return res;


    }
    public void def(int[] nums){
        //说明遍历完一个分支
        if(curr.size()==nums.length){
            //因为java中的参数传递是值传递,如果直接传curr,得到的是地址,,需要创建一个新的数组为其复制即可
            res.add(new ArrayList<Integer>(curr));
            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]==1) continue;
           //上面i>0防止数组-1越界
            

            visited[i]=1;
            curr.add(nums[i]); //先置为1,再添加到小集合中

            def(nums);

            curr.remove(curr.size()-1); //回溯
            visited[i]=0;



        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值