子集 leetcode java_[LeetCode]subsets/子集

Given a set of distinct integers, nums, return all possible subsets (the power set).

给定一组不重复整形数组,返回所有可能的子集(既幂集)

Note: The solution set must not contain duplicate subsets.

注:解不能包含重复的子集

Example:

Input: nums = [1,2,3]

Output:

[

[3],

[1],

[2],

[1,2,3],

[1,3],

[2,3],

[1,2],

[]

]

参考了网上网友的解法,主要由三个解法:

循环的方法:从空子集开始,每循环一个数字,把已有的所有子集取出来,加上新的数字作为结果放进去。

例如,一开始子集合中只包含[]一个集合;循环第一个数字1时候,拷贝[],然后放入1,得到[1]再放入总的集合,得到[],[1]。

接下来,循环到2,分别拷贝[]和[1],放入2,然后放入总的集合,得到[],[1],[2],[1,2]。以此类推。

public static List> subsets(int[] nums) {

List> result = new ArrayList<>();

List empty = new ArrayList<>();

result.add(empty);

//因为题目要求升序输出,所以需要先排序。

Arrays.sort(nums);

for (int i = 0; i < nums.length; i++) {

int size = result.size();

for (int j = 0; j < size; j++) { //循环所有已有的子集,用于拷贝

List temp = new ArrayList(result.get(j)); //ArrayList的拷贝构造函数

temp.add(nums[i]);

result.add(temp);

}

}

return result;

}

深度搜索优先:因为每个数字是否存在在子集中,只有是和否两个选择。所以可以将处理每一个数字作为一级二叉树的分支选择,根节点是空集合;第一级的两个分支分别表示第一个数字是否选择。

[]

/ \

/ \

/ \

[1] []

/ \ / \

/ \ / \

[1 2] [1] [2] []

/ \ / \ / \ / \

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

然后只需要按这个遍历所有叶子节点即可,所以有了深度优先搜索的解法。

public static List> subsets2(int[] nums) {

Arrays.sort(nums);

List> result = new ArrayList<>();

List empty = new ArrayList<>();

//从根节点开始遍历,当前节点是根节点

dfs(nums,0,empty,result);

return result;

}

public static void dfs(int[] nums, int index, List temp, List> result) {

//如果已经搜索到最大深度,说明到达了叶子结点,则停止搜索。

if (index == nums.length) {

result.add(temp);

return;

}

//假设左子树表示选择了当前数字,则先遍历选择的情况,拷贝当前已经构造的集合

List choiced = new ArrayList<>(temp);

//添加当前数字进去

choiced.add(nums[index]);

//继续遍历左分支

dfs(nums, index + 1, choiced, result);

//若未选择当前数字,既是遍历右子树,因此不需要对集合做任何更改,直接传递到右子树继续遍历。

dfs(nums, index + 1, temp, result);

}

位运算方式:跟第二种方案类似,每个数字是否出现在集合里应该只存在两种状态true或者false。因此可以得到一个表格:

1

2

3

结果

0

false

false

false

[]

1

false

false

true

[3]

2

false

true

false

[2]

3

false

true

true

[2,3]

4

true

false

false

[1]

5

true

false

true

[1,3]

6

true

true

false

[1,2]

7

true

true

true

[1,2,3]

既长度为n的数组最多有2^n这么多组合,只需要从0递增,然后每一位表示一个数字是否被选中,然后将数值转换成集合放入总集合即可。

public static List> subsets3(int[] nums){

Arrays.sort(nums);

List> result = new ArrayList<>();

//空集合需要单独处理一下,因为要从

//因为Java primitive类型最大只有long,还不是无符号的,只能表示最大2^64 / 2 - 1的数字,

//可能会不够用,所以使用BigInteger执行位操作

BigInteger bit = BigInteger.ZERO;

//最大长度为2^nums.length这么多

BigInteger bitMax = BigInteger.ONE.shiftLeft(nums.length);

List one = null;

while(bit.compareTo(bitMax)< 0) {

one = new ArrayList<>();

BigInteger temp = bit;

for(int i =0;i

//这里做了个反转,数字的最低位表示数组的最高位,本质没有区别,只影响加入汇总集合的顺序

if(temp.and(BigInteger.ONE).intValue() != 0) {

one.add(nums[i]);

}

//因为每次都用最低位比较,所以比较完之后要右移

temp = temp.shiftRight(1);

}

result.add(one);

//递增

bit = bit.add(BigInteger.ONE);

}

return result;

}

上面三个解法主要参考了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值