题目描述:
给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
示例 1:
输入: nums = [1,2,3]
输出: [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
示例 2:
输入: nums = [0]
输出: [[],[0]]
提示:
1 <= nums.length <= 10-10 <= nums[i] <= 10nums中的所有元素 互不相同
思路:
dfs深度优先搜索的经典题目,思想就是穷举所有可能的路径。
因为之前总结说dfs喜欢for循环,但是这里用for循环是不对的,正确的做法是一个dfs里调用两个dfs,分为”有“和”无“两个分支,刚好有n层,一共是2^n次方个解。
那其实之前的很多题,说dfs喜欢循环,是因为有循环那么多个分支而已。很多判断是为了剪枝。
实现:
dfs都要有的res,holder,输入数组nums,再就是起点start。
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
List<Integer> holder = new ArrayList<>();
dfs(res, holder, 0, nums);
return res;
}
private void dfs(List<List<Integer>> res, List<Integer> holder, int start, int[] nums) {
if (start == nums.length) {
res.add(new ArrayList<Integer>(holder));
return;
}
holder.add(nums[start]);
dfs(res, holder, start+1, nums);
holder.remove(holder.size()-1);
dfs(res, holder, start+1, nums);
}
}
另外去年9月还写出来一个基于位运算的实现,主要利用了子集数量是2的n次方的性质。
class Solution {
public List<List<Integer>> subsets(int[] nums) {
//数组长度大于30的时候这个方法就不适用了
// 主要依赖于这个全部子集的属性,n个元素,一共有2^n个子集
int n = nums.length;
int total = 1 << n;
List<List<Integer>> res = new ArrayList<>();
for (int i = 0; i < total; i++) {
// 每个i对应一个结果,需要一个List
List<Integer> list = new ArrayList<>();
for (int j = 0; j < n; j++) {
//对数组元素遍历
if (((i >> j) & 1) == 1) {
// i >> j是想把每一位都挪到最低位,然后和1取与,1就保留,0就算了
list.add(nums[j]);
}
}
res.add(new ArrayList<Integer>(list));
}
return res;
}
}
仅供参考。