LeetCode78/90 子集
发布日期:2021-05-14 23:49:53 浏览次数:19 分类:精选文章

本文共 2487 字,大约阅读时间需要 8 分钟。

题目分析


第一个问题:得到所有可能的子集(幂集)

给定一个不含重复元素的整数数组 nums,返回该数组所有可能的子集。每个子集都不能包含重复元素。例如,输入 nums = [1, 2, 3],输出是所有 2^3=8 个子集。

为了实现这一点,可以使用递归的方法。每次递归选择当前元素是否加入子集,然后递归处理剩下的元素。这种方法的时间复杂度是 O(2^n),其中 n 是数组的长度。

代码实现思路:

  • 利用 dfs(深度优先搜索)函数遍历数组。
  • 在每一次递归中,决定当前元素是否加入子集。
  • 每次递归调用前,记录当前选择的元素数量。
  • 每次递归返回时,将当前子集添加到结果中。
  • 这样的方法简单且有效,但不适合处理大量元素的情况,因为计算量会非常大。

    第二个问题:得到所有可能的子集(幂集)

    给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集。子集仍然不能包含重复元素。例如,输入 nums = [1, 2, 2],输出是所有可能的不含重复子集。

    这个问题比第一个问题复杂,因为必须排除重复子集。为了解决这个问题,可以采取以下方法:

  • 使用递归的方法,但在递归过程中记录已经选择过的元素,避免重复选择。
  • 在递归过程中检查是否已经选择了当前元素,若已选择则不再选择。
  • 在代码实现中:

  • 输入数组可以包含重复元素。
  • 在递归时,检查当前元素是否已经被选择过。
  • 如果是,则进行下一个递归。
  • 如果不是,则将当前元素加入子集并继续递归。
  • 需要注意的是,这种方法虽然能解决重复元素的问题,但对于包含大量重复元素的数组,递归深度和层数会增加,导致性能问题。


    完整代码


    第一个问题:得到所有可能的子集

    功能说明代码

    int resSize;int[] res;void dfs(int[] nums, int numsSize, int[][] returnColumnSizes, int[] s, int s_index, int[][] res, int temp) {    res[resSize] = new int[s_index];    returnColumnSizes[resSize] = s_index;    for (int i = 0; i < numsSize; i++) {        // 生成所有可能的子集        // 复制当前状态到父节点        int[] newS = Arrays.copyOf(s, s_index + 1);        newS[s_index] = nums[i];        dfs(nums, numsSize, returnColumnSizes, newS, s_index + 1, res, temp);    }    // Base case: 空集    if (s_index == 0) {        return;    }}

    初始化调用

    int main() {    int numsSize = nums.length;    int[][] returnColumnSizes = new int[n];    Arrays.fill(returnColumnSizes, 0);    resSize = 0;    dfs(nums, numsSize, returnColumnSizes, s, 0, res);        return res;}

    第二个问题:优化处理重复元素

    功能说明代码

    int resSize;int[][] res;int last搬家;void dfs(int[] nums, int numsSize, int[][] returnColumnSizes, int[] s, int s_index, int[][] res, int temp, int last) {    // 这里检查当前元素是否是重复的元素    boolean isPreviouslySelected = false;    // 为了防止重复选择,检查是否已经选了相同的元素    for (int j = 0; j < last; j++) {        if (nums[j] == nums[last])         {            isPreviouslySelected = true;            break;        }    }    // 调用递归    if (isPreviouslySelected) {        return;    }    int lastIndex = last;    res[resSize] = new int[s_index + 1];    returnColumnSizes[resSize] = s_index + 1;    // 将当前元素加入s    s[s_index] = nums[lastIndex];        // 递归调用    dfs(nums, numsSize, returnColumnSizes, s, s_index + 1, res, temp, lastIndex + 1);        // 递归结束后,恢复状态    s = Arrays.copyOf(s, s_index);}int main() {    int[] nums = numsArray;    int[] s = new int[0];    int i;    dfs(nums, nums.length, returnColumnSizes, s, 0, res, temp, 0);        return res;}

    需要注意的是,在代码中我们通过记录上次选择的位置 last 来判断是否已经选中相同的元素。如果已经选中,则跳过,避免重复选择同一个元素。这样可以确保每个子集中的元素都是唯一的。

    上一篇:LeetCode17 电话号码的字母组合
    下一篇:LeetCode39/40 组合总和

    发表评论

    最新留言

    表示我来过!
    [***.240.166.169]2025年04月25日 05时14分05秒