Leetcode78. Subsets(q)

文章目录

链接

link

思路

没思路
看别人的方法。
有一种方法,每次遇到一个新的元素,1.不添加到原来的集合中 2.添加到原来的集合中。只有这两种情况。
在我看来比较难以实现的时是,因为不知道最终有多少个集合,所以不知道怎么分配内存。是先设置一个储存各种数组指针的数组吗?但是最后有多少个指针呢?
所以好像用c++麻烦一些,因为python数组可以随意边长。
不过,经查询资料,c++也可以

Vectors are sequence containers representing arrays that can change in size.
compared to arrays, vectors consume more memory in exchange for the ability to manage storage and grow dynamically in an efficient way.

python

1.

发现一个很有趣的事情。

class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        result = [[]]
        for num in nums:
            # 拷贝结果数组
            tem = result.copy()
            # 结果数组中的每个数组加上新数
            for a in tem:
                
                a.append(num)
                result += tem
            # 合并两个
            result += tem
        return result

尽管tem是result拷贝过来的,但是在修改tem中各个数组的时候,还是把result中的数组修改了。可见tem是result拷贝过来的,但是拷贝过来的仍然是result中的各个数组名,所以修改的时候仍然修改的是result的值。
怎么解决这个办法呢?能不能把result中的各个数组依次拷贝过来到tem中?貌似可以,但是好麻烦啊。
于是有了下面这块代码

class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        result = [[]]
        for num in nums:
            # 拷贝结果数组
            tem = []
            for array in result:
                tem.append(array.copy())
            # 结果数组中的每个数组加上新数
            for a in tem:
                a.append(num)
            # 合并两个
            result += tem
        return result

但是发现result的值并没有改变啊?!
发现,是因为result += tem 并没有改变result的值。必须利用.extend()函数才可以改变。

class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        result = [[]]
        for num in nums:
            # 拷贝结果数组
            tem = []
            for array in result:
                tem.append(array.copy())
            # 结果数组中的每个数组加上新数
            for a in tem:
                a.append(num)
            # 合并两个
            result.extend(tem)
        return result

终于
可以

。。。
发现自己基础知识还是不牢啊

2.

思路同c++2.
注意要给result初始化许多数组

class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        result = []
        ele_num = len(nums)
        sub_size = 2 ** ele_num
        for i in range(sub_size):
            result.append([])
        for i in range(ele_num):
            for j in range(sub_size):
                if j >> i & 1:
                    result[j].append(nums[i])
        return result

c++

1.

思路同python1.
(经常几种语言之间的语法搞混orz)

class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        int subset_num = pow (2, nums.size());
        vector<vector<int> > result (subset_num, vector<int>());
        vector<vector<int>> tem (subset_num, vector<int>());
        int num;
        result[0] = {};
        for(int i = 0; i  < nums.size(); i++){
            num = nums[i];
            tem.assign(result.begin(),result.end());
            for(int j = 0; j < tem.size(); j++){
                tem[j].push_back(num);
            }
            result.insert(result.end(),tem.begin(), tem.end());
        }
        return result;
    }
};

输出结果如下

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

不知道为啥多了很多重复的元素。
那就去重呗~(曲线救国)

unique()函数:unique函数比较的时相邻的两个元素,重复的放到vector尾部,返回值是重复元素的首地址。
vector.erase(unique(vector.begin(),vector.end()), vector.end());
2.
转化为set,在转为vector:这个思路比较简单,这里就不介绍了!

class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        int subset_num = pow (2, nums.size());
        vector<vector<int> > result (subset_num, vector<int>());
        vector<vector<int>> tem (subset_num, vector<int>());
        int num;
        result[0] = {};
        for(int i = 0; i  < nums.size(); i++){
            num = nums[i];
            tem.assign(result.begin(),result.end());
            for(int j = 0; j < tem.size(); j++){
                tem[j].push_back(num);
            }
            result.insert(result.end(),tem.begin(), tem.end());
        }
        result.erase(unique(result.begin(), result.end()), result.end());
        return result;
    }
};

过了,但是效率很低。那么,到底是什么让结果出现了重复元素呢?
原因就是,在刚开始还没有分配空间的时候,就为result[0] 赋值,这是不可以的,可以改为,1.分配一个单位的空间,然后赋值。2.还有一种方法,就是刚开始不用分配空间,但是初始化第一个为0的时候,用push_back()函数。3.直接初始化。(后两种用时更短)
1.

        vector<vector<int> > result (1, vector<int>());
        //可以直接写为 vector<vector<int> > result (1);
        vector<vector<int>> tem (1, vector<int>());
        int num;
        result[0] = {};
      

        vector<vector<int> > result ;
        vector<vector<int>> tem ;
        int num;
        result.push_back({});
     

        vector<vector<int> > result = {{}} ;
        vector<vector<int>> tem(result) ;
        int num;
        result.push_back({});
     

2.

参考别人的思路,可以用到位运算的方法。真的非常地巧妙。
集合中的所有元素,在集合中的每一个子集中,只有选或者不选两种情况。所以可以用1表示选,0表示不选。假设集合元素个数为n,那么总共就有2^n种情况。
0~(2^n-1)每一个数字代表一种情况。遇到是1的位置,添加对应元素即可。
即利用位运算右移,利用&判断最后一位是否为1。
刚开始写的版本

class Solution {
public:
        vector<vector<int>> subsets(vector<int>& nums) {
        int siz = nums.size();
        int sub_size = pow(2, siz);
        vector<vector<int> > subset_set (sub_size);
        int i,j;
        //遍历每一个子集
        for(i = 0; i < sub_size; i++){
            //遍历集合中的每一个元素,确定子集中是否有这个元素
            for(j = 0; j < siz; j++){
            	//判断**最后一位**是否为1
                if(i >> j & 1){
                    subset_set[i].push_back(nums[j]);
                }
            }
        }
     
        return subset_set;
        }
};
    

这样用时很长。用时8ms,打败56%。
那么,换一个不同的循环方式,是否能优化时间呢?
上一个循环是先遍历每一个子集,然后遍历每一个元素。如果先遍历每一个元素,再遍历每一个子集,所用时间会有不同吗?


        //遍历每一个元素
        for(i = 0; i < siz; i++){
            for(j = 0; j < sub_size; j ++){
                if(j >> i & 1){
                    subset_set[j].push_back(nums[i]);
                }
            }
        }  

用时4ms,打败90%。
q:为什么?以后来解答吧。

发布了74 篇原创文章 · 获赞 4 · 访问量 1449

猜你喜欢

转载自blog.csdn.net/weixin_44814121/article/details/100810854
今日推荐