【问题标题】:Integers and recursion整数和递归
【发布时间】:2021-01-18 21:10:35
【问题描述】:

下面的代码是生成平衡括号

class Solution:
        def generateParenthesis(self, n: int) -> List[str]:
            res = []
            self.backtrack(n, res, 0, 0, [])
            return res

        def backtrack(self, n, res, o, c, path):

            print(o, c, path)
            if len(path) == 2*n:
                res.append("".join(path))
                return 
            if o < n:
                o += 1
                self.backtrack(n, res, o, c, path + ['('])

            if c < o:
                c += 1
                self.backtrack(n, res, o, c, path + [')'])

n = 3 时的打印输出是,

0 0 []
1 0 ['(']
2 0 ['(', '(']
3 0 ['(', '(', '(']
3 1 ['(', '(', '(', ')']
3 2 ['(', '(', '(', ')', ')']
3 3 ['(', '(', '(', ')', ')', ')']
3 1 ['(', '(', ')']
3 2 ['(', '(', ')', ')']
3 3 ['(', '(', ')', ')', ')']
2 1 ['(', ')']
3 1 ['(', ')', '(']
3 2 ['(', ')', '(', ')']
3 3 ['(', ')', '(', ')', ')']
3 2 ['(', ')', ')']
3 3 ['(', ')', ')', ')']
1 1 [')']
2 1 [')', '(']
3 1 [')', '(', '(']
3 2 [')', '(', '(', ')']
3 3 [')', '(', '(', ')', ')']
3 2 [')', '(', ')']
3 3 [')', '(', ')', ')']
2 2 [')', ')']
3 2 [')', ')', '(']
3 3 [')', ')', '(', ')']
3 3 [')', ')', ')']

我知道 3-3 之前发生了什么(第一个),但在那之后为什么 3-1 只得到 2 个左括号但 o 等于 3,起初我认为它是因为变量 o 已被设置之前递归的范围始终为 3,但后来 o 被视为等于 2,所以不是这样。

我知道列表和集合等数据结构中的这种行为,这就是为什么我在函数调用中添加项目以避免它们在每次递归调用时都被更改,但对于整数也是如此吗?这可以解释为什么当我在函数调用中执行 o + 1 时它会起作用。

有人可以对此进行复习吗!

谢谢

【问题讨论】:

    标签: python python-3.x recursion scope integer


    【解决方案1】:

    仅供参考,这是我解决此问题的方法。你可以和你的比较一下。

    class Solution(object):
        def generateParenthesis(self, n):
            
            def paren(left, right, curr, res):
                # evalue current string
                # if out of brackets to add, it must be a valid one
                if left == 0 and right == 0:
                    res.append(curr)
                    return
    
                # recursive call: add either open or close
                if left > 0:
                    # add open bracket, decr count
                    paren(left-1, right, curr + "(", res)
    
                # if adding close bracket is valid
                if right > left:
                    # add close bracket, decr count
                    paren(left, right-1, curr + ")", res)
    
                return res
            # end paren()
    
            res = paren(n, n, '', [])
    
            return res
    

    【讨论】:

    • 我试图理解为什么我们必须将 left-1/right-1 放在函数调用内部而不是外部。就像这样做有什么区别。
    【解决方案2】:

    您应该使用o+1 作为其参数调用回溯,而不是在函数中修改o,因为它会扭曲您使用o 的下一个条件(并导致与路径的内容不一致)。

    只有 3 种方法可以向现有的匹配括号模式添加更多括号。所以递归非常简单。你只需要消除重复的模式。这是一个生成器:

    def parent(N, pattern="",seen=None):
        if seen is None: seen = set()
        if N:
            yield from parent(N-1,f"{pattern}()",seen)
            yield from parent(N-1,f"({pattern})",seen)
            yield from parent(N-1,f"(){pattern}",seen)
        elif pattern not in seen:
            seen.add(pattern)
            yield pattern 
    

    输出

    print(*parent(3))
    
    # ()()() (()()) (())() ((())) ()(())
    

    您还可以使用众所周知的左右算法,该算法使用两个计数器来平衡括号,这两个计数器都必须为零才能使模式完整。

    当有可用的左括号(左侧)时,它会在当前模式中添加一个左括号并递归以关闭它们。

    当有未决的(未闭合的)左括号时添加右右括号,并且递归继续使用剩余的括号打开或关闭更多。这不会产生重复,因为打开和关闭只发生在不同的不平衡级别上。

    def paren(L,R=None,pattern=''):
        if R is None: R = L
        if not L and not R: yield pattern;return
        if L>0: yield from paren(L-1,R,pattern+"(")
        if R>L: yield from paren(L,R-1,pattern+")")
    

    【讨论】:

    • 我在问我添加计数器(在函数调用之外)的方式在做什么
    • 在我的回答开头添加了解释
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-13
    • 2013-11-05
    • 2020-07-17
    • 2011-06-06
    相关资源
    最近更新 更多