LeetCode:22. Generate Parentheses

LeetCode:22. Generate Parentheses

Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.

假设有n对括号,求出所有形式正确的组合。例如:

[
  "((()))",
  "(()())",
  "(())()",
  "()(())",
  "()()()"
]

思路一:动态规划

由于括号肯定是成对出现的,所以第0位置肯定是"(",而这个左括号对应的")"肯定只会出现在第1,3,5…位置,因为一对括号之间要么不包含别的括号,要么也是包含成对的括号,所以之间的间隔肯定是偶数。

我们先用3对括号举例子,设i对括号的正确组合结果为f(i),那么f1="()",f2=[f1+"()","("+f1+")","()"+f1],f3=[f1+"(())","(("+f1+"))","(())"+f1,f2+"()","("+f2+")","()"+f2]。注意这里的f3,它有三种情况,一种是f1和两对括号的组合,还有一种是f2和一对括号的组合,最后一种情况是f1和f2的组合。1,2两种情况只是fj的位置摆放不同,可以合并。第3种情况是单纯由前面的结果组合而成。
所以i对括号的结果公示可以写成如下:

f ( i ) = { ′ ( ) ′ i = 1 ∑ j = 1 n − 1 ( [ f j + ( n − j ) ′ ( ′ + ( n − j ) ′ ) ′ ) , [ ( n − j ) ′ ( ′ + f j + ( n − j ) ′ ) ′ ) , [ ( n − j ) ′ ( ′ + ( n − j ) ′ ) ′ + f j ) , ] ) ∑ k = 1 n − 1 ( f k + f i − k ) f(i)= \begin{cases} '()' & i=1\\ \sum_{j=1}^{n-1}([fj+(n-j)'('+(n-j)')'),[(n-j)'('+fj+(n-j)')'),[(n-j)'('+(n-j)')'+fj),]) \\ \sum_{k=1}^{n-1}(f_k+f_{i-k})& \end{cases} f(i)=()j=1n1([fj+(nj)(+(nj))),[(nj)(+fj+(nj))),[(nj)(+(nj))+fj),])k=1n1(fk+fik)i=1

Python 实现代码

l = 0
allAns = []

class Solution:
    def realGenerateParenthesis(self, n: int) -> List[str]:
        global allAns
        
        left = "("
        right = ")"
        allAns[0]=[left+right]
        
        if n == 1:
            return allAns[0]
        
        for i in range(1,n):
            print(i) # i+1对括号
            
            curSet = set()
            ans = []
            
            for j in range(1,i+1):
                
                # 情况1,2.由不同数量的左右括号和f(j)组成
                thisleft = left*j
                thisright = right*j
                lastAns = allAns[i-j]
                for last in lastAns:
                    tmp=last+thisleft+thisright
                    curSet.add(tmp)
                    tmp=thisleft+last+thisright
                    curSet.add(tmp)
                    tmp=thisleft+thisright+last
                    curSet.add(tmp)
                
                # 情况3,单纯由两个f(j)组成
                leftPart = allAns[j-1]
                rightPart = allAns[i-j]
                for l in leftPart:
                    for r in rightPart:
                        curSet.add(l+r)

            for c in curSet:
                ans.append(c)
                
            # 缓存起来,供下一步使用
            allAns[i]=(ans)
        return allAns[len(allAns)-1]
    
    def generateParenthesis(self, n: int) -> List[str]:
        global allAns
        allAns = [[] for i in range(n)]
        res = self.realGenerateParenthesis(n)
        return res

思路二:回溯法

这个思路就是在添加(左/右)括号的过程中,通过个数来判断括号是否合法。

Python 代码实现

# Backtracking
class Solution(object):
    def generateParenthesis(self, N):
        ans = []
        def backtrack(S = '', left = 0, right = 0):
            if len(S) == 2 * N:
                ans.append(S)
                return
            if left < N:
                backtrack(S+'(', left+1, right)
            if right < left:
                backtrack(S+')', left, right+1)

        backtrack()
        return ans

left 表示已经添加的左括号的个数,right 表示已经添加的右括号的个数。值得注意的是由于左括号肯定是优先插入,所以先判断 left < N。当S的长度达到2N的时候表示全部插入完毕。可以用下面的树状图表示插入过程,以N=3为例:

              ('',0,0)
                  |
             ('(',1,0)
            /        \
     ('((',2,0)   ('()',1,1)
         /              \
   ('(()',2,1)    ('()(',2,1)
       /                 \
('(())',2,2)    ('()()',2,2)

复杂度分析

实际上对于N,符合情况的括号对排列的个数是一个卡特兰数:

C n = 1 n + 1 ( 2 n n ) C_n=\frac{1}{n+1}(\begin{array}{lr} 2n\\ n\\ \end{array} ) Cn=n+11(2nn)

然后又因为 C n ∼ 4 n n n C_n \sim \frac{4^n}{n\sqrt{n}} Cnnn 4n,所以这种方法的时间复杂度就是 O ( 4 n n ) O(\frac{4^n}{\sqrt{n}}) O(n 4n)

思路三:Closure Number

官方答案还提供了这样一种思路,其实主要思想我们在思路一中也提到了。就是位置0肯定是左括号,然后对应的右括号肯定只能出现在1,3,5…这样的奇数位置。一对括号之间可能会包含0到多个括号对,同样它的右侧也可能会出现0到多个括号对。抽象写法就是'({}){}'.format(left, right)。这种方法就是思路一的简写形式。

Python 代码实现

class Solution(object):
    def generateParenthesis(self, N):
        if N == 0: return ['']
        ans = []
        for c in xrange(N):
            for left in self.generateParenthesis(c):
                for right in self.generateParenthesis(N-1-c):
                    ans.append('({}){}'.format(left, right))
        return ans

THE END.

你可能感兴趣的:(LeetCode)