[leetcode]22. 括号生成

本文通过一道LeetCode题目22——括号生成,探讨了使用动态规划解决此类问题的思路。作者解释了如何利用回溯算法生成所有有效括号组合,并反思了自己的解决方案。文章强调了动态规划的核心思想,即在已知小规模问题解的基础上扩展求解大规模问题。同时,分享了一种更优雅的解法,指出动态规划的关键在于找到如何从较小规模问题扩展到更大规模问题的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

例如,给出 n = 3,生成结果为:

[ “((()))”, “(()())”, “(())()”, “()(())”, “()()()” ]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/generate-parentheses
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

这一题归类在回溯算法下,很容易就想到了回溯算法,我写出来的版本:

class Solution:
    def __init__(self):
        self.ans = []
    def generateParenthesis(self, n: int) -> List[str]:
        self.generate(n*2,0,'')
        return self.ans
        
    def generate(self,deep,left_num,s):
        if left_num < 0 or deep < 0:
            return 
        if deep == 0 and left_num == 0:
            # good ans
            self.ans.append(s)
        
        self.generate(deep-1,left_num+1,s+'(')
        self.generate(deep-1,left_num-1,s+')')
        

首先我用一个deep代表现在还能插入多少个符号,初始值为 n*2。当deep==0的时候也就意味着不能再插入符号了。

这里的left_num代表左括号的数量-右括号的数量,由于我是从左往右一个一个插入符号,在任何情况下不可能出现右括号数量比左括号多的,也就是说一旦出现了left_num<0,就可以跳出递归。

所以递归结束条件就得出来了。

而当deep0以及left_num0,说明这是一个正确的答案。


别人家的leetcode

我的代码简洁有余而速度不足,思路清晰但是毕竟不够精巧。
补充我认为比较优雅的解法,出处已经标明在结尾。

反思

首先,面向小白:什么是动态规划?在此题中,动态规划的思想类似于数学归纳法,当知道所有 i<n 的情况时,我们可以通过某种算法算出
i=n 的情况。 本题最核心的思想是,考虑 i=n 时相比 n-1 组括号增加的那一组括号的位置。

思路

具体思路如下: 当我们清楚所有 i<n 时括号的可能生成排列后,对与 i=n 的情况,我们考虑整个括号排列中最左边的括号。
它一定是一个左括号,那么它可以和它对应的右括号组成一组完整的括号 “( )”,我们认为这一组是相比 n-1 增加进来的括号。

那么,剩下 n-1 组括号有可能在哪呢? 【这里是重点,请着重理解】
剩下的括号要么在这一组新增的括号内部,要么在这一组新增括号的外部(右侧)。

既然知道了 i<n 的情况,那我们就可以对所有情况进行遍历: “(” + 【i=p时所有括号的排列组合】 + “)” +【i=q时所有括号的排列组合】 其中 p + q = n-1,且p q均为非负整数。 事实上,当上述 p 从 0 取到 n-1,q 从n-1 取到 0 后,所有情况就遍历完了。

代码: 具体代码如下:(时间击败百分之 95,内存击败百分之 99.65)【p.s. 实测并没有这么高了…】

class Solutin:
    def generateParenthesis(self, n: int) -> List[str]:
        if n == 0:
            return []
        total_l = []
        total_l.append([None])
        total_l.append(["()"])
        for i in range(2,n+1):  # 开始计算i时的括号组合,记为l
            l = []
            for j in range(i): #遍历所有可能的括号内外组合
                now_list1 = total_l[j]
                now_list2 = total_l[i-1-j]
                for k1 in now_list1:  #开始具体取内外组合的实例
                    for k2 in now_list2:
                        if k1 == None:
                            k1 = ""
                        if k2 == None:
                            k2 = ""
                        el = "(" + k1 + ")" + k2
                        l.append(el)
            total_l.append(l)
        return total_l[n] ```

作者:yuyu-13
链接:https://leetcode-cn.com/problems/two-sum/solution/zui-jian-dan-yi-dong-de-dong-tai-gui-hua-bu-lun-da/
来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

重点:动态规划。
将i<n的情况都记录下来,然后可以认为:
n的情况是 n-1情况的扩展。具体扩展就是加一对括号,那么只要基于之前的【可行情况】加一对就好了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值