每日leetcode22:括号生成

给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。

如n=3,结果应为

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

这是一个明显的排列问题,要穷尽所有的组合,可以考虑回溯法,用回溯法要考虑以下几个问题

①终止条件:可以根据当前字符串长度来进行判断,若为n的2倍则可以终止;然而每一次递归都求一次长度会不会效率过于低下,所以可以考虑进行计数:每匹配一次,n自减1,减到0就可以终止了

②递归情况:很明显,对于每一个节点,最多有两个子节点:+"("和+")",但是不是每一个节点都能有两个子节点,一是考虑"("已经满n个了的情况,这种情况只能添加")",不能加"(",二是"("已经被匹配完了的情况,这种情况只能加"(",因为不能")"开头,剩余的情况都是两个都能加的了

class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        ret = []
        def test(s, n, i, j):
            if n == 0:
                ret.append(s)
            else:
                if j == m:
                    s += ")"
                    test(s, n-1, i-1, j)
                elif i == 0:
                    s += "("
                    test(s, n, i+1, j+1)
                else:
                    s += "("
                    test(s, n, i+1, j+1)
                    s = s[:-1] + ")"
                    test(s, n-1, i-1, j)
        m = n
        test("", n ,0 , 0)
        return ret

用时44ms,99.37%

然后尝试把s+"("这种操作移到递归的调用中,根据前面的文章 电话号码的字母组合(python)&回溯法以及递归的理解 中的想法,这样做必然降低速度,但是能提高代码可看性

    def generateParenthesis(self, n: int) -> List[str]:
        ret = []
        def test(s, n, i, j):
            if n == 0:
                ret.append(s)
            else:
                if j == m:
                    test(s+")", n-1, i-1, j)
                elif i == 0:
                    test(s+"(", n, i+1, j+1)
                else:
                    test(s+"(", n, i+1, j+1)
                    test(s+")", n-1, i-1, j)
        m = n
        test("", n ,0 , 0)
        return ret

用时52ms,94.99%

然后看来一下别人的答案,代码更加简洁,他们讨论的是未满可加(我是先讨论已满只能加,剩下的情况自由加两个符号之一,所以我要比他们多一种情况,他们的代码更加简洁,但是由于我讨论的情况之间互斥,所以我的代码效率会更高)

    def generateParenthesis(self, n: int) -> List[str]:
        ret = []
        def test(s, n, i, j):
            if n == 0:
                ret.append(s)
            if i < m:
                test(s+"(", n, i+1, j+1)
            if j != 0:
                test(s+")", n-1, i, j-1)
        m = n
        test("", n , 0 , 0)
        return ret

56ms,91.18%

同理如果将s+"("这样的操作移到递归调用外,效率会高一点

    def generateParenthesis(self, n: int) -> List[str]:
        ret = []
        def test(s, n, i, j):
            if n == 0:
                ret.append(s)
            if i < m:
                s += "("
                test(s, n, i+1, j+1)
                s = s[:-1]
            if j != 0:
                s += ")"
                test(s, n-1, i, j-1)
        m = n
        test("", n , 0 , 0)
        return ret

48ms,97.9%

最后总结一下回溯法的实现要点

①退出情况(优化点)

②递归情况:其实就是对每一个子节点进行递归调用

如到了a就要对def进行递归,有的子节点递归是循环实现,如电话号码组合的那个题,有的则需要对每个点进行单独递归,这是由每个节点的子节点的构成情况决定的。需要注意的是,如果将一个变量的处理放在了递归调用之外(也就是不在函数调用的参数中进行改变,那么在这个递归调用之后下一个递归调用之前,一定还要把这个变量变回去)

③优化,也就是变量是在递归调用外处理还是在递归调用的参数中进行处理,前者能适当提高效率,后者能够简化代码。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值