题意:
给定一个整数数组 nums ,其中可能包含重复元素,请你返回这个数组的所有可能子集。
返回的答案中不能包含重复的子集,将答案按字典序进行排序。
方法一:
递归+剪枝
思路:递归回溯题型,先画图再写代码。得到的每棵子树都是集合的子树。
注意:这里要剪枝,当前一个数等于当前数并且前一个数未访问过,则跳过该分支。
if(i>0&&nums[i]==nums[i-1]&&vis[i-1]==0)//剪枝 continue;
class Solution { public: vector<vector<int>> res; int vis[15]={0}; vector<vector<int>> subsets(vector<int>& nums) { sort(nums.begin(),nums.end());//排序 vector<int> v; dfs(nums,0,v);//递归 return res; } void dfs(vector<int>& nums,int st,vector<int> &v){ res.push_back(v);//加入结果二维数组 int n=nums.size(); for(int i=st;i<n;i++){ if(i>0&&nums[i]==nums[i-1]&&vis[i-1]==0)//剪枝 continue; v.push_back(nums[i]); vis[i]=1; dfs(nums,i+1,v);//递归回溯 v.pop_back(); vis[i]=0; } } };
时间复杂度:空间复杂度:
方法二:
暴力递归(非剪枝)
思路:暴力递归。
利用一个无序set实现去重效果,忽略剪枝。
class Solution { public: vector<vector<int>> res; int vis[15]={0}; unordered_set<string> mySet;//无序set vector<vector<int>> subsets(vector<int>& nums) { sort(nums.begin(),nums.end());//排序 vector<int> v; dfs(nums,0,v);//递归 return res; } void dfs(vector<int>& nums,int st,vector<int> &v){ string str=""; for(int i=0;i<v.size();i++){ str+=v[i]+'0'; } // cout << str << endl; if(mySet.count(str)==0){//实现去重 res.push_back(v);//加入结果二维数组 mySet.insert(str); } int n=nums.size(); for(int i=st;i<n;i++){ v.push_back(nums[i]); vis[i]=1; dfs(nums,i+1,v);//递归回溯 v.pop_back(); vis[i]=0; } } };
时间复杂度:空间复杂度: