【发布时间】:2011-03-11 11:22:01
【问题描述】:
给出一个算法来找到给定n的所有有效括号排列 例如:
for n=3, O/P should be
{}{}{}
{{{}}}
{{}}{}
{}{{}}
{{}{}}
【问题讨论】:
标签: algorithm
给出一个算法来找到给定n的所有有效括号排列 例如:
for n=3, O/P should be
{}{}{}
{{{}}}
{{}}{}
{}{{}}
{{}{}}
【问题讨论】:
标签: algorithm
这是一个经典的组合问题,它以许多不同的方式表现出来。这些问题本质上是相同的:
N 括号对(即这个问题)N+1 因子的所有可能方式N+1 叶生成所有完整二叉树这是一个用Java解决这个问题的简单递归算法:
public class Parenthesis {
static void brackets(int openStock, int closeStock, String s) {
if (openStock == 0 && closeStock == 0) {
System.out.println(s);
}
if (openStock > 0) {
brackets(openStock-1, closeStock+1, s + "<");
}
if (closeStock > 0) {
brackets(openStock, closeStock-1, s + ">");
}
}
public static void main(String[] args) {
brackets(3, 0, "");
}
}
以上打印(as seen on ideone.com):
<<<>>>
<<><>>
<<>><>
<><<>>
<><><>
基本上,我们会跟踪有多少开括号和右括号“库存”供我们在递归构建字符串时使用。
请注意,如果您交换递归顺序,以便在尝试添加左括号之前尝试添加右括号,您只会得到相同的平衡括号列表,但顺序相反! (see on ideone.com)。
上述解决方案非常简单明了,但可以进一步优化。
最重要的优化是在字符串构建方面。虽然表面上看起来像一个简单的字符串连接,但上面的解决方案实际上有一个“隐藏的”O(N^2) 字符串构建组件(因为将一个字符连接到长度为N 的不可变String 是一个O(N) 操作) .通常我们通过使用可变的StringBuilder 来优化它,但对于这种特殊情况,我们也可以简单地使用固定大小的char[] 和index 变量。
我们还可以通过简化递归树来进行优化。我们可以只递归“一种方式”,然后迭代地执行“另一种方式”,而不是像原来的解决方案那样递归“双向”。
在下文中,我们进行了两种优化,使用char[] 和index 代替String,并且递归只添加左括号,迭代地添加右括号:(see also on ideone.com)
public class Parenthesis2 {
public static void main(String[] args) {
brackets(4);
}
static void brackets(final int N) {
brackets(N, 0, 0, new char[N * 2]);
}
static void brackets(int openStock, int closeStock, int index, char[] arr) {
while (closeStock >= 0) {
if (openStock > 0) {
arr[index] = '<';
brackets(openStock-1, closeStock+1, index+1, arr);
}
if (closeStock-- > 0) {
arr[index++] = '>';
if (index == arr.length) {
System.out.println(arr);
}
}
}
}
}
递归逻辑现在不那么明显了,但是这两种优化技术很有指导意义。
【讨论】:
Eric Lippert 最近在他的文章Every Tree There Is 中对此进行了博文。文章参考上一篇文章Every Binary Tree There Is写的代码。
如果你能枚举出所有的二叉树,那么你就可以枚举出几十个不同等价问题的所有解决方案。
【讨论】:
【讨论】:
Python 中的非递归解决方案:
#! /usr/bin/python
def valid(state,N):
cnt=0
for i in xrange(N):
if cnt<0:
return False
if (state&(1<<i)):
cnt+=1
else:
cnt-=1
return (cnt==0)
def make_string(state,N):
ret=""
for i in xrange(N):
if state&(1<<i):
ret+='{'
else:
ret+='}'
return ret
def all_permuts(N):
N*=2
return [make_string(state,N) for state in xrange(1<<N) if valid(state,N)]
if __name__=='__main__':
print "\n".join(all_permuts(3))
这基本上检查 [0,2^n) 中每个数字的二进制表示,将“1”视为“{”,将“0”视为“}”,然后仅过滤掉那些正确的均衡。
【讨论】: