题意描述:
给定一组不含重复元素的整数数组 nums
,返回该数组所有可能的子集(幂集)。
说明 :解集不能包含重复的子集。
示例:
输入: nums = [1,2,3]
输出:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
解题思路:
Alice: 这道题在哪也见过,而且当时没有做出来,😂
Bob: 😂我也没有思路,我们把例子列一列,找找规律吧。
Alice: 那就先写到四个元素的吧。
[ ] | [1] | [1, 2] | [1,2,3 ] | [1, 2, 3, 4 ] |
---|---|---|---|---|
[ ] | [ ] , 1 | [ ], 1, 2, 12 | [ ], 1, 2, 12, 3, 13, 23, 123 | … |
Bob: 这个表格画的不错呀,直接找“通项”公式还是有困难的,不过我好像发现了前后相邻两项之间的关系。
Alice: 相邻两项的递推公式 ? 是把 新增加的元素 在原来的子集上全部添加一遍 吗 ?
Bob: 对,你看 [1,2,3]
和 [1,2,3,4]
的子集,假设我们已经求出了 [1,2,3]
的子集,只需要 在 再把 4 这个元素再添加到已有的子集上,然后再加上 [1,2,3]
的子集就是[1,2,3,4]
的子集了。
Alice: 也就是说[1,2,3,4]
的子集可以分为两部分,有 4 的部分好没有 4 的部分。没有 4 的部分就是 [1,2,3] 的幂集,有 4 的部分就是 [1,2,3] 的幂集 全部再加一个 4。
Bob: 然后这就像是斐波那契数列一样,可以用递归的方法来做了。
Alice:😎😎。
代码:
Python 方法一: 递归。
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
return self.getSubsets(nums, [[]])
def getSubsets(self, nums: List[int], ans: List[List[int]]) -> List[List[int]]:
# 递归的终止条件
if len(nums) == 0:
return ans
else:
# 每次添加一个 nums[0] 到前面的子集中去
tmp = []
for x in ans:
tmp.append(x + [nums[0]])
ans.extend(tmp)
nums.pop(0)
return self.getSubsets(nums, ans)
Java 方法一: 递归。
class Solution {
int[] nums = null;
List<List<Integer>> ans = new ArrayList();
// 减少参数传递
public List<List<Integer>> subsets(int[] nums) {
this.nums = nums;
List<Integer> tmp = new ArrayList();
this.ans.add(tmp);
// init
return getSubsets(0);
}
public List<List<Integer>> getSubsets(int index){
// 递归求解
if(index == nums.length){
return this.ans;
}else{
int tmpLength = this.ans.size();
for(int i=0; i<tmpLength; ++i){
List<Integer> tmp = new ArrayList();
for(int j=0; j<this.ans.get(i).size(); ++j){
tmp.add(this.ans.get(i).get(j));
}
tmp.add(this.nums[index]);
this.ans.add(tmp);
}
return getSubsets(index+1);
}
}
}
易错点:
- 一些测试样例:
[]
[1]
[1,2]
[1,2,3]
[1,2,3,4]
- 答案:
[[]]
[[],[1]]
[[],[1],[2],[1,2]]
[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3],[4],[1,4],[2,4],[1,2,4],[3,4],[1,3,4],[2,3,4],[1,2,3,4]]
总结: