Leetcode78. 子集(二进制模拟+dfs)

Posted !0 !

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Leetcode78. 子集(二进制模拟+dfs)相关的知识,希望对你有一定的参考价值。

题目链接:https://leetcode-cn.com/problems/subsets/

解题思路

方法一:二进制模拟

我们可以用一个数i ( 0 ≤ i ≤ 2 n − 1 ) (0 \\leq i \\leq 2^n - 1) (0i2n1)表示一个集合,数i的第j位表示数组中第j个数是否属于当前枚举的集合,如果属于加入答案。
举个例子:[1,3];那他子集的个数就为2^ni的二进制表示就模拟该数组的两个数是否被选择。
i=0,其二进制位00,表示子集空(两个数都不选)。
i=1,其二进制为01,表示子集[3](选择第二个元素,不选第一个元素)
i=2,其二进制为10,表示子集[1](选择第一个元素,不选第二个元素)
i=3,其二进制为11,表示子集[1,3](两个元素都选)

代码

class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> ans = new ArrayList<>();
        for(int i = 0; i < 1 << nums.length; i++) { //i从0~2^n - 1
            List<Integer> res = new ArrayList<>();
            for(int j = 0; j < nums.length; j++) {  //判断每一位是否属于当前集合
                if((i >> j & 1) == 1)   //如果是1则属于该集合
                    res.add(nums[j]);
            }
            ans.add(res);
        }
        return ans;
    }
} 

复杂度分析

  • 时间复杂度: O ( 2 n ∗ n ) O(2^n * n) O(2nn)
  • 空间复杂度: O ( n ) O(n) O(n)

方法二:dfs

对于数组中的每个数,我们都有选和不选两种状态,所以直接递归,枚举出所有数的这两种状态,最后组合在一起就是答案。

代码

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

    public List<List<Integer>> subsets(int[] nums) {
        dfs(0, nums);   //从第0个元素开始
        return ans;
    }

    public void dfs(int cur, int[] nums) {
        if (cur == nums.length) {   //如果枚举完所有元素
            ans.add(new ArrayList<Integer>(t));
            return;
        }
        t.add(nums[cur]);   //选当前元素
        dfs(cur + 1, nums); //继续递归
        t.remove(t.size() - 1); //如果不选当前元素
        dfs(cur + 1, nums); //继续递归
    }
}

复杂度分析

  • 时间复杂度: O ( 2 n ∗ n ) O(2^n * n) O(2nn)
  • 空间复杂度: O ( n ) O(n) O(n)

以上是关于Leetcode78. 子集(二进制模拟+dfs)的主要内容,如果未能解决你的问题,请参考以下文章

leetcode-Subsets-78

[算法题解详细]DFS解力扣78子集

LC77 Combinations

Leetcode5759. 找出所有子集的异或总和再求和(二进制模拟暴搜)

leetcode78 子集(Medium)

LeetCode:78. 子集90. 子集 II