一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第12天,点击查看活动详情。
1.题目一
78. 子集
给你一个整数数组 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] <= 10
nums 中的所有元素 互不相同
思路
回溯法三部曲
- 递归函数的返回值以及参数
- 回溯函数终止条件
- 单层搜索的过程 还是那句话画图能更清晰了解,此处我就不画图了。
1.子集的话没有明确的递归终止条件,只要是深搜过程中不重复的子集都可以加入res中 2.当for循环执行完成之后会自动开始回溯执行path.pop(),这也是不需要明确的递归终止条件的原因,会自动开始回溯
如果把 子集问题、组合问题、分割问题都抽象为一棵树的话,那么组合问题和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点!
其实子集也是一种组合问题,因为它的集合是无序的,子集{1,2} 和 子集{2,1}是一样的。
那么既然是无序,取过的元素不会重复取,写回溯算法的时候,for就要从startIndex开始,而不是从0开始!
当前递归结束后,要将当前的选择撤销,回到选择前的状态,去考察另一个选择,即进入下一轮迭代,尝试另一种切分的可能。
这样才能在解的空间树中,把路走全了,搜出所有的合法部分解。
代码
var subsets = function(nums) {
let res = [];
let path = [];
const dfs = (startIndex) => {
res.push(path.slice())
//当for循环执行完之后会自动开始回溯执行path.pop()
for(let i = startIndex; i < nums.length; i++) {
path.push(nums[i])
dfs(i+1)
path.pop()
}
}
dfs(0)
return res
};