给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例: 输入: nums = [1,2,3] 输出: [ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ]
解题思路总结
- 使用回溯法(backtracking)来解决子集问题,其核心思路是对每一个元素做两种选择:要么将其加入到当前的子集中,要么不加入,并不断递归处理剩下的元素。
- 在每一次递归调用时,都会将当前构造的
path
加入到result
中,确保所有可能的子集都被枚举出来。 - 最终返回的
result
包含了所有的子集,包括空集。
完整代码如下:
class Solution:
def subsets(self, nums):
result = []
path = []
self.backtracking(nums, 0, path, result)
return result
def backtracking(self, nums, startIndex, path, result):
result.append(path[:]) # 收集子集,要放在终止添加的上面,否则会漏掉自己
# if startIndex >= len(nums): # 终止条件可以不加
# return
for i in range(startIndex, len(nums)):
path.append(nums[i])
self.backtracking(nums, i + 1, path, result)
path.pop()
class Solution:
def subsets(self, nums):
result = []
path = []
self.backtracking(nums, 0, path, result)
return result
nums
:输入的数组,表示需要找出其所有子集的集合。result
:用于存储最终结果,即所有可能的子集。path
:用来存储当前递归路径上选择的元素,代表一个子集。
在这个函数中,首先定义了 result
和 path
,分别用来存储最终所有子集的集合和当前正在构建的子集,然后调用 backtracking
函数开始回溯。backtracking
函数会从 nums
的第一个元素(下标为 0
)开始递归地探索所有子集。
def backtracking(self, nums, startIndex, path, result):
result.append(path[:]) # 收集子集
for i in range(startIndex, len(nums)):
path.append(nums[i]) # 选择元素加入子集
self.backtracking(nums, i + 1, path, result) # 递归调用
path.pop() # 撤销选择,回溯
2.1 result.append(path[:])
- 这行代码表示:将当前路径
path
中的元素加入到result
中。注意这里的path[:]
是一个浅拷贝,确保后续对path
的修改不会影响已经加入result
的内容。 - 由于任何一个时刻的
path
都可以作为一个合法的子集,因此每当进入backtracking
函数时,无论path
中有多少元素,都会将它作为一个子集存入result
。
2.2 for
循环
for i in range(startIndex, len(nums))
:表示从nums
中当前的起始位置startIndex
开始,依次选择元素加入到当前子集(即path
)中。- 对于每一个元素
nums[i]
,首先将其加入到path
中,然后递归调用backtracking
函数,开始探索从i + 1
位置开始的下一个元素。 - 递归完毕后,通过
path.pop()
将最后加入的元素删除,进行回溯,尝试其他的可能组合。
2.3 终止条件
- 代码中没有显式的终止条件。事实上,回溯函数的退出是通过遍历
nums
数组的长度自动完成的。当startIndex
达到len(nums)
时,for
循环不再执行,因此递归自然结束。 - 可以加一个显式的终止条件,但实际上没有这个必要,因为
for
循环本身已经会停止。