递归与回溯1:生成全部有效括号组合
从现在开始我们一起来梳理递归相关的问题。递归是高阶算法的核心,回溯、dp都是递归的拓展和延伸。
废话少说,递归的问题一般我们不要急着看代码,因为看了也不懂,而应该先分析问题的本质,从小到大逐步归纳出特征,最后再写代码。而计算机调用的时候恰好是从大小到逐步递进的。
先看一个CC150中的题目,实现一种算法,打印n对括号中的全部有效组合,即左右括号正确配对。
示例:输入n=3,输出:((())), (()()), (())(), ()(()),()()()所以有3个。
这个题如果用递归的话怎么做呢?
如果直接想是不好想的,我们画一个图看一下:
很明显看到, 从n=2开始就是将上面一层的每一个都是在其左边、右边和包起来三种操作,n从1到2就很明显,从n到3就是图中红色标记的地方。后面的每一层都对前面做相同的三个操作。这就是一个从小到大不断递归的过程。
但是这里有个问题,出现重复了怎么办?例如n=2的时候()()和()()是一样的。显然这时候只保留一种就足够了,后序递归操作也只处理一个就行了,那如何去重呢?我们想到集合能保证元素唯一,所以我们可以将每层的元素用集合来保存。代码如下:
public static Set<String> parentThesis(int n) {
Set<String> s_n = new HashSet<String>();
if (n == 1) {
s_n.add("()");
return s_n;
}
Set<String> s_n_1 = parentThesis(n - 1);
for (String s : s_n_1) {
s_n.add("()" + s);
s_n.add(s + "()");
s_n.add("(" + s + ")");
}
return s_n;
}
这里虽然有个for循环,但是只是简单的拼接字符串,因此难度不算很大的。
推荐阅读