给定一个含不同整数的集合,返回其所有的子集、
给定一个含不同整数的集合,返回其所有的子集
注意事项
子集中的元素排列必须是非降序的,解集必须不包含重复的子集
样例
如果 S = [1,2,3],有如下的解:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
挑战
你可以同时用递归与非递归的方式解决么?
标签
递归 优步 脸书
相关题目
中等最小子集 46 % 容易
所有子集的和 16 % 容易
分割字符串 21 % 中等
恢复IP地址 24 % 中等
带重复元素的子集 26 % 中等
(1)Java
// 递归:实现方式,一种实现DFS算法的一种方式
class Solution {
/**
* @param S: A set of numbers.
* @return: A list of lists. All valid subsets.
*/
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> results = new ArrayList<>();
if (nums == null) {
return results;
}
if (nums.length == 0) {
results.add(new ArrayList<Integer>());
return results;
}
Arrays.sort(nums);
helper(new ArrayList<Integer>(), nums, 0, results);
return results;
}
// 递归三要素
// 1. 递归的定义:在 Nums 中找到所有以 subset 开头的的集合,并放到 results
private void helper(ArrayList<Integer> subset,
int[] nums,
int startIndex,
List<List<Integer>> results) {
// 2. 递归的拆解
// deep copy
// results.add(subset);
results.add(new ArrayList<Integer>(subset));
for (int i = startIndex; i < nums.length; i++) {
// [1] -> [1,2]
subset.add(nums[i]);
// 寻找所有以 [1,2] 开头的集合,并扔到 results
helper(subset, nums, i + 1, results);
// [1,2] -> [1] 回溯
subset.remove(subset.size() - 1);
}
// 3. 递归的出口
// return;
}
}
// // Non Recursion
// class Solution {
// /**
// * @param S: A set of numbers.
// * @return: A list of lists. All valid subsets.
// */
// public List<List<Integer>> subsets(int[] nums) {
// List<List<Integer>> result = new ArrayList<List<Integer>>();
// int n = nums.length;
// Arrays.sort(nums);
// // 1 << n is 2^n
// // each subset equals to an binary integer between 0 .. 2^n - 1
// // 0 -> 000 -> []
// // 1 -> 001 -> [1]
// // 2 -> 010 -> [2]
// // ..
// // 7 -> 111 -> [1,2,3]
// for (int i = 0; i < (1 << n); i++) {
// List<Integer> subset = new ArrayList<Integer>();
// for (int j = 0; j < n; j++) {
// // check whether the jth digit in i's binary representation is 1
// if ((i & (1 << j)) != 0) {
// subset.add(nums[j]);
// }
// }
// result.add(subset);
// }
// return result;
// }
// }
(2)C++
①
class Subsets{
public:
vector<vector<int>> getSubsets(vector<int>& nums){
vector<vector<int>> result;
vector<int> item;
result.push_back(item);
generate(0, nums, item, result);
return result;
}
private:
void generate(int i, vector<int>& nums,
vector<int>& item,
vector<vector<int>> &result){
if(i >= nums.size()){// 递归终止条件(因为 下标从0起)
return;
}
item.push_back(nums[i]);
result.push_back(item);// 将当前生成的子集item加入最终结果
generate(i + 1, nums, item, result);// 第一次递归
item.pop_back();// 回溯递归要素!递归回溯:放/不放入元素nums[i]
// 如:item中有[1,2]-->回溯变为item:[1]-->第二次递归后,变为item:[1,3]
generate(i + 1, nums, item, result);// 第二次递归
}
};
②class Solution2 {
private:
void helper(vector<vector<int> > &results,
vector<int> &subset,
vector<int> &nums,
int start) {
results.push_back(subset);
for (int i = start; i < nums.size(); i++) {
subset.push_back(nums[i]);
helper(results, subset, nums, i + 1);
subset.pop_back();
}
}
public:
vector<vector<int> > subsets(vector<int> &nums) {
vector<vector<int> > results;
vector<int> subset;
sort(nums.begin(), nums.end());
helper(results, subset, nums, 0);
return results;
}
};
③//位运算版
class Solution3 {
public:
vector<vector<int>> subsets(vector<int>& nums){
vector<vector<int>> result;
int all_set = 1 << nums.size(); //设置全部集合的最大值+1; 1 << n, 即2^n
for(int i = 0; i < all_set; i++){
vector<int> item;
for(int j = 0; j < nums.size(); j++){
if(i & (1 << j)){
// 构造数字i代表的集合,个元素存储至item
item.push_back(nums[j]);
}// 整数i代表从0至2^n-1这2^n-1个集合
// (1 << j)即为构造nums数组的第j个元素
// 若i & (1 << j)为真,则nums[j]放入item
result.push_back(item);
}
}
return result;
}
};