返回

算法学习 | 深入理解LeetCode第78题 | 子集的划分

前端





## LeetCode第78题:子集

### 问题

给定一个整数数组nums,生成其所有可能的子集。

**示例:** 

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


### 解法:

**分治法:** 

分治法是一种经典的算法范式,它将问题分解成更小的子问题,然后依次解决这些子问题,最后将子问题的解组合起来得到原问题的解。对于子集划分问题,我们可以使用分治法来枚举所有可能的子集。

具体步骤如下:

1. 定义一个函数`subsets(nums)`来计算子集。
2. 如果`nums`为空,则返回一个空列表。
3. 否则,从`nums`中取出第一个元素`num`。
4. 调用`subsets(nums[1:])`得到不包含`num`的所有子集。
5. 然后,将`num`分别添加到这些子集的末尾,得到包含`num`的所有子集。
6. 将两个列表合并起来,返回所有子集。

**回溯法:** 

回溯法是一种常用的搜索算法,它通过枚举所有可能的解来找到问题的解。对于子集划分问题,我们可以使用回溯法来生成所有可能的子集。

具体步骤如下:

1. 定义一个函数`subsets(nums)`来计算子集。
2. 定义一个空列表`result`来存储结果。
3. 调用`backtrack(nums, [], result)`函数来生成所有子集。
4. 在`backtrack`函数中,如果`nums`为空,则将当前子集添加到`result`列表中。
5. 否则,从`nums`中取出第一个元素`num`。
6. 调用`backtrack(nums[1:], current_subset + [num], result)`函数来生成包含`num`的所有子集。
7. 调用`backtrack(nums[1:], current_subset, result)`函数来生成不包含`num`的所有子集。

**复杂度分析:** 

**时间复杂度:** 

对于分治法,时间复杂度为`O(2^n)`,其中`n`是数组`nums`的长度。这是因为分治法需要枚举所有可能的子集,而子集的数量是`2^n`。

对于回溯法,时间复杂度也为`O(2^n)`。这是因为回溯法需要枚举所有可能的解,而解的数量是`2^n`。

**空间复杂度:** 

对于分治法,空间复杂度为`O(n)`。这是因为分治法需要使用栈空间来存储递归调用的参数。

对于回溯法,空间复杂度为`O(n)`。这是因为回溯法需要使用栈空间来存储递归调用的参数。

### 代码实现:

def subsets(nums):
result = []

def backtrack(nums, current_subset, result):
    if not nums:
        result.append(current_subset)
        return

    num = nums[0]
    backtrack(nums[1:], current_subset + [num], result)
    backtrack(nums[1:], current_subset, result)

backtrack(nums, [], result)
return result

### 总结:

在这篇文章中,我们介绍了LeetCode算法题之78题——子集的两种解法:分治法和回溯法。我们分析了这两种算法的复杂度,并提供了代码实现。希望这篇文章对您理解子集划分问题有所帮助。