题解 | #集合的所有子集#

集合的所有子集

http://www.nowcoder.com/practice/c333d551eb6243e0b4d92e37a06fbfc9

题目:集合中的所有子集

描述:现在有一个没有重复元素的整数集合S,求S的所有子集
注意:你给出的子集中的元素必须按升序排列,给出的解集中不能出现重复的元素。

示例1:输入:[1,2,3],返回值:[[],[1],[2],[3],[1,2],[1,3],[2,3],[1,2,3]]

解法一:
思路分析:初读题目,我们可以看出来这是初中的一道数学题目,题目要求输出S的所有子集,这里我们想到首先肯定是空子集,首先将空子集传入最终设计的容器res中,题目要求所有的子集必须按照升序排列,所以我们可以调用sort()函数,首先就对该集合进行元素排序,然后挨个进行输出,用i表示数位,当i等于1的时候,输出子集数量为1的子集,依次类推,构建一个循环,实际上相当于,用暴力法将每个符合条件的子集挨个添加到容器当中。

实例分析:输入:[1,2,3]

输入集合

1

2

3

首先容器res设定,sub暂存容器,排序,将空子集添加res

res内部有

排序后

1

2

3

1[]

2[1],[2],[3]

3[1,2],[1,3],[2,3]

4[1,2,3]

i = 1

k = 1,位数为1,挨个push S[i],判断后,pop()

i = 2

k = 2,位数为2,挨个push S[i],判断后,pop()

i = 3

k = 3,位数为3,挨个push S[i],判断后,pop()

循环结束,输出最终值

最终值为:[],[1],[2],[3],[1,2],[1,3],[2,3],[1,2,3]


其中按位数输出子集的代码为:


void subset(vector&S, vector &vec, vectorsub, int start, int k) {         if (k == sub.size()){//当循环满足条件后,存储进一个集合当中             vec.push_back(sub);             return;         }         for (int i = start; i < S.size(); ++i) {//存储的顺序             sub.push_back(S[i]);             subset(S, vec, sub, i+1, k);             sub.pop_back();     } }


具体C++代码为: 
class Solution {
public:
    vector<vector<int> > subsets(vector<int> &S) {
        vector<vector<int>> res;//设置最终存放的对象
        int size = S.size();//S中包含多少元素
        if (size == 0)
            return res;
        vector<int> sub;
        sort(S.begin(), S.end());//题目要求按顺序排放
        res.push_back(sub);//空子集是所有集合的子集
        for (int i = 1; i <= S.size(); ++i) {//i表示位数,i = 1时表示返回一位的子集
            subset(S, res, sub, 0, i);
        }
        return res;
    }
    void subset(vector<int> &S, vector<vector<int> > &vec, vector<int> sub, int start, int k) {
        if (k == sub.size()){//当循环满足条件后,存储进一个集合当中
            vec.push_back(sub);
            return;
        }
        for (int i = start; i < S.size(); ++i) {//存储的顺序
            sub.push_back(S[i]);
            subset(S, vec, sub, i+1, k);
            sub.pop_back();
        }
    }
};

因为其中包括两个for循环用于判断和输出子集,第一个for循环为输出子集的位数,第二个for循环为判断存储的子集满足并输出,所以其时间复杂度为O(N^2),空间复杂度为O(N)。


解法二:

思路分析:同样也可以使用递归遍历的方法进行判断,每个元素只有两种状态,选择或者不选择,选择当前第i个元素,计算出其的所有组合结果,或者是不选择该元素,返回其组合的结果值。还是首先把集合内的元素进行排序,添加一个空子集,随后进行判断。

具体java代码为:


import java.util.*;
 
public class Solution {
    public ArrayList subsets(int[] S) {
        Arrays.sort(S);//升序排列
        ArrayList res = new ArrayList();
        ArrayList sub = new ArrayList();
        res.add(sub);//空子集添加
        for(int i = 0 ; i< S.length; i++){ //选择了第i个后,将sub增加一个S[i] ArrayList newres = new ArrayList();//重新创建一个保存对象
            for(ArrayListlast : res){
                ArrayList newres1 =  new ArrayList();
                newres1.addAll(last);//将last中的所有元素添加到newres1中
                newres1.add(S[i]);//改变newres1的值,然后保存
                newres.add(newres1);
            }
            res.addAll(newres);//将最终值添加到res中
        }
        return res;
    }
}


设定了两层for循环,故时间复杂度为O(N^2),空间复杂度为O(N)。


算法自然分析 文章被收录于专栏

在解决问题的同时,不断与人交流学习,通过牛客各式各样的题目,学习分享。

全部评论
for循环里还包了个递归,时间复杂度也是o(n!)吧
点赞 回复 分享
发布于 2021-11-30 23:00

相关推荐

11 1 评论
分享
牛客网
牛客企业服务