LeetCode 子集

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

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

示例:

输入: nums = [1,2,3]
输出:
[
  [3],
  [1],
  [2],
  [1,2,3],
  [1,3],
  [2,3],
  [1,2],
  []
]
解法一:

这道求子集合的问题,由于其要列出所有结果,按照以往的经验,肯定要是要用递归来做。这道题其实它的非递归解法相对来说更简单一点,下面我们先来看非递归的解法,我们可以一位一位的往上叠加,比如对于题目中给的例子 [1,2,3] 来说,最开始是空集,那么我们现在要处理 1,就在空集上加 1,为 [1],现在我们有两个子集 [] 和 [1],下面我们来处理 2,我们在之前的子集基础上,每个都加个 2,可以分别得到 [2],[1, 2],那么现在所有的子集合为 [],[1],[2],[1, 2],同理处理 3 的情况可得 [3],[1, 3],[2, 3],[1, 2, 3],再加上之前的子集就是所有的子集合了,代码如下:

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

        lists.add(new ArrayList<>());
        
        for (int i = 0; i < nums.length; i++) {

            int size = lists.size();

            for (int j = 0; j < size; j++) {
                List<Integer> list = lists.get(j);
                list.add(nums[i]);
                lists.add(new ArrayList<>(list));
                //System.out.println("before: " + list);
                list.remove(list.size() - 1);
                //System.out.println("after: " + list);
            }
        }

        return lists;
    }

打印迭代过程如下:

before: [1]
after: []
before: [2]
after: []
before: [1, 2]
after: [1]
before: [3]
after: []
before: [1, 3]
after: [1]
before: [2, 3]
after: [2]
before: [1, 2, 3]
after: [1, 2]
解法二

下面来看递归的解法,这相当于一种深度优先搜索,参见网友JustDoIt 的博客,由于原集合每一个数字只有两种状态,要么存在,要么不存在,那么在构造子集时就有选择和不选择两种情况,所以可以构造一棵二叉树,左子树表示选择该层处理的节点,右子树表示不选择,最终的叶节点就是所有子集合,树的结构如下:

                        []        
                   /          \        
                  /            \     
                 /              \
              [1]                []
           /       \           /    \
          /         \         /      \        
       [1 2]       [1]       [2]     []
      /     \     /   \     /   \    / \
  [1 2 3] [1 2] [1 3] [1] [2 3] [2] [3] []
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> lists = new ArrayList<>();

        List<Integer> out = new ArrayList<>();

        subsetsDFS(nums, 0, out, lists);

        return lists;
    }

    public void subsetsDFS(int[] nums, int level, List<Integer> out, List<List<Integer>> lists) {

        lists.add(out);

        for (int i = level; i < nums.length; i++) {
            out.add(nums[i]);
            List<Integer> list = new ArrayList<>(out);
            subsetsDFS(nums, i + 1, list, lists);
            out.remove(out.size() - 1);
        }
    }

子集添加的顺序如下:

[]
[1]
[1, 2]
[1, 2, 3]
[1, 3]
[2]
[2, 3]
[3]
解法三

最后我们再来看一种解法,这种解法是 CareerCup 书上给的一种解法,想法也比较巧妙,把数组中所有的数分配一个状态,true 表示这个数在子集中出现,false 表示在子集中不出现,那么对于一个长度为 n 的数组,每个数字都有出现与不出现两种情况,所以共有 2^n 种情况,我们把每种情况都转换出来就是子集了,我们还是用题目中的例子, [1 2 3] 这个数组共有 8 个子集,每个子集的序号用二进制表示,把是 1 的位对应原数组中的数字取出来就是一个子集,八种情况都取出来就是所有的子集了,参见代码如下:

1 2 3 Subset
0 F F F []
1 F F T [3]
2 F T F [2]
3 F T T [2, 3]
4 T F F [1]
5 T F T [1, 3]
6 T T F [1, 2]
7 T T T [1, 2, 3]
    public List<List<Integer>> subsets(int[] nums) {
        
        List<List<Integer>> lists = new ArrayList<>();

        int max = 1 << nums.length;

        for (int i = 0; i < max; i++) {
            List<Integer> list = convertIntToSet(nums, i);
            lists.add(list);
        }
        
        return lists;
    }

    private List<Integer> convertIntToSet(int[] nums, int i) {

        List<Integer> sub = new ArrayList<>();
        int idx = 0;

        for (int k = i; k > 0; k >>= 1) {
            if ((k & 1) == 1) {
                sub.add(nums[idx]);
            }
            idx++;
        }
        
        return sub;
    }

本文参考自 [LeetCode] Subsets 子集合

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 算法思想贪心思想双指针排序快速选择堆排序桶排序荷兰国旗问题二分查找搜索BFSDFSBacktracking分治动态...
    第六象限阅读 3,396评论 0 0
  • 今天是我没收入的第24天。朋友说如果自己没能力就连父母也会看你不顺眼的,这话虽然不中听可我却能体会到,我不想更不敢...
    柚子君3693阅读 125评论 0 0
  • 第八章选对位置,最大限度地发挥优势和潜能 一,找好团队来成就自我 没有人是全能英雄,只要懂得做组合,打配合,发挥自...
    房铁冰阅读 377评论 0 1
  • 简介:现在版本控制主要是SVN和Git,我经历的两家公司都是用SVN管理,许多人用软件客户端进行代码提交等,但个人...
    Terry_S阅读 32,457评论 0 5
  • 大二的我想我再也不会真心不带一丝一毫的他心喜欢或者爱上一个人。再也不是单纯的想和一个人谈恋爱,拒绝了别人却感到一丝...
    木柚z阅读 104评论 0 0