You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

生成括号问题中回溯算法的栈回溯逻辑及pop时机解析

回溯算法中pop逻辑与生成括号问题的执行解析

核心逻辑:回溯是「试错+撤销选择」

回溯的本质是走不通就回头,回头时必须把刚才选的路擦掉。每一次向当前路径currCombo中添加字符(append),都是选择了一条分支;当这条分支的所有可能性都探索完毕后,必须用pop把这个字符移除,才能回到上一个岔路口,尝试其他分支。

生成括号问题的代码与pop对应关系

先看标准可行代码:

def generateParenthesis(n):
    result = []
    def backtrack(currCombo, openN, closeN):
        # 基准情况:括号长度达标,记录结果
        if len(currCombo) == 2 * n:
            result.append(''.join(currCombo))
            return
        # 尝试加左括号
        if openN < n:
            currCombo.append('(')
            backtrack(currCombo, openN + 1, closeN)
            currCombo.pop()  # 撤销左括号选择
        # 尝试加右括号
        if closeN < openN:
            currCombo.append(')')
            backtrack(currCombo, openN, closeN + 1)
            currCombo.pop()  # 撤销右括号选择
    backtrack([], 0, 0)
    return result

这里的pop和append是严格一一对应的:每加一个字符,递归探索完所有子分支后,必须撤销这个选择,否则路径会带着之前的分支残留,导致后续分支的选择错误。

生成((()))后的回溯过程拆解(n=3)

当生成第一个结果((()))时,递归调用链已经走到最深层:

路径:['(', '(', '(', ')', ')', ')'],触发基准条件,加入结果后返回上一层。

接下来的回溯(pop)过程分4步,对应你提到的“3个右括号+1个左括号”:

  1. 第一次pop:从最深层返回后,执行currCombo.pop(),去掉最后一个),路径变为['(', '(', '(', ')', ')'],当前递归层结束,返回上一层。
  2. 第二次pop:回到上一层(对应加倒数第二个)的递归),执行pop()去掉倒数第二个),路径变为['(', '(', '(', ')'],递归层结束,返回上一层。
  3. 第三次pop:回到加倒数第三个)的递归层,执行pop()去掉这个),路径变为['(', '(', '('],递归层结束,返回上一层。
  4. 第四次pop:回到加第三个(的递归层,执行pop()去掉这个(,路径变为['(', '('],递归层结束,回到上一个岔路口。

为什么要这些pop?

回到路径['(', '(']时,左括号分支(即加第三个(的分支)已经探索完毕,现在可以尝试右括号分支:

  • 此时closeN=0 < openN=2,满足加右括号的条件,执行append(')'),路径变为['(', '(', ')'],进入新的递归链,最终生成第二个结果(()())。

如果没有这些pop,路径会一直停留在['(', '(', '(', ')', ')', ')'],无法回到岔路口选择其他分支,自然生成不了后续的有效括号组合。

关键总结

  • pop的时机:紧跟在递归调用之后——递归调用代表当前选择的所有子分支已探索完毕,必须撤销选择回到岔路口。
  • pop的次数:每一次append对应且仅对应一次pop,保证路径始终是当前分支的纯净选择序列。
  • 可视化技巧:可以在递归函数中添加打印语句,实时输出进入递归和pop后的路径,直观看到每一步的变化,比如:
    def backtrack(currCombo, openN, closeN):
        print(f"进入: {currCombo} | 左括号数: {openN} | 右括号数: {closeN}")
        if len(currCombo) == 2 * n:
            result.append(''.join(currCombo))
            print(f"找到结果: {''.join(currCombo)}")
            return
        if openN < n:
            currCombo.append('(')
            backtrack(currCombo, openN + 1, closeN)
            currCombo.pop()
            print(f"撤销左括号后: {currCombo}")
        if closeN < openN:
            currCombo.append(')')
            backtrack(currCombo, openN, closeN + 1)
            currCombo.pop()
            print(f"撤销右括号后: {currCombo}")
    

内容的提问来源于stack exchange,提问作者calvin2011

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 23:55:27