leetcode20200409每日一题-22. 括号生成

1.题目

在这里插入图片描述

2.题目说明

给定一个数字n,n表示生成括号数量,比如题中n=3,表示生成3对括号。括号可以相交或者互不相交或者部分相交。输出所有的情况并以列表的形式返回。

注:输出情况必须是有序的,不然报错~像我用python的话,不放心可以在得到结果后面加个sort

3.各路解法

解法一

class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        if n == 0:
            return [""]
        elif n == 1:
            return ["()"]
        elif n == 2:
            return ["()()","(())"]
        result = []
        for i in range(n):
            temp1 = self.generateParenthesis(i)
            temp2 = self.generateParenthesis(n-i-1)
            result.extend(["(%s)%s" % (p,q) for p in temp1 for q in temp2])
        return result

思路:dfs~

n=0,1,2作为初始状态,然后对0~n-1的情况分别递归in-i-1。但是这里要注意,实际上递归一共生成i+n-i-1=n-1个括号,所以倒数第二行在构造结果的时候,多加了一个括号。

不减那个1行不行,也不行。因为当n=3,i=0的时候,n-i=3,会陷入无限递归。

extend() 函数用于在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)。

解法二

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

思路:回溯~

用一个列表储存当前内容,left表示左括号的个数,right表示右括号的个数。第一个if表示如果长度达到了2n(n对括号总长度是2n),就把这个加入到结果中。第二个if表示如果左括号数量小于n,就可以加左括号。第三个if表示如果右括号数量小于左括号,则可以加右括号。

S.pop()表示把加的括号去掉,这就是回溯。因为每当开始一个新的递归,我可以选择左括号+1或者右括号+1,对应的就是两种不同的情况,我可以先尝试左括号+1,尝试完了,就左括号-1,即S.pop()。然后再判断是否满足right<left,再给右括号+1,然后再回溯。通过将每种情况都试一遍,行就记录然后回退,不行就直接回退,从而得到所有解~

另外,这样的if语句安排,能够保证输出的顺序没有问题。

解法三

class Solution(object):
    def generateParenthesis(self, n):
        if n == 1:
            return ['()']
        results = set([])
        for i in range(1, n):
            l1 = self.generateParenthesis(i)
            l2 = self.generateParenthesis(n - i)
            for item1 in l1:
                for item2 in l2:
                    results.add(item1[:-1] + item2 + ')')
                    results.add(item1 + item2)
        return list(results)

思路:dfs~

这个dfs和第一种各有所长吧。这个只考虑了n=1的情况,n=0的时候,其实并不需要考虑,因为两个列表分别是0+n1+(n-1)的情况其实是一样的。

最后那个嵌套for循环里面为啥要加两个。可以简单的这样理解:如果n=1,就一个括号;如果n=2,就是两个括号嵌套或者并列。results.add(item1[:-1] + item2 + ')')不就是两个括号嵌套吗。results.add(item1 + item2)不就是两个括号并列吗。如果n>3,那不就拆分成若干个1和2的加和,就完事了。

解法四

class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        dp=[]
        dp.append([''])
        for i in range(1,n+1):
            temp=[]
            for j in range(i):
                temp+=['('+l+')'+r for l in dp[j] for r in dp[i-1-j]] 
            dp.append(temp)
        return dp[-1]

思路:dp~

dp明确两点,初始状态和状态转移方程。

初始状态:['']
转移方程:dp[i] = '(' + dp[j] + ')' + dp[i-1-j]

temp用来记录当前内容。转移方程必须是ji-j-1,不减一就会变成dp[i] = dp[j] + dp[i-j],这样没法求dp[i]。另外,为什么括号加在dp[j]外面,看了解法三咱就知道,主要考虑的就是嵌套和并列的情况。因为这里j是可以取0的,取0的时候加个括号就是并列。不取0的时候加个括号就是嵌套了。不理解的同学可以自己拿草稿纸出来画一下~

3.总结

总的来说,还是dp速度快一点,内存占用基本都是13.7MB左右。先画图,然后再实现,有错就多调试,问题不大~
在这里插入图片描述

发布了18 篇原创文章 · 获赞 1 · 访问量 798

猜你喜欢

转载自blog.csdn.net/shuaishuaihyh/article/details/105406494