求数组的所有子集
比如有数组[1, 2, 3],其元素数量n = 3,将那么其子集为
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
算法(1)
使用二叉树来构建含有子集的叶子节点,然后使用中序遍历
思路
每一层代表一个元素,左子树代表不使用该节点,右子树代表使用该节点,使用中序遍历来获得全部叶子节点,那么获得该数组的子集。
void getArr(vector<int> List,vector<<vector>> result, vector<int> temp,int level){
if(level == List.size()) {
result.add(temp);
}else{
vector<int> temp;
getArr(List, result, temp, level + 1);
temp.add(List[level]);
getArr(List, result, temp, level + 1);
}
}
算法(2)
思路
因为这个可以划分出比原问题规模小却同质的问题,那么是可以用递归解决。
vector<int> t;
vector<vector<int>> ans;
void dfs(int cur, vector<int>& nums){
if(cur==nums.size()){ //到最后一位
ans.push_back(t); //结束,返回上一层
return;
}
t.push_back(nums[cur]); //取第cur+1个元素
dfs(cur+1,nums);
t.pop_back(); //不取第cur+1个元素
dfs(cur+1, nums);
}
vector<vector<int>> subsets(vector<int>& nums) {
dfs(0,nums);
return ans;
}
上面的代码中,dfs(cur,nums)参数表示当前位置是cur,原序列是nums。原序列的每个位置在答案序列中的状态有被选中和不被选中两种。
我们用t数组存放已被选出来的数字。在进入dfs(cur,nums)之前,[0,cur-1]位置的状态是确定的,而[cur, n-1] 内的位置状态是不确定的。dfs(cur,n)需要确定cur位置的状态,然后求解子问题dfs(cur+1,n)。对于cur位置,我们需要考虑a[cur]位置的状态,如果取,我们需要把a[cur]放到一个临时的答案数组中(即t数组), 再执行dfs(cur+1, n), 执行结束后需要对t进行回溯;如果不去,则直接执行dfs(cur+1, n)。在整个递归调用过程中,cur是从小到大递增的,当cur增加到n的时候,记录答案并终止递归。
时间复杂度:
二进制枚举的时间复杂度是 O(n x 2^n), 一共2^n个状态,每种状态需要O(n)的时间来构造子集。
空间复杂度:
O(n)。临时数组t的空间代价是O(n),递归时栈空间的代价为O(n)。