Subset I & II

来源:互联网 发布:java棕色rgb 编辑:程序博客网 时间:2024/05/22 06:49

一:subset I

题目:

Given a set of distinct integers, S, return all possible subsets.

Note:

  • Elements in a subset must be in non-descending order.
  • The solution set must not contain duplicate subsets.

For example,
If S = [1,2,3], a solution is:

[  [3],  [1],  [2],  [1,2,3],  [1,3],  [2,3],  [1,2],  []]
链接:https://leetcode.com/problems/subsets/

分析:说白了就是求不同元素所构成的所有子集,这里提供三种方法

(1)递归————较难理解

对结合[1,2,3] 从0结点的1开始,都有选择或者不选,不选为空,放在左子树,选择放在由子树,这样就得到一棵完全二叉树,其中叶子结点就是我们所求。理解代码可以试着从只有1个结点开始思考。

图中与代码有差异,左右刚好相反



[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. class Solution {  
  2. public:  
  3.     void recursion(vector<int> temp, vector<int> &S, int level, vector<vector<int> > &result){  
  4.         if(level == S.size()){  
  5.             result.push_back(temp);  
  6.             return;  
  7.         }  
  8.         recursion(temp, S, level+1, result);   // 不选元素s[level]  通过只有1个元素来理解递归  
  9.         temp.push_back(S[level]);  
  10.         recursion(temp, S, level+1, result);   // 选择元素s[level]  
  11.     }  
  12.     vector<vector<int> > subsets(vector<int> &S) {  
  13.         sort(S.begin(), S.end());  
  14.         vector<int> temp;  
  15.         vector<vector<int> > result;  
  16.         recursion(temp, S, 0, result);  
  17.         return result;  
  18.     }  
  19. };  

(2) 迭代

通过上图我们可以看出,每次都是在原有的子集后面添加新元素S[i] 并加入到result中就会得到另外一个子集,因此可以采用迭代处理。

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. class Solution {  
  2. public:  
  3.     void iterSet(int i, vector<vector<int> > &result, vector<int> &S){  
  4.         int n = result.size();  
  5.         for(int j = 0; j < n; j++){  
  6.             vector<int> temp = result[j];   //集合中原有的子集保持不变,  
  7.             temp.push_back(i);             //但是对于每个子集都新遍历的一个元素S[i]加入构成新子集  
  8.             result.push_back(temp);  
  9.         }  
  10.     }  
  11.     vector<vector<int> > subsets(vector<int> &S) {  
  12.         vector<vector<int> > result;  
  13.         sort(S.begin(), S.end());  
  14.         vector<int> temp;  
  15.         result.push_back(temp);    // 集合中已有空集  
  16.         for(int i = 0; i < S.size(); i++){       // 对于每个元素都遍历一遍,  
  17.             iterSet(S[i], result, S);  
  18.         }  
  19.         return result;  
  20.           
  21.     }  
  22. };  
(3)位操作

对于n个元素,每个元素要么加入要么不加入,则会得到一个n位的二进制串,n为二进制串可以看做是一个状态或者说一个子集,每个元素与一位一一对应,状态的大小为1<<n. 对于每个状态j,我们通过判断第k位是否为1,为1则将S[k]加入vec,判断结束,将vec加入result即可。

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. class Solution {  
  2. public:  
  3.     vector<vector<int> > subsets(vector<int> &S) {  
  4.         vector<vector<int> > result;  
  5.         int n = S.size();  
  6.         int max = 1 << n;     // 最多状态数 存在用1 不存在用0  
  7.         int i = 0;  
  8.         sort(S.begin(), S.end());  
  9.         while(i < max){            // 对每一种状态进行遍历 并将其所对应的元素加入到集合中  
  10.             int j = i;  
  11.             vector<int> temp;  
  12.             /*for(int k= 0; k < n; k++){ 
  13.                 if((j & (1<<k)) != 0) temp.push_back(S[k]); 
  14.             }*/  
  15.             int index = 0;  
  16.             while(j>0){  
  17.                 if(j&1) temp.push_back(S[index]);    // 第index为1 则加入s[index]位  
  18.                 j = j >> 1;  
  19.                 index++;  
  20.             }  
  21.             result.push_back(temp);  
  22.             i++;  
  23.         }  
  24.         return result;  
  25.           
  26.     }  
  27. };  

二:subset II

题目:

Given a collection of integers that might contain duplicates, S, return all possible subsets.

Note:

  • Elements in a subset must be in non-descending order.
  • The solution set must not contain duplicate subsets.

For example,
If S = [1,2,2], a solution is:

[  [2],  [1],  [1,2,2],  [2,2],  [1,2],  []]
链接:https://leetcode.com/problems/subsets-ii/

分析:与unique paths的区别在于允许元素重复,这是当元素重复时,我们会发现每次加入的子集都是上次迭代的子集,因此需要对迭代法略做改进。

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. class Solution {  
  2. public:  
  3.     void iterSet(int i, vector<vector<int> > &result, vector<int> &S, int &t){  
  4.         int n = result.size();  
  5.         int count = 0;  
  6.         int j = 0;  
  7.         if(i-1>=0 && S[i]==S[i-1])j = n-t;   // 如果相等  则只能在上次加入的子集中加入s[i]  
  8.         for(;j < n; j++){  
  9.             vector<int> temp = result[j];   //集合中原有的子集保持不变,  
  10.             temp.push_back(S[i]);             //但是对于每个子集都新遍历的一个元素S[i]加入构成新子集  
  11.             result.push_back(temp);  
  12.             count++;                     //主要用来记录每次迭代加入集合个数  
  13.         }  
  14.         t = count;  
  15.     }  
  16.     vector<vector<int> > subsetsWithDup(vector<int> &S) {  
  17.         vector<vector<int> > result;  
  18.         sort(S.begin(), S.end());  
  19.         vector<int> temp;  
  20.         result.push_back(temp);    // 集合中已有空集  
  21.         int t = 0;  
  22.         for(int i = 0; i < S.size(); i++){       // 对于每个元素都遍历一遍,  
  23.             //if(i-1 < 0 || S[i] != S[i-1]) t = 0;  
  24.             iterSet(i, result, S, t);  
  25.         }  
  26.         return result;  
  27.     }  
  28. };  
0 0
原创粉丝点击