LeetCode 78. Subsets 题解

LeetCode 78. Subsets 题解

题目描述

给你一个整数数组 nums,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

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

示例 1:

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

示例 2:

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

解题思路

方法一:回溯算法

思路

  • 使用回溯算法生成所有可能的子集
  • 维护一个路径数组 path 来存储当前的子集
  • 维护一个起始索引 start,表示从哪个位置开始选择元素,避免重复子集
  • 每次递归调用时,将当前 path 添加到结果中
  • 然后遍历从 start 到数组末尾的每个元素:
    • 将元素添加到 path
    • 递归调用回溯函数,起始索引为当前索引加 1
    • 回溯:从 path 中移除元素

复杂度分析

  • 时间复杂度:O(n × 2^n),其中 n 是数组的长度。总共有 2^n 个子集,每个子集需要 O(n) 的时间复制到结果中。
  • 空间复杂度:O(n),其中 n 是数组的长度。递归调用的栈空间和 path 数组的空间都是 O(n)。

方法二:迭代法

思路

  • 从空集开始,逐步构建所有子集
  • 对于数组中的每个元素,将其添加到现有的所有子集中,形成新的子集
  • 例如,对于数组 [1,2,3]:
    • 初始子集:[]
    • 添加 1:[], [1]
    • 添加 2:[], [1], [2], [1,2]
    • 添加 3:[], [1], [2], [1,2], [3], [1,3], [2,3], [1,2,3]

复杂度分析

  • 时间复杂度:O(n × 2^n),其中 n 是数组的长度。总共有 2^n 个子集,每个子集需要 O(n) 的时间处理。
  • 空间复杂度:O(n × 2^n),其中 n 是数组的长度。需要存储 2^n 个子集,每个子集的平均长度为 O(n)。

代码实现

方法一:回溯算法

class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        result = []
        path = []
        n = len(nums)
        
        def backtrack(start):
            # 将当前 path 添加到结果中
            result.append(path.copy())
            
            # 遍历从 start 到数组末尾的每个元素
            for i in range(start, n):
                # 将元素添加到 path 中
                path.append(nums[i])
                # 递归调用,起始索引为当前索引加 1
                backtrack(i + 1)
                # 回溯:从 path 中移除元素
                path.pop()
        
        backtrack(0)
        return result

方法二:迭代法

class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        result = [[]]
        
        for num in nums:
            # 将当前元素添加到现有的所有子集中,形成新的子集
            new_subsets = []
            for subset in result:
                new_subsets.append(subset + [num])
            # 将新的子集添加到结果中
            result.extend(new_subsets)
        
        return result

测试用例

测试用例 1:

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

测试用例 2:

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

测试用例 3:

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

总结

本题是回溯算法的经典问题,主要考察对回溯思想的理解和应用。两种方法各有特点:

  • 回溯算法:通过递归的方式生成所有子集,逻辑清晰易懂,空间复杂度较低。
  • 迭代法:通过迭代的方式逐步构建所有子集,代码简洁,易于理解。

在实际应用中,两种方法都可以使用。对于初学者来说,回溯算法可能更容易理解,因为它的逻辑更直观。而迭代法则更简洁,不需要递归调用。

无论使用哪种方法,核心思想都是生成所有可能的子集,这对于解决许多组合问题都有帮助,例如组合总和、排列问题等。

评论 29
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值