78. 子集

题目描述

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

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

输入输出

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

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

基本思路

先回顾一下 46. 全排列 回溯算法的解题模板

1
2
3
4
5
6
7
8
9
result = []
def backtrack(路径, 选择列表):
if 满足结束条件:
result.add(路径)
return
for 选择 in 选择列表:
做选择
backtrack(路径, 选择列表)
撤销选择

本题中的代码思路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
vector<int> t;
void dfs(int cur, int n) {
if (cur == n) {
// 记录答案
// ...
return;
}
// 考虑选择当前位置
t.push_back(cur);
dfs(cur + 1, n);
t.pop_back();
// 考虑不选择当前位置
dfs(cur + 1, n);
}
  1. 在进入dfs(cur, n)之前 [0, cur-1]位置状态已经确定 但是[cur, n-1]的状态是未知的
  2. dfs就用于确定状态 并确定dfs(cur+1, n)
  3. 对于cur位置需要考虑nums[cur]要不要取 如果取 要加入tmp中 再执行dfs(cur+1, n) 执行结束后需要对tmp进行回溯
  4. 如果不取,则直接执行 dfs(cur+1,n) 在整个递归调用的过程中,cur 是从小到大递增的,当 cur 增加到 n 的时候,记录答案并终止递归。
  5. 性能:
    1. 时间复杂度:$O(n \times 2 ^ n)$ 一共$2^n$个状态,每种状态需要 $O(n)$ 的时间来构造子集。
    2. 空间复杂度:$O(n)$ 临时数组tmp的空间代价是$O(n)$ 递归时栈的空间代价是$O(n)$

java实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
List<Integer> tmp = new ArrayList<Integer>();
List<List<Integer>> res = new ArrayList<List<Integer>>();
public List<List<Integer>> subsets(int[] nums) {
dfs(0, nums);
return res;
}

public void dfs(int cur, int[] nums){
if(cur == nums.length){
res.add(new ArrayList<Integer>(tmp));
return;
}
tmp.add(nums[cur]);
dfs(cur + 1, nums);
tmp.remove(tmp.size() - 1);
dfs(cur + 1, nums);
}
}