Files
leetcode-master/problems/0078.子集.md
youngyangyang04 c761b59b50 Update
2020-09-18 16:51:32 +08:00

114 lines
3.2 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 题目地址
# 第78题. 子集
给定一组不含重复元素的整数数组 nums返回该数组所有可能的子集幂集
说明:解集不能包含重复的子集。
示例:
输入: nums = [1,2,3]
输出:
[
[3],
  [1],
  [2],
  [1,2,3],
  [1,3],
  [2,3],
  [1,2],
  []
]
# 思路
求子集问题和 求组合组合和分割问题又不一样了, 如何把 子集问题、组合问题、分割问题都抽象为一棵树的话,那么组合问题和分割问题都是找树的叶子节点,而子集问题是找树的所有节点!
取子集也是,其实也是一种组合位置,因为它的集合是无序的,子集{1,2} 和 子集{2,1}是一样的。 那么既然是无序写回溯算法的时候for就要从startIndex开始而不是从0开始
那有同学问题什么时候for可以从0开始求排列问题的时候就要从0开始因为集合是有序的{1, 2} 和{2, 1}是两个集合。
以示例中nums = [1,2,3]为例把求子集抽象为树型结构,如下:
<img src='../pics/78.子集.png' width=600> </img></div>
从图中,可以看出,遍历这个树的时候,把所有节点都记录下来,就是要求的子集。
来看一下我总结的回溯模板来:
```
backtracking() {
if (终止条件) {
存放结果;
}
for (选择:选择列表(可以想成树中节点孩子的数量)) {
递归,处理节点;
backtracking();
回溯,撤销处理结果
}
}
```
首先是终止条件终止条件就是startIndex已经大于数组的长度了就是终止了代码如下:
```
if (startIndex >= nums.size()) {
return;
}
```
但是,要明确的是,**求取子集问题,其实没有必要加终止条件,因为子集就是要遍历整个一棵树,不需要任何剪枝!**
大家一会看到下面整体代码的时候就知道了。
然后就是看如何写for循环**因为求子集也是无序的所以for循环要从startIndex开始**
代码如下:
```
for (int i = startIndex; i < nums.size(); i++) {
```
接下来就是递归与回溯,定一个`vector<int> path`用来收集子集的元素在回溯的时候还要弹出backtracking每次调用自己的时候记着要从i+1 开始,代码如下:
```
for (int i = startIndex; i < nums.size(); i++) {
path.push_back(nums[i]);
backtracking(nums, i + 1);
path.pop_back();
}
```
重点代码分析完之后,整体代码如下:
可以发现我在backtracking里并没有写终止条件因为本来我们就要遍历整颗树。
有的同学可能担心会不会无限递归? 并不会因为每次递归的下一层就是从i+1开始的。
# C++代码
```
class Solution {
private:
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& nums, int startIndex) {
result.push_back(path);
for (int i = startIndex; i < nums.size(); i++) {
path.push_back(nums[i]);
backtracking(nums, i + 1);
path.pop_back();
}
}
public:
vector<vector<int>> subsets(vector<int>& nums) {
result.clear();
path.clear();
backtracking(nums, 0);
return result;
}
};
```