78. 子集
给你一个整数数组 nums
,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
标准的回溯解法
递归出口:遍历到数组末尾
递归体:数组中每个元素有选择和不选择两种情况,
选择当前元素:把当前元素临时保存,然后进入下一层递归,执行完回溯,把当前元素弹出
不选择当前元素:直接进入下一个位置的递归
vector<vector<int>> ans;
vector<int> sub;
void backtrack(vector<int> nums, int startIndex){
ans.push_back(sub); //未得到所有解,开始时加入集合,第一轮会把[]加入
if(startIndex == nums.size()) return;
for(int i = startIndex; i<nums.size(); ++i){
sub.push_back(nums[i]);
backtrack( nums, i + 1 ); //从下一位置开始
sub.pop_back();
}
}
vector<vector<int>> subsets(vector<int>& nums) {
backtrack(nums,0);
return ans;
}
};
90. 子集 II
给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。
分析:
与78.子集的区别是本题在给定集合中有重复元素,而求取的子集不能重复,多一个去重。
如果求出所有解再去重太浪费时间,应该在过程中去重,也就是不把重复的元素加入子集中。
示例 1:
输入:nums = [1,2,2] 输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]
什么时候去重?回溯的过程可以描述为二叉树,[1,2,2,]的选择路径是1->2->2深度为3, [1,2]是1->2此时深度为2,第二层有两个2可选,选择过第一个后,回溯到本层,在第二个2操作时需要去重
也就是将nums排序后,如果当前元素与前一个元素相同,直接continue跳过。
可以使用mark数组,元素选择为1,未选择是0,便于观察,和40.数组总和逻辑相同。但是本题中不是求全部排列,可以不使用标记数组直接向深一层递归
vector<vector<int>> ans;
vector<int> sub;
void backtrack(vector<int> nums, int startIndex, vector<bool>& mark){
ans.push_back(sub);
if(startIndex >= nums.size()) return;
for(int i = startIndex; i<nums.size(); ++i){
//mark[i-1] == 0 说明没有选中前一个 在同一层上
//可以不使用mark,因为要的不是全排列,下一层迭代从i+1开始
//if(i > startIndex && num[i] == num[i-1])
if(i>0 && nums[i] == nums[i-1] && mark[i-1] == false) continue;
sub.push_back(nums[i]);
mark[i] = true;
backtrack(nums, i+1, mark);
mark[i] = false;
sub.pop_back();
}
}
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
vector<bool> mark(nums.size(),false);
sort(nums.begin(), nums.end());
backtrack(nums, 0, mark);
return ans;
}
也可以使用set去重,每层用同一个set
vector<vector<int>> ans;
vector<int> sub;
void backtrack(vector<int>& nums, int startIndex) {
ans.push_back(path);
unordered_set<int> set;
for (int i = startIndex; i < nums.size(); i++) {
// 如果set中已有该元素就直接跳过
if (set.find(nums[i]) != set.end() ) {
continue;
}
sub.push_back(nums[i]);
set.insert(nums[i]);
backtrack(nums, i + 1);
sub.pop_back();
}
}
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
sort(nums.begin(), nums.end()); // 去重需要排序
backtrack(nums, 0);
return result;
}