题目
给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
示例 1:
输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
示例 2:
输入:nums = \[0]
输出:\[\[],\[0]]
思路
这道题是经典的回溯算法问题。我们可以通过深度优先遍历来枚举出所有可能的子集。具体实现有以下几个步骤:
- 初始化结果数组
result和当前子集path。 - 枚举起始位置
start,从0到nums的长度。 - 将当前数
nums[start]加入到子集中,并将子集path添加到结果数组result中。 - 回溯过程中,依次从子集
path中删除最后一个元素,得到新的子集path。 - 递归调用该过程,更新子集
path和结果数组result。
根据上面的思路,我们可以写出下面的 TypeScript 代码:
function subsets(nums: number[]): number[][] {
const result: number[][] = [];
const path: number[] = [];
function backtrack(start: number) {
// 将当前子集添加到结果数组中
result.push([...path]);
for (let i = start; i < nums.length; i++) {
// 加入当前数
path.push(nums[i]);
// 继续递归构造子集
backtrack(i + 1);
// 回溯,撤销选择
path.pop();
}
}
backtrack(0);
return result;
}
上述代码中,我们使用了回溯算法来枚举所有可能的子集。其中,backtrack 函数为主要递归函数,用于构造子集。在该函数中,我们首先将当前子集 path 添加到结果数组 result 中,然后依次选取后面的元素并递归调用 backtrack 函数,最后回溯撤销选择。
复杂度分析
- 时间复杂度为
对于本题的时间复杂度分析,我们需要考虑回溯函数的执行次数。由于每个元素都有两种状态(选或不选),因此回溯函数中的循环执行次数为 ,其中 表示原数组的长度。又因为在构造子集时需要复制数组和遍历数组,因此总的时间复杂度为 。
- 空间复杂度为
对于本题的空间复杂度,我们需要考虑递归调用时使用的栈空间和中间结果数组的空间。由于回溯算法是一种递归算法,因此在执行函数时会产生额外的栈空间,其空间复杂度为 。同时,在递归调用过程中,还需要使用一个中间结果数组来存储子集,其空间复杂度也为 。因此,总的空间复杂度为 。