📜  门| GATE-CS-2015(套装3)|第 56 题(1)

📅  最后修改于: 2023-12-03 15:12:42.843000             🧑  作者: Mango

题目描述

给定一个由 n 个唯一整数组成的数组 nums,返回所有可能的子集(幂集)。解集不能包含重复的子集。

示例

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

题解

本题可以使用回溯算法来解决。

首先,将nums数组按升序进行排序,这是为了使得枚举子集时子集内元素的顺序是升序的。

接着,从长度为0的子集开始,对于每一次增加元素,都对nums数组进行一次遍历,将其添加到当前子集中,并继续进行长度增加。每次添加元素后,需要回溯到上一次的状态,将上次添加的元素删除,继续进行遍历。当子集长度达到数组长度时,说明已经构建出一个子集。

最后,将所有子集加入到解集中,即可完成求解。

以下是代码实现:

class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        nums.sort()
        res = []
        n = len(nums)

        def backtrack(start, subset):
            # 当元素个数为 n 时,结束递归
            if len(subset) == n:
                res.append(subset[:])
                return

            for i in range(start, n):
                # 添加元素到当前子集中
                subset.append(nums[i])
                # 递归,继续构建子集
                backtrack(i + 1, subset)
                # 删除上一次添加的元素
                subset.pop()

        # 从空集开始,构建所有子集
        backtrack(0, [])
        return res

时间复杂度为 O(2^n),即为解集中元素个数的上限。空间复杂度为 O(n),即递归栈深度的上限。

总结

本题展示了回溯算法在求解子集问题中的应用。回溯算法的一般步骤为:定义状态,枚举所有可能的状态,检查是否符合要求,并进行回溯。掌握回溯算法的关键在于理解回溯的本质,即通过维护状态,在状态树上遍历所有可能状态,从而求解问题。