leetcode 子集 (c++实现)

  我的思路比较常见,是用回溯法,效果一般,代码如下:

class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int>> res;
        int n = nums.size();
        for (int i = 1; i < n; i++) {
            vector<int> subset = {};
            backTrack(nums, res, subset, i, 0);
        }
        vector<int> subset = {};
        res.push_back(subset);
        res.push_back(nums);
        return res;
    }
    
    void backTrack(vector<int>& nums, vector<vector<int>>& res, vector<int>& subset, int len, int index) {
        if (subset.size() == len) {
            res.push_back(subset);
            return;
        }
        for (int j = index; j < nums.size(); j++) {
            subset.push_back(nums.at(j));
            backTrack(nums, res, subset, len, j + 1);
            subset.pop_back();
        }
    }
};

  看到一个解法比较有意思,运行时间和我的一样,12ms,主要是利用二进制特性,先上代码:

class Solution {
public:
	vector<vector<int>> subsets(vector<int>& nums) {
		vector<vector<int>> result;
		int len = (0 ^ (1 << nums.size()));
		for (int i = 0; i < len; i++) {
			vector<int> t;
			int k = i;
			int j = 0;
			while (k) {
				if(k % 2)
					t.push_back(nums.at(j));
				k = k / 2;
				j++;
			}
			result.push_back(t);
		}
		return result;
	}
};

  这里有两点需要注意的是:
  1、len = (0 ^ (1 << nums.size())):这一步是求出有子集的个数,有元素 n n 个,那么子集的个数为 2 n 2^n 个,证明见链接,如果输入为 [1, 2, 3],自己个数为8。
  2、k % 2 和 k / 2:其实把子集这个问题转换成二进制发现,结果过就是对三位进行编码,如果子集为空集,则用三位编码得000,若子集为原数组本身,则用三位编码得111。那么求余和整除操作其实就是把三位编码中的1找出来,若为1,则 j++,然后push_back。
  下面的代码是最快实现,也就是另一种形式的回溯:

class Solution {
public:
    vector<vector<int>> res;
    vector<bool> visit;
    // p:位置 表示当前 执行到要确定 哪一个位置了
    void permuten(vector<int>& nums, int p, vector<int>& tmp, int count, int begin)
    {
        if (p == count)
        {
            res.push_back(tmp);
            return;
        }
        for(int i = begin; i < nums.size(); i++)
        {
            if(!visit[i])
            {
                // 一定加上改变 visit
                visit[i] = true;
                // 当前位置上的数确定了
                tmp.push_back(nums[i]);
                // 继续确定下一个位置
                permuten(nums, p+1, tmp, count, i + 1);
                // 执行到这里 表示所有位置上的数已经确定了 本次可以结束了
                // 弹出当前的数 看还有没有其他可能
                // 回溯
                tmp.pop_back();
                // 一定加上改变 visit
                visit[i] = false;
            }
        }
    }
    
     vector<vector<int>> subsets(vector<int>& nums) {
        res.clear();
        if(nums.size() == 0) return {};
         res.push_back({});
         for(int i = 1; i < nums.size() + 1; i++)
         {
            vector<int> tmp;
            // vector赋值
            visit = vector<bool>(i ,false);
            permuten(nums, 0, tmp, i, 0);   
         }
        return res;
    }
};
引用与感谢
发布了27 篇原创文章 · 获赞 10 · 访问量 5022

猜你喜欢

转载自blog.csdn.net/l1l1l1l/article/details/89947614