LeetCode中国,https://leetcode-cn.com/problems/subsets/。
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
输入: nums = [1,2,3]
输出:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
LeetCode 给出本题难度中等。
根据输入的数列,生成所有的子集。很明显,这是一个回溯算法题目。
本题的核心就是如何生成子集。也就是说利用回溯算法生成所有的子集。下面我们来分析一下样例数据。样例数据为 [1, 2, 3],数列的长度为 3,那么我们的任务就是如何生成所有的子集。
我们可以考虑使用一个循环来生成子集。什么意思呢,这个循环中,表示从第 i 个位置开始,到数列的结束,依次生成子集。循环代码如下:
for (int i=pos; i
下面我们用一张图来说明一下对应的输入数据的搜索过程:
从上图,我们可以清晰的看到,如何从空集开始,逐步搜索的过程。
参考输入样例数据分析。
设计搜索函数的核心就是确定要几个参数。碰到这个问题,我们先不管三七二十一,将函数写上去,然后再逐步确定需要几个参数。这是写回溯算法的套路。
1、一个数组,用来当前的所有数据集。
2、一个数组,用来当前的已经生成的子集。
3、一个整数,表示位置信息,即在所有数据集的索引。
这样,我们就可以设计出一个带有 3 个参数的搜索函数,原型如下。
void dfs(vector& nums, vector path, int pos);
这题的返回条件为所有数据搜索完毕。
套路回溯即可,即套用回溯算法模板即可。
class Solution {
public:
vector> ans;
/*
参数1:
参数2:
参数3:从pos位置开始选
*/
void dfs(vector& nums, vector path, int pos) {
ans.push_back(path);
for (int i=pos; i> subsets(vector& nums) {
vector path;
dfs(nums, path, 0);
return ans;
}
};
当然,我们还可以套用标准的回溯模板来实现。也就是搜索的方法不一样,用一个比较容易理解的方法进行搜索,就是每次搜索按个数进行。第一次搜索所有 0 个数字子集,第二次搜索所有 1 个数字子集,第三次搜索所有 2 个数字字节,...,最后一次搜索所有 n 个数据子集。
这样,我们可以绘制出对应的样例数据搜索过程。
其他地方就不写了,基本是雷同的。
class Solution {
public:
vector> ans;
int n, k;
/*
参数1:
参数2:
参数3:从pos位置开始选
*/
void dfs(vector& nums, vector path, int pos) {
//退出条件
if (path.size() == k) {
//搜索到k个
ans.push_back(path);
return;
}
for (int i=pos; i> subsets(vector& nums) {
n = nums.size();
vector path;
for (k=0; k<=n; k++) {
dfs(nums, path, 0);
}
return ans;
}
};
由于这样的搜索 O(n*2^n),所以和第一个方案比对,明显效果差了很多。但是这个方案更加容易理解。