LeetCode78/90 subset I/II**

一: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个结点开始思考。

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



class Solution {
public:
    void recursion(vector<int> temp, vector<int> &S, int level, vector<vector<int> > &result){
        if(level == S.size()){
            result.push_back(temp);
            return;
        }
        recursion(temp, S, level+1, result);   // 不选元素s[level]  通过只有1个元素来理解递归
        temp.push_back(S[level]);
        recursion(temp, S, level+1, result);   // 选择元素s[level]
    }
    vector<vector<int> > subsets(vector<int> &S) {
        sort(S.begin(), S.end());
        vector<int> temp;
        vector<vector<int> > result;
        recursion(temp, S, 0, result);
        return result;
    }
};

(2) 迭代

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

class Solution {
public:
    void iterSet(int i, vector<vector<int> > &result, vector<int> &S){
        int n = result.size();
        for(int j = 0; j < n; j++){
            vector<int> temp = result[j];   //集合中原有的子集保持不变,
            temp.push_back(i);             //但是对于每个子集都新遍历的一个元素S[i]加入构成新子集
            result.push_back(temp);
        }
    }
    vector<vector<int> > subsets(vector<int> &S) {
        vector<vector<int> > result;
        sort(S.begin(), S.end());
        vector<int> temp;
        result.push_back(temp);    // 集合中已有空集
        for(int i = 0; i < S.size(); i++){       // 对于每个元素都遍历一遍,
            iterSet(S[i], result, S);
        }
        return result;
        
    }
};
(3)位操作

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

class Solution {
public:
    vector<vector<int> > subsets(vector<int> &S) {
        vector<vector<int> > result;
        int n = S.size();
        int max = 1 << n;     // 最多状态数 存在用1 不存在用0
        int i = 0;
        sort(S.begin(), S.end());
        while(i < max){            // 对每一种状态进行遍历 并将其所对应的元素加入到集合中
            int j = i;
            vector<int> temp;
            /*for(int k= 0; k < n; k++){
                if((j & (1<<k)) != 0) temp.push_back(S[k]);
            }*/
            int index = 0;
            while(j>0){
                if(j&1) temp.push_back(S[index]);    // 第index为1 则加入s[index]位
                j = j >> 1;
                index++;
            }
            result.push_back(temp);
            i++;
        }
        return result;
        
    }
};

二: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的区别在于允许元素重复,这是当元素重复时,我们会发现每次加入的子集都是上次迭代的子集,因此需要对迭代法略做改进。

class Solution {
public:
    void iterSet(int i, vector<vector<int> > &result, vector<int> &S, int &t){
        int n = result.size();
		int count = 0;
		int j = 0;
		if(i-1>=0 && S[i]==S[i-1])j = n-t;   // 如果相等  则只能在上次加入的子集中加入s[i]
        for(;j < n; j++){
            vector<int> temp = result[j];   //集合中原有的子集保持不变,
			temp.push_back(S[i]);             //但是对于每个子集都新遍历的一个元素S[i]加入构成新子集
            result.push_back(temp);
			count++;                     //主要用来记录每次迭代加入集合个数
        }
		t = count;
    }
    vector<vector<int> > subsetsWithDup(vector<int> &S) {
        vector<vector<int> > result;
        sort(S.begin(), S.end());
        vector<int> temp;
        result.push_back(temp);    // 集合中已有空集
		int t = 0;
        for(int i = 0; i < S.size(); i++){       // 对于每个元素都遍历一遍,
			//if(i-1 < 0 || S[i] != S[i-1]) t = 0;
            iterSet(i, result, S, t);
        }
        return result;
    }
};



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值