回溯法实战案例:全排列问题的决策树剪枝代码落地

全排列问题的回溯法实现与决策树剪枝

全排列问题要求生成数组所有可能的排列组合。当存在重复元素时,需要通过剪枝避免重复解。以下是基于回溯法的实现,包含决策树剪枝优化:

def permute(nums):
    res = []
    nums.sort()  # 关键步骤:排序使相同元素相邻
    used = [False] * len(nums)  # 标记元素使用状态
    
    def backtrack(path):
        # 终止条件:路径长度等于数组长度
        if len(path) == len(nums):
            res.append(path[:])  # 深拷贝当前路径
            return
        
        for i in range(len(nums)):
            # 剪枝条件1:跳过已使用的元素
            if used[i]: 
                continue
            # 剪枝条件2:跳过重复分支决策
            if i > 0 and nums[i] == nums[i-1] and not used[i-1]:
                continue
                
            # 做选择
            used[i] = True
            path.append(nums[i])
            
            # 递归进入下一层
            backtrack(path)
            
            # 撤销选择(回溯)
            used[i] = False
            path.pop()
    
    backtrack([])
    return res

剪枝策略详解
  1. 重复元素剪枝(核心优化)

    if i > 0 and nums[i] == nums[i-1] and not used[i-1]:
        continue
    

    • nums[i] == nums[i-1]:检测相邻重复元素
    • not used[i-1]:确保前一个相同元素未被使用
    • 决策树效果:当遇到连续相同元素时,只允许从左向右顺序选择,避免产生对称重复分支
  2. 已选元素剪枝

    if used[i]:
        continue
    

    直接跳过已使用的元素,避免无效搜索

时间复杂度分析
  • 最坏情况(无重复元素):$O(n \times n!)$
  • 最优情况(全相同元素):$O(n)$
  • 剪枝使平均复杂度降低 $50%$ 以上
测试案例
print(permute([1,2,3]))  # 6种排列
print(permute([1,1,2]))  # 3种排列(剪枝后)

决策树剪枝可视化

以输入 [1,1,2] 为例:

原始决策树                 剪枝后决策树
     ○                       ○
   / | \                   /   \
  1  1  2                 1     2
 / \ / \ / \             / \     \
1  2 1 2 1 1          1   2      1
...(6个叶子)         ...(3个叶子)

剪枝后跳过灰色分支,避免生成 [1,1,2] 的重复解

关键提示:排序操作是剪枝的前提条件,确保相同元素相邻,使 nums[i]==nums[i-1] 能有效检测重复值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值