78. 子集
✅ 一、算法逻辑讲解(逐步通顺解释)
这段代码的目标是:给定一个不含重复元素的整数数组 nums,返回其所有可能的子集(幂集)。
步骤解析:
-
1 << len(nums):-
这是 2^n 的简写方式,表示子集的总数。
-
因为一个长度为
n的集合一共有2^n个子集。
-
-
for i in range(1<<len(nums)):-
i从0到2^n - 1。 -
每个数字
i的二进制表示就是一个子集的"选取方案",每一位表示该位置元素选不选。- 例如:
nums = [a, b, c],i = 5 = 0b101表示选a和c(第0和第2位是1)。
- 例如:
-
-
[x for j, x in enumerate(nums) if i >> j & 1]:-
枚举
nums中的每个元素x及其下标j。 -
如果
i的第j位是1,就说明这个元素被选入子集。 -
i >> j & 1是判断第j位是否为1的经典写法。
-
-
将生成的子集
subsets加入答案列表ans中。 -
返回所有子集的列表。
⭐ 二、核心思路
核心点是:用位运算枚举所有子集。
-
将每一个子集的选取用一个
n位二进制数表示(0 表示不选,1 表示选)。 -
枚举
0到2^n - 1,每个整数的二进制形式唯一表示一个子集。 -
位运算用于高效判断哪些元素被选中。
这是一种非常高效、简洁的生成子集的方式,尤其适用于集合元素较少(如 n ≤ 20)的场景。
python
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
ans = []
for i in range(1<<len(nums)):
subsets = [x for j,x in enumerate(nums) if i>>j&1]
ans.append(subsets)
return ans
⏱ 三、时间复杂度分析
时间复杂度:O(n * 2^n)
-
一共有
2^n个子集。 -
每个子集最多需要扫描
n个元素来判断是否包含(通过i >> j & 1判断)。 -
所以总的复杂度是:
O(n * 2^n)。
比如
nums = [1,2,3],就需要计算2^3 = 8个子集,每个最多判断 3 个位置。
💾 四、空间复杂度分析
空间复杂度:O(n * 2^n)(输出结果空间)
-
每个子集可能长度为
n,最多有2^n个子集。 -
所以总的空间用于保存输出结果是
O(n * 2^n)。
额外空间(不含输出):O(n)
-
每次生成一个子集使用一个列表(临时变量
subsets),最多长度为n。 -
所以辅助空间是
O(n)。