算法训练|子集II

在这里插入图片描述
在这里插入图片描述

思路一:回溯、去重

class Solution {
    //设置临时集合
    List<Integer> temp = new ArrayList<Integer>();
    //设置子集总集合
    List<List<Integer>> ans = new ArrayList<List<Integer>>();
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        //将数组进行一次排序,用来避免重复收集的问题(排完序之后可以使用收集的方式/Set的方式来进行去重)
        Arrays.sort(nums);
        //数组的长度用来构造visted[]数组
        int n = nums.length;
        //使用 visited 数组来记录哪一个元素在当前路径中被使用了
        boolean[] visited = new boolean[n];
        //从0的位置开始递归搜索nums数组,因此参数是nums和0
        backtrace(nums,0,visited);
        //返回总集合
        return ans;
    }

    //采用回溯来求解本题
    public void backtrace(int[] nums,int start,boolean visited[]){
        //将temp加入ans结果集合中
        ans.add(new ArrayList<Integer>(temp));
        //用for循环遍历数组(背后实际上已经模拟成一颗树,也就是用for循环来模拟遍历树)收集结果
        for(int i = start;i < nums.length; ++i){
            //如果当前元素和前一个元素相同,而且前一个元素没有被访问,说明前一个相同的元素在当前层已经被用过了
            if(i > 0 && nums[i - 1] == nums[i] && !visited[i - 1]) continue;
            // 记录下来,用过了当前的元素
            visited[i] = true;
             // 放到临时集合中
            temp.add(nums[i]);
            //递归
            backtrace(nums,i+1,visited);
            //回溯,将当前标记为已经访问的结点取消标记,这样回到上一层就会使一个没有被访问的状态
            visited[i] = false;
            temp.remove(temp.size() - 1);
        }
    }
}

在这里插入图片描述

思路二:Set去重(时间和空间复杂度都高)

class Solution {
    //所有子集的集合
    Set<List<Integer>> subsets = new HashSet<>();
    //临时集合,用来存放单一子集
    List<Integer> temp = new ArrayList<Integer>();
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        Arrays.sort(nums);
        int length = nums.length;
        //用一个循环来列举出一个集合所有子集的二进制表示 例如[A,B,C] 的子集二进制表示[[000][001][010][011][100][101][110][111]]
        for(int i = 0; i<(1<<length); i++){
            //清空临时集合
            temp.clear();
            for(int j = 0; j < length; j++){
                //判断临时集合中的每一位是否在[A,B,C]中,如果在,将该位add进临时集合中
                if((i&(1<<j))!=0){
                    temp.add(nums[j]);
                }
            }
            //把每一个临时集合add进总集合中
            subsets.add(new ArrayList<>(temp));
        }
        return new ArrayList<>(subsets);
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

敲代码的洋葱头

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值