LeetCode | 78. 子集

原题Medium):

  给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

  说明:解集不能包含重复的子集。

  

 

思路一:回溯

  深度优先,从单一数组成员出发,以下标为剪枝条件,即不能搜索时不能小于当前下标,这防止了重复子集的出现,且途中把遇到的元素都加入临时数组,并把临时数组加入解集。

 1 void recall(vector<vector<int>> &res, vector<int> &nums, vector<int> tmp, int index){
 2         if(tmp.size()<=nums.size())
 3             res.push_back(tmp);
 4         for(int i = index;i<nums.size();i++)  //以下标index起始,防止了重复子集的出现
 5         {
 6             tmp.push_back(nums[i]);       //把当前下标的成员加入临时子集,并深度搜索拥有此下标成员后的组合
 7             recall(res, nums, tmp, i+1);
 8             tmp.pop_back();            //在穷尽数组后,把当前下标成员弹出子集。
 9         }
10     }
11     vector<vector<int>> subsets(vector<int>& nums) {
12         vector<vector<int>> res;
13         vector<int> tmp;
14         recall(res, nums, tmp, 0);  //从空集出发,这就包括了空集
15         return res;
16     }

 

思路二:位运算

  独热码,获取数组长度,得其数组状态数(有多少状态就有多少子集)subset_sum,在示例中subset_sum就为8(1<<3),用连续的独热码依次标记nums数组的每一个元素,这体现在第二个循环的1<<j里,第0号元素的独热码为001,第1号的独热码为010,第2号的独热码为100。我们能通过单个元素的编码( i<< j)和每个子集的编码( i )进行比较而轻易地知道这个元素在不在这个子集中。例如当 i = 5 时,此时其二进制为101,这代表的子集为{1,3},则只有j为0(1<<0 = 001)或者j为2(1<<2 = 100)时,按位与运算的结果(结果为001和100)才为非0,可把nums[0]与nums[2]加入外循环定义的子集。

 1 vector<vector<int>> subsets(vector<int>& nums) {
 2     vector<vector<int>>subset_set;
 3     int subset_num = 1 << nums.size();  //获取数组长度,得其数组状态数(有多少状态就有多少子集)
 4     for (int i = 0; i<subset_num; i++) {
 5         vector<int>subset;
 6         for (int j = 0; j<nums.size(); j++) {
 7             if (i & 1 << j) {        //单个元素的编码和每个子集的编码进行按位与运算
 8                 subset.push_back(nums[j]);  
 9             }
10         }
11         subset_set.push_back(subset);
12     }
13     return subset_set;
14 }
posted @ 2019-10-18 11:06  羽园原华  阅读(112)  评论(0编辑  收藏  举报