返回
穷举子集之美:LeetCode 90. 子集 II(重复元素)的递归解法
前端
2023-11-15 09:27:20
LeetCode 题解:90. 子集 II:递归+for循环+回溯,JavaScript,详细注释
我们先来认识一下什么是子集。子集是指一个集合的元素中的一些元素构成的集合,包括空集。给定一个包含重复元素的集合,我们的目标是找到它所有的子集。
这道题最直观的解法就是使用递归。递归的基本思路是:对于一个集合,我们可以把它分解成一个元素和剩余的元素,然后对剩余的元素进行递归,将元素加入或不加入到子集中,以此穷举出所有的子集。
为了避免重复,我们在递归过程中使用一个 visited
数组来记录每个元素是否已经加入到子集中。具体步骤如下:
- 创建一个函数
subsetsWithDup
,接收一个数组nums
作为参数。 - 创建一个结果数组
result
和一个visited
数组,其中visited
数组与nums
数组长度相等,并初始化为false
。 - 调用递归函数
dfs
,从索引 0 开始遍历nums
数组。 - 在
dfs
函数中,如果visited[i]
为true
,则说明元素nums[i]
已经加入到子集中,直接返回。否则,将visited[i]
设为true
,将nums[i]
加入到子集subset
中,并调用dfs
函数从索引i+1
开始继续遍历nums
数组。 - 在
dfs
函数中,如果到达了数组的末尾,则将子集subset
加入到结果数组result
中。 - 在
dfs
函数中,将visited[i]
设回false
,并将nums[i]
从子集subset
中弹出。 - 返回
result
。
/**
* LeetCode 90. 子集 II
*
* @param {number[]} nums
* @return {number[][]}
*/
const subsetsWithDup = function (nums) {
if (nums === null || nums.length === 0) {
return [[]];
}
nums.sort((a, b) => a - b); // 排序数组,以便去除重复元素
const result = [];
const visited = new Array(nums.length).fill(false);
const dfs = (i, subset) => {
if (i === nums.length) {
result.push(subset.slice());
return;
}
if (visited[i]) {
return;
}
// 选择当前元素
subset.push(nums[i]);
visited[i] = true;
dfs(i + 1, subset);
// 不选择当前元素
subset.pop();
visited[i] = false;
dfs(i + 1, subset);
};
dfs(0, []);
return result;
};
时间复杂度
解法的时复杂度为O(2^n),其中n为输入数组的长度。
空间复杂度
解法的空间复杂度为O(n),其中n为输入数组的长度。