幂集。编写一种方法,返回某集合的所有子集。集合中不包含重复的元素。
说明:解集不能包含重复的子集。
示例:
输入: nums = [1,2,3]
输出:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
题解:
思路一:二进制法
首先知道n个元素的集合的幂集个数为: n^2
nums = [1,2,3], 长度为3, 对于nums[]的位置,取值赋1,不取赋0。
如:
第0个子集: 0->[0,0,0]: []
第1个子集: 1->[0,0,1]: [nums[0]]
第2个子集: 2->[0,1,0]: [nums[1]]
第3个子集: 3->[0, 1, 1]: [nums[0],nums[1]]
第4个子集: 4->[1, 0, 0]: [nums[2]]
第5个子集: 5->[1, 0, 1]:[nums[0],nums[2]]
第6个子集: 6->[1, 1, 0]:[nums[1],nums[2]]
第7个子集: 7->[1, 1, 1]:[nums[0],nums[1],nums[2]]
JAVA代码:
class Solution {
public List<List<Integer>> subsets(int[] nums) {
// n个元素的集合,幂集个数为2^n
List<List<Integer>> res = new ArrayList<>();
int n = nums.length;
//i代表第i个集合
for (int i=0; i<(1<<n); i++){
List<Integer> temp = new ArrayList<>();
//j代表Nums[]的位置
for(int j=0; j<n; j++){
if ((i & (1<<j))!=0) {
temp.add(nums[j]);
}
}
res.add(temp);
}
return res;
}
}
思路二:枚举法
Nums = [1,2,3]
JAVA代码如下
class Solution {
public List<List<Integer>> subsets1(int[] nums) {
List<List<Integer>> output = new ArrayList<>();
//初始时output中只有一个空的list
output.add(new ArrayList<>());
for (int num: nums){
List<List<Integer>> newSubsets = new ArrayList<>(); //存放每加入一个新元素后新增的子集
//产生新的子集
for (List<Integer> curr1: output) {
newSubsets.add(new ArrayList<Integer>(curr1){{add(num);}}); //这一句不是太懂
}
//将新子集加入到output中
for (List<Integer> curr2: newSubsets)
output.add(curr2);
}
return output;
}
}
思路三:二叉树法
所有子集可构成一棵满二叉树,左右子树看作选和不选的问题,每一层则表示对第i个元素的选与不选。那么只要遍历这棵满二叉树即可。
JAVA代码:
public static void preOrder(List<List<Integer>> res, List<Integer> subset, int i, int[] nums){
if (i>=nums.length) return;
// 到了新的状态,记录新的路径,要重新拷贝一份
subset = new ArrayList<Integer>(subset);
res.add(subset);
preOrder(res, subset, i+1, nums);
subset.add(nums[i]);
preOrder(res, subset, i+1, nums);
}
思路四:回溯法
JAVA代码:
public static void backtrack(int[] nums, int i, List<Integer> sub, List<List<Integer>> res) {
for (int j = i; j < nums.length; j++) {
sub.add(nums[j]);
res.add(new ArrayList<Integer>(sub));
backtrack(nums, j + 1, sub, res);
sub.remove(sub.size() - 1);
}
}