子集问题实战总结:DFS 回溯法的解题步骤与代码规范

子集问题实战总结:DFS 回溯法

一、问题定义

给定一个元素互异的集合,找出所有可能的子集(包括空集)。例如:

  • 输入:$[1,2,3]$
  • 输出:$[], [1], [2], [3], [1,2], [1,3], [2,3], [1,2,3]$
二、DFS回溯法核心思想
  1. 状态树遍历:每个元素有"选"与"不选"两种状态
  2. 回溯框架
    def backtrack(start, path):
        添加当前路径到结果集
        for i in range(start, n):
            选择当前元素
            backtrack(i+1, path)  # 递归
            撤销选择(回溯)
    

  3. 避免重复:通过 start 参数控制遍历起点
三、解题步骤
  1. 初始化
    • 结果集 res = []
    • 当前路径 path = []
  2. DFS函数设计
    def dfs(start, path):
        res.append(path[:])  # 深拷贝当前路径
        for i in range(start, len(nums)):
            path.append(nums[i])    # 选择当前元素
            dfs(i+1, path)          # 递归下一层
            path.pop()              # 回溯撤销
    

  3. 递归终止:当 start 超出数组范围时自动结束
  4. 复杂度分析
    • 时间复杂度:$O(2^n)$(每个元素两种选择)
    • 空间复杂度:$O(n)$(递归栈深度)
四、完整代码实现
def subsets(nums):
    res = []
    
    def dfs(start, path):
        res.append(path[:])  # 关键:复制当前路径
        for i in range(start, len(nums)):
            path.append(nums[i])
            dfs(i+1, path)  # 从下一个位置开始
            path.pop()       # 回溯
    
    dfs(0, [])
    return res

# 测试用例
print(subsets([1,2,3])) 
# 输出:[[],[1],[1,2],[1,2,3],[1,3],[2],[2,3],[3]]

五、关键技巧
  1. 深拷贝陷阱res.append(path[:]) 避免后续修改影响结果
  2. 剪枝优化:当元素可能重复时需排序并跳过相同元素
    if i > start and nums[i] == nums[i-1]: 
        continue
    

  3. 迭代替代方案:可用位运算($0$ 到 $2^n-1$ 的二进制表示)
六、变式问题
  1. 重复元素:先排序,在递归中跳过重复值
  2. 组合求和:添加目标和判断条件
  3. 排列问题:移除 start 参数,每次从 $0$ 开始遍历

总结:DFS回溯法是解决子集问题的通用范式,核心在于掌握"选择-递归-撤销"的三步操作框架,注意状态管理和剪枝优化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值