• Leetcode 90. 子集 II


    1.题目描述

    给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。

    解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。

    输入:nums = [1,2,2]
    输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]

    输入:nums = [0]
    输出:[[],[0]]

    • 提示:
      • 1 <= nums.length <= 10
      • -10 <= nums[i] <= 10

    2.思路分析

    本题与Leetcode 78 子集的区别就是集合里有重复元素,且要求子集去重。

    其实子集也是一种组合问题,因为它的集合是无序的,子集{1,2} 和 子集{2,1}是一样的。

    举个栗子: nums = [1,2,2]为例把求子集抽象为树型结构,如下:

    注: 去重需要先对集合排序

    在这里插入图片描述

    回溯三部曲:

    回溯函数要处理的参数以及返回值

    • 全局变量:result(保存子集集合,二维) path:子集收集元素 startIndex(控制下一层的起始位置)

      result,path = [], []
      def backtrack(nums:List[int], startIndex:int):
      
      • 1
      • 2

    递归终止条件:

    剩余集合为空时,即为叶子结点。

    if (startIndex >= len(nums)):
        return
    
    • 1
    • 2

    其实可以不需要加终止条件,因为startIndex >= nums.size(),本层for循环本来也结束了

    单层搜索逻辑

    • 如果判断同一树层上元素(相同的元素)是否使用过 ?
    • 如果nums[i] == nums[i - 1] 并且 used[i - 1] == False,就说明:前一个树枝,使用了nums[i - 1],也就是说同一树层使用过nums[i - 1]
    # 单层递归逻辑
    for i in range(start_index, len(nums)):
        if i > 0 and nums[i] == nums[i-1] and used[i-1]==False :
            continue
        path.append(nums[i])
        used[i] = True
        backtracking(nums, i+1)
        used[i] = False
        path.pop()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3.代码实现

    # 使用uesd数组
    class Solution:
        def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
            result, path = [], []
            used = [False] * len(nums)
    
            def backtrack(nums: List[int], startIndex: int) -> None:
                result.append(path[:])
                # 终止条件
                if startIndex == len(nums):
                    return
                for i in range(startIndex, len(nums)):
                    if i > 0 and nums[i - 1] == nums[i] and used[i - 1] == False:
                        continue
                    # 处理节点
                    path.append(nums[i])
                    used[i] = True
                    # 递归
                    backtrack(nums, i + 1)
                    # 回溯
                    used[i] = False
                    path.pop()
            # 排序
            nums.sort()
            backtrack(nums, 0)
            return result
        
    # 不使用used数组
    class Solution:
        def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
            result, path = [], []
    
            def backtrack(nums: List[int], startIndex: int) -> None:
                result.append(path[:])
                # 终止条件
                if startIndex == len(nums):
                    return
                for i in range(startIndex, len(nums)):
                    if i > startIndex and nums[i - 1] == nums[i]:
                        continue
                    # 处理节点
                    path.append(nums[i])
    
                    # 递归
                    backtrack(nums, i + 1)
                    # 回溯
    
                    path.pop()
    
            # 排序
            nums.sort()
            backtrack(nums, 0)
            return result
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    参考:
    https://www.programmercarl.com/0090.%E5%AD%90%E9%9B%86II.html#%E5%85%B6%E4%BB%96%E8%AF%AD%E8%A8%80%E7%89%88%E6%9C%AC

  • 相关阅读:
    leetcode每日一题刷题打卡1700
    1、Python 基础知识总结
    十五分钟上手JavaScript之面向对象
    详解Kubernetes Pod优雅退出
    第一届电子纸产业创新应用论坛
    ts面试题总结
    装饰模式~
    idea导入eclipse项目的时候,Java图标变成黄色小J了,怎么解决?
    【Java|golang】667. 优美的排列 II---先按k递减,再按1递增
    第十篇:复习maven
  • 原文地址:https://blog.csdn.net/weixin_44852067/article/details/126563910