1 题目
题目:子集(Subsets)
描述:给定一个含不同整数的集合,返回其所有的子集。子集中的元素不能以降序排列,解集不能包含重复的子集。
lintcode题号——17,难度——medium
样例1:
输入:nums = [0]
输出:
[
[],
[0]
]
解释:
[0]的子集只有[]和[0]。
样例2:
输入:nums = [1,2,3]
输出:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
解释:
[1,2,3]的子集有[],[1],[2],[3],[1,2],[1,3],[2,3],[1,2,3]。
2 解决方案
2.1 思路
题目要求得到所有子集,深度优先搜索(Depth First Search)的经典应用场景之一就是在一定的条件下遍历所有解集,考虑使用DFS来解。
DFS常用于需要遍历出所有解的场景中,例如求所有子集、得到所有组合、全排列等经典问题。
2.2 图解
nums = [1,2,3]的情况下,深度优先搜索的图如下:
每个节点都生成一个子集,得到所有子集:
2.3 时间复杂度
深度优先搜索的时间复杂度是逻辑图上的节点数(即所有元素的组合数,n个元素,每个元素都有取或不取两种可能,所以是2的n次方)与处理每个节点的耗时(for循环n次)的乘积,该题的算法的时间复杂度为O(2^n * n)。
深度优先搜索的时间复杂度计算没有通用的方式,只能根据具体题目计算,可以理解成看作答案个数与构造每个答案花费的时间的乘积。
2.4 空间复杂度
使用了vector数据结构保存节点,算法的空间复杂度为O(n)。
3 源码
细节:
- 题目要求子集元素按升序排列,所以需要提前排序原数组。
C++版本:
/**
* @param nums: A set of numbers
* @return: A list of lists
*/
vector<vector<int>> subsets(vector<int> &nums) {
// write your code here
vector<vector<int>> results;
if (nums.empty())
{
results.push_back(vector<int>());
return results;
}
sort(nums.begin(), nums.end());
vector<int> path;
dfs(nums, path, 0, results);
return results;
}
void dfs(vector<int> & nums, vector<int> path, int startIndex, vector<vector<int>> & results)
{
results.push_back(path);
for (int i = startIndex; i < nums.size(); i++)
{
path.push_back(nums.at(i));
dfs(nums, path, i + 1, results);
path.pop_back();
}
}