难度(medium)
题目描述:
给出n对括号,请编写一个函数来生成所有的由n对括号组成的合法组合。例如n=3,解集为: "((()))", "(()())", "(())()", "()(())", "()()()" 思路:
和上一道题目有点类似,但是本题可以出现(())()的组合形式,上一道题目不能是这种形式。
也就是说所有合法的括号组合不仅仅是对称形式了,也存在非对称形式的情况。所以用栈的思路就行不通。
但是可以观察到,一个合法的组合,所有左括号出现的次数L=右括号出现的次数R,并且组合的长度=2*n。
所以可以拟合一个合法组合的生成过程,来进行算法的设计。
首先可以定义一个空的字符数组s,用于字符的添加,并将左括号出现的次数设为L,右括号出现的次数设为R。
那么第一次添加到括号必然是左括号‘(’,因为添加右括号不合法。因为是有多种组合,所以当左括号‘(’出现次数L小于n时,都可以一直添加,并且每添加1次,左括号出现的次数L+1,这样看来,算法设计上就适合采用递归形式。如下所示:
if(L < n){ bracketArrange(n,L+1,R,s);}
(关于L < n: 因为不可能一直添加左括号,合法组合还需要右括号搭配,比如3对括号,你最多单个左括号或者=单个右括号只有3个,所以L<3,为什么不能等于3呢,因为如果if(L<=3)那么当L=3的时候仍然可以进入if语句,那么下一次L+1后,L=4就大于单个左括号的临界值,所以不能等于3)
同理,当左括号添加完过后,就可以添加右括号了,添加的条件肯定是先有左括号的存在,并且左括号的个数L要大于右括号的次数R(设想,当你左括号2个右括号3个了,(())) 、())()....肯定不合法的,其次右括号个数还要小于n,上面已经说了原因。那么递归形式:
if(R < L && R < n){ bracketArrange(n,L,R+1,s)}
当左右括号添加完毕后,找一个list存储,那么此时整个字符组合的长度=2*n,并且结束递归,这样这个条件便是递归出口:
if(s.length() == 2 * n){ list.add(s); return;}
讲道理,整个代码部分,return才是最巧妙灵性的设计,有了return,才有了这么多不重复的合法组合。因为第一种组合走完,return会返回到上一个递归,上一个递归又会返回给上上个递归,然后在条件合适的if语句下面做第二次组合。这里不是很好表述,需要自己debug跑一下,就大概清楚了。
代码:
import java.util.ArrayList;public class myBracketArrange { static ArrayListlist = new ArrayList<>(); public static void main(String[] args) { Scanner in = new Scanner(System.in); int n = in.nextInt(); bracketArrange(n,0,0,""); for (int i = 0; i < list.size(); i++) { System.out.print(list.get(i)); System.out.println("\t"); } } public static void bracketArrange(int n, int l, int r, String s){ if (l < n){ bracketArrange(n,l+1, r, s + '('); } if (r < l && r < n){ bracketArrange(n, l,r+1,s + ')'); } if(s.length() == 2*n){ list.add(s); return; } }}
想写点其他东西了...
再看吧。
封面和配图来自于网络,侵删