22. 括号生成

https://leetcode-cn.com/problems/generate-parentheses/

解法一:暴力

先生成所有括号的组合,然后逐个检测是否满足条件。

重点是生成所有的组合(长度为2*n,每个位置有左括号和右括号两种可能,共2^2n种情况),用递归。

检测是否符合就比较简单了,看左右是否配对即可。注意避免右括号先于左括号出现的情况

还有就是python的函数内定义嵌套函数,调用不用加self,引用外层参数也不用

class Solution:
    def generateParenthesis(self, n: int) -> List[str]:    
        def generate(A):    #回溯生成函数
            if len(A) == 2*n:    #递归出口
                if valid(A):    #调用验证
                    res.append(''.join(A))
                return
            #经典回溯
            A.append('(')
            generate(A)
            A.pop()
            A.append(')')
            generate(A)
            A.pop()
        
        def valid(A):    #验证函数
            bal = 0    #balance,遇到左括号+1,右括号-1
            for ch in A:
                if ch == '(': bal += 1
                else: bal -= 1
                if bal < 0: return False    #若右括号先出现
            return bal == 0
        
        res = []
        generate([])
        return res

简化写法:

class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        def generate(A):
            if len(A) == 2*n:
                if (valid(A)):
                    res.append(''.join(A))
                return
            #简洁回溯
            generate(A + ['('])
            generate(A + [')'])

        def valid(A):    #验证函数
            bal = 0    #balance,遇到左括号+1,右括号-1
            for ch in A:
                if ch == '(': bal += 1
                else: bal -= 1
                if bal < 0: return False    #若右括号先出现
            return bal == 0
        
        res = []
        generate([])
        return res

将generate函数中参数A由list改为字符串,更加直接:

class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        def generate(A):
            if len(A) == 2*n:
                if (valid(A)):
                    res.append(A)
                return
            generate(A + '(')
            generate(A + ')')
            
        def valid(A):    #验证函数
            bal = 0    #balance,遇到左括号+1,右括号-1
            for ch in A:
                if ch == '(': bal += 1
                else: bal -= 1
                if bal < 0: return False    #若右括号先出现
            return bal == 0
        
        res = []
        generate('')
        return res

解法二:回溯

不是先生成所有组合,而是生成所有合法的组合

用left,right表示左右括号数,先加左括号,保证左括号数=n;然后加右括号,保证右括号数=左括号,递归回溯。这在回溯过程中保证左右括号相等,而不是解法一中生成最终组合后才判断左右是否相等,因此速度更快

注意左右递归的两个if是并列的,而不能是二选一的if else。如果二选一,就变成一直递归左括号直到n,再递归右括号,最终只生成一个结果

class Solution:
    def generateParenthesis(self, n: int) -> List[str]:    
        def generate(A, left, right):
            if len(A) == 2*n:    #出口
                res.append(''.join(A))
                return
            if left < n:    #先加左括号
                #经典回溯格式
                A.append('(')
                generate(A, left+1, right)
                A.pop()
            if right < left:    #若右括号不足,补充右括号
                A.append(')')
                generate(A, left, right+1)
                A.pop()
        res = []
        generate([], 0, 0)
        return res

也可以换种写法,将新A直接写入递归函数中,这样每次递归的A都保存在当前层次的递归函数中,不需要再append,pop操作。78.子集的回溯也可以如此改写

class Solution:
    def generateParenthesis(self, n: int) -> List[str]:    
        def generate(A, left, right):
            if len(A) == 2*n:
                res.append(''.join(A))
                return
            if left < n:
                generate(A+['('], left+1, right)                
            if right < left:
                generate(A+[')'], left, right+1)
        res = []
        generate([], 0, 0)
        return res

简化:

class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        def generate(A, left, right):
            if len(A) == 2*n:
                res.append(A)
                return
            if left < n:
                generate(A + '(', left+1, right)
            if right < left:
                generate(A + ')', left, right+1)

        res = []
        generate('', 0, 0)
        return res

最后更新于