力扣第七十八题-子集

243 阅读2分钟

「这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战

前言

力扣第七十八题 子集 如下所示:

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

示例 1:

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

示例 2:

输入: nums = [0]
输出: [[],[0]]

一、思路

题目中有一点很重要:数组中的元素互不相同。只要遍历的过程中不回头,就不会出现重复的问题。

我们的目标是得到所有不重复的子集,既然是所有的可能,那么每个元素都有可能选或者不选,总共有 2^n 次方总可能性。

我们用 0 表示不选, 1 表示选当前位置的元素。以 nums ={1, 2, 3} 作为例子,它们的与二进制对应的关系如下所示:

image.png

大致的实现步骤如下:

  1. 开始遍历,从 02^n -1n 为数组 nums 的长度)
  2. 将遍历的下标转为对应的二进制,并记录结果即可 (例如:当 i=1 时,对应的二进制为 001,子集的结果为 {3}
  3. 遍历结束,返回所有的子集即可

举个例子

此处以 nums= [1, 2, 3] 作为例子

  1. 开始遍历,从 i = 0 开始
  2. i = 0 时,对应的二进制为 000,此时的子集为 {}
  3. ......
  4. i = 7 时,对应的二进制为 111,此时的子集为 {1, 2, 3}
  5. 遍历结束,返回结果集即可

二、实现

实现代码

在将下标转为二进制的过程中,可以直接使用位运算 向右移,这样可以直接判断第几对应的值是否为 1

    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> ret = new ArrayList<>();
        for (int i = 0; i < (1 << nums.length); i++) {
            List<Integer> temp = new ArrayList<>();
            for (int j = 0; j < nums.length; j++) {
                if ((i >> j & 1) == 1) {
                    temp.add(nums[j]);
                }
            }
            ret.add(temp);
        }
        return ret;
    }

测试代码

    public static void main(String[] args) {
        int[] nums = {1, 2, 3, 4};
        new Number78().subsets(nums);
    }

结果

image.png

三、总结

这一题也可以想象成 全二叉树 的遍历,树的深度为 nums.length。从根节点开始,每个节点都可以选择 0 或者 1

感谢看到最后,非常荣幸能够帮助到你~♥

如果你觉得我写的还不错的话,不妨给我点个赞吧!如有疑问,也可评论区见~