LeetCode 热题 HOT 100 第13天:“括号生成”

继续刷LeetCode 热题 HOT 100 的题目,并且在博客更新我的solutions。在csdn博客中我会尽量用文字解释清楚,相关Java代码大家可以前往我的个人博客jinhuaiyu.com中查看。
今天的题目是一道当年学动态规划时的经典题目,但是很可惜……我忘记了怎么做。找不到分解成子问题的方法,被迫又看了一眼解答。希望能吸取经验,以后用于解决其他动态规划和递归的题目。
题目:括号生成
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
示例 1:
输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]
示例 2:
输入:n = 1
输出:["()"]
提示:
1 <= n <= 8
solution 1:动态规划/递归
这里就不讲除了动态规划以外的解答了,毕竟动态规划的时间复杂度和空间复杂度都很好,没有必要舍本逐末。我个人感觉用动态规划用递归比用迭代更好写,因此先介绍递归版动态规划。我们的目标是把generateParenthesis(n)递归分解成子问题,这道题里有两点需要吸取经验的点。
一是提取n不同时解的共性,我们的解是一组字符串,于是又要提取这些字符串的共性,这个共性就是不管n是多少(除了0),解中每一个字符串最左边的都是左括号。既然有左括号,就一定有和它配对的那个右括号。我们把这对括号提取出来,剩下的n-1对括号就被分成了p对和q对(q=n-1-p)。
第二点就是,子问题可能是多个,大家看到上面可能以为就是把generateParenthesis(n)分成了generateParenthesis§和generateParenthesis(q=n-1-p),然而p可以等于0~n-1中任何数字,也就是说子问题有n组,每组里面被分成了两个。
我们可以用一个装list的list,设为dp(可以理解为动态的二维数组或者二维列表)来记录所有子问题的解,因为每种子问题不止会被调用一次。
递归的边界条件是n为0,此时把一个装了一个空字符串的list放入dp,不再调用自身。在各种子问题被调用的时候,可以判断一下dp里面是否已经有n的解被记入了,如果有就直接提取答案,不用再递归计算,否则递归(这一步就是动态规划的精髓)。
在遍历generateParenthesis§和generateParenthesis(q=n-1-p)两个子问题返回的解列表时,我们得到字符串s1和s2(长度分别为p、q)。generateParenthesis(n)的解列表中的一个字符串就应该是"(s1)s2"。这里其实是一个双重循环,当p为i,q为n-1-i时,generateParenthesis§和generateParenthesis(q)会各自返回一个字符串列表,把他们两两组合并用一个括号隔开的字符串都是不同的字符串。
然后最外面还有一层对p从0到n-1的循环,完成以最左侧的括号为左括号所包裹的s1的长度从0到n-1的遍历求解。对于n来说这些解都是不会重复的,因为s1长度不同时,字符串一定不同,否则左括号就不是最左侧的括号了。
讲了这么多,如果大家还是迷糊,可以配着带详细注释的代码看,代码在我的个人博客http://jinhuaiyu.com/leetcode-generate-parentheses/

solution 2:动态规划/迭代
迭代就是在最外面再套一层循环来代替递归的作用,先将n为0和1的解列表填入dp,然后和递归一样通过三层循环来填充dp,只不过是将n从小到大依次按"(s1)s2"的规则计算所有解,由于0和1已经有看,n为2时可以通过n为0和1的解列表得出解并填充到dp,n为s时可以通过n为0、1、2时的解列表得出解并填充到dp……最终到n时,dp里面已经填充了0到n-1的所有解列表,n根据规则计算出所有解即可(s1的长度p从0到n,然后再是两层循环把p对括号的解列表和q对括号的解列表两两组合)。
代码也放在我的个人博客http://jinhuaiyu.com/leetcode-generate-parentheses/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值