力扣HOT100之回溯:78. 子集
这道题之前刷代码随想录的时候做过,现在又给忘完了,不过看了下自己当时写的博客,一下子就明白过来了,这道题收集的是组合结果,元素的排列顺序不重要,这与上一题46.全排列是不一样的,我们对比一下可以发现,全排列是在每一个叶子节点(触发递归终止条件)才收集结果,而对于这道题而言,我们并不是只有在叶子节点才收获结果,事实上,每向path
数组中添加一个新的元素,我们就可以收获一次结果,那么我们怎么知道当前添加的这个元素在之前没有被统计过呢?我们需要借助一个变量start_index
,在递归函数的主体部分,我们直接从下标为start_index
的元素开始遍历,而start_index
左侧的元素已经被统计过,不再考虑。
例如,对于输入[1, 2, 3]
我们先统计包含1
的所有子集[1], [1, 2], [1, 2, 3], [1, 3]
后,start_index
应当更新为1,开始记录所有包含2
的子集,由于元素1
的下标为0
,在后续的统计中不会被重复添加。
这样,我们在记录完所有子集后,一定不会重复,考虑到空集也是符合条件的子集,因此我们需要在递归函数彻底调用结束后及时添加一个空列表进去,然后再返回。
class Solution {
public:vector<vector<int>> result; //用于保存所有的子集vector<int> path; //记录每个子集vector<vector<int>> subsets(vector<int>& nums) {backtracking(nums, 0);result.push_back({}); //添加空集return result;}void backtracking(vector<int>& nums, int start_index){//递归终止条件if(start_index >= nums.size()) //索引超出范围return ;//递归主体//start_index之前的元素已经添加过,不再考虑for(int i = start_index; i < nums.size(); i++){path.emplace_back(nums[i]);result.emplace_back(path);backtracking(nums, i + 1);path.pop_back();}}
};