赞
踩
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例: 输入: nums = [1,2,3] 输出: [ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ]
注意本题与之前所有回溯算法所不同的一点就是,之前都是在叶子节点返回结果,而求子集需要在所有节点返回结果。同时这个终止条件可写可不写。
- class Solution {
- private:
- vector<vector<int>> result;
- vector<int> path;
- void backtracking(vector<int>& nums, int startIndex) {
- result.push_back(path);
- if(startIndex == nums.size()) {
- return;
- }
- for(int i = startIndex; i < nums.size(); i++) {
- path.push_back(nums[i]);
- backtracking(nums, i+1);
- path.pop_back();
- }
- }
- public:
- vector<vector<int>> subsets(vector<int>& nums) {
- result.clear();
- path.clear();
- backtracking(nums,0);
- return result;
- }
- };
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例:
本题是上一题和组合总和II的结合题,需要注意以下几点:终止条件可以不写,最后因为for循环一定都会终止;每次递归都返回结果,并不仅仅是叶子节点;注意树层去重和树枝去重的区别,本题要求树层去重才会直接continue;在回溯之前要现将nums排序才行。
- class Solution {
- private:
- vector<vector<int>> result;
- vector<int> path;
- void backtracking(vector<int>& nums, int startIndex, vector<bool>& used) {
- result.push_back(path);
- for (int i = startIndex; i < nums.size(); i++) {
- // used[i - 1] == true,说明同一树枝candidates[i - 1]使用过
- // used[i - 1] == false,说明同一树层candidates[i - 1]使用过
- // 而我们要对同一树层使用过的元素进行跳过
- if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {
- continue;
- }
- path.push_back(nums[i]);
- used[i] = true;
- backtracking(nums, i + 1, used);
- used[i] = false;
- path.pop_back();
- }
- }
-
- public:
- vector<vector<int>> subsetsWithDup(vector<int>& nums) {
- result.clear();
- path.clear();
- vector<bool> used(nums.size(), false);
- sort(nums.begin(), nums.end()); // 去重需要排序
- backtracking(nums, 0, used);
- return result;
- }
- };
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
set去重版本:同样也是树层去重,因为如果经历过递归以后不算重复,只有for循环的时候才算重复(树层去重)
- class Solution {
- private:
- vector<vector<int>> result;
- vector<int> path;
- void backtracking(vector<int>& nums, int startIndex) {
- result.push_back(path);
- unordered_set<int> uset; //去重集合
- for (int i = startIndex; i < nums.size(); i++) {
- if (uset.find(nums[i]) != uset.end()) { //如果集合里面有了这个元素,说明重复
- continue;
- }
- uset.insert(nums[i]); //每次插入一个进入集合里面
- path.push_back(nums[i]);
- backtracking(nums, i + 1);
- path.pop_back();
- }
- }
-
- public:
- vector<vector<int>> subsetsWithDup(vector<int>& nums) {
- result.clear();
- path.clear();
- sort(nums.begin(), nums.end()); // 去重需要排序
- backtracking(nums, 0);
- return result;
- }
- };
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
startIndex:
- class Solution {
- private:
- vector<vector<int>> result;
- vector<int> path;
- void backtracking(vector<int>& nums, int startIndex) {
- result.push_back(path);
- for (int i = startIndex; i < nums.size(); i++) {
- // 而我们要对同一树层使用过的元素进行跳过
- if (i > startIndex && nums[i] == nums[i - 1] ) { // 注意这里使用i > startIndex
- continue;
- }
- path.push_back(nums[i]);
- backtracking(nums, i + 1);
- path.pop_back();
- }
- }
-
- public:
- vector<vector<int>> subsetsWithDup(vector<int>& nums) {
- result.clear();
- path.clear();
- sort(nums.begin(), nums.end()); // 去重需要排序
- backtracking(nums, 0);
- return result;
- }
- };
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是2。
示例:
说明:
本题同样需要去重,同时加了递增,并且不能排序,所以不能使用used数组的方法了,于是用set来进行去重:注意每层里面都有一个set维护,他只负责自己这一层的。
- class Solution {
- private:
- vector<vector<int>> result;
- vector<int> path;
- void backtracking(vector<int>& nums, int startIndex) {
- if (path.size() > 1) {
- result.push_back(path);
- // 注意这里不要加return,要取树上的节点
- }
- unordered_set<int> uset; // 使用set对本层元素进行去重
- for (int i = startIndex; i < nums.size(); i++) {
- if ((!path.empty() && nums[i] < path.back())
- || uset.find(nums[i]) != uset.end()) {
- continue;
- }
- uset.insert(nums[i]); // 记录这个元素在本层用过了,本层后面不能再用了
- path.push_back(nums[i]);
- backtracking(nums, i + 1);
- path.pop_back();
- }
- }
- public:
- vector<vector<int>> findSubsequences(vector<int>& nums) {
- result.clear();
- path.clear();
- backtracking(nums, 0);
- return result;
- }
- };
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
以上代码用我用了unordered_set<int>
来记录本层元素是否重复使用。
其实用数组来做哈希,效率就高了很多。
注意题目中说了,数值范围[-100,100],所以完全可以用数组来做哈希。
程序运行的时候对unordered_set 频繁的insert,unordered_set需要做哈希映射(也就是把key通过hash function映射为唯一的哈希值)相对费时间,而且每次重新定义set,insert的时候其底层的符号表也要做相应的扩充,也是费事的。
那么优化后的代码如下:nums[i] + 100保证方括号里的值永远大于等于0
- class Solution {
- private:
- vector<vector<int>> result;
- vector<int> path;
- void backtracking(vector<int>& nums, int startIndex) {
- if (path.size() > 1) {
- result.push_back(path);
- }
- int used[201] = {0}; // 这里使用数组来进行去重操作,题目说数值范围[-100, 100]
- for (int i = startIndex; i < nums.size(); i++) {
- if ((!path.empty() && nums[i] < path.back())
- || used[nums[i] + 100] == 1) {
- continue;
- }
- used[nums[i] + 100] = 1; // 记录这个元素在本层用过了,本层后面不能再用了
- path.push_back(nums[i]);
- backtracking(nums, i + 1);
- path.pop_back();
- }
- }
- public:
- vector<vector<int>> findSubsequences(vector<int>& nums) {
- result.clear();
- path.clear();
- backtracking(nums, 0);
- return result;
- }
- };
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。