这是Cracking the Coding Interview(5 th edition)的问题9.6
实施算法以打印n对括号的所有有效组合
的实施例的
输入:3
输出:"((())),(()()),(())(),()(()),()()()"
这是我实现的算法(在Java中)
private static Set<String> getAllComb(int n) {
Set<String> allPoss = new HashSet<String>();
if(n>0) {
if(n==1) {
allPoss.add("()");
} else {
Set<String> before = getAllComb(n-1);
for(String phrase: before) {
int length = phrase.length();
for(int start = length - 2; start>=0; start--) {
if(phrase.charAt(start) == '(') {
String phraseToConsider = phrase.substring(0, start+1) + "()" +
phrase.substring(start + 1);
if(!allPoss.contains(phraseToConsider)){
allPoss.add(phraseToConsider);
}
}
}
String phraseToConsider = "()" + phrase.substring(0);
if(!allPoss.contains(phraseToConsider)){
allPoss.add(phraseToConsider);
}
}
}
}
return allPoss;
}
这会产生正确的输出。我知道面试官(至少在亚马逊)喜欢问你解决方案的时间和空间复杂性。对于时间复杂度,我能够证明算法在具有递归关系的 O(n)中运行。我在分析空间复杂性方面遇到了麻烦。我这是一个递归解决方案,所以它至少应该是 O(n)但是在每次递归调用时,我也生成一个以n为界的集合。由于n个递归调用,总空间是 O(n)还是 O(n 2 )因为设置的大小为每个递归调用n?
绑定n答案 0 :(得分:3)
对于时间复杂度,我能够证明算法在O(n)中以递归关系运行
这是错误的。平衡括号的序列数由Catalan numbers给出:指数多个这样的序列。你的算法不能是线性的,如果它也正确地解决问题,因为只输出指数数量的解决方案本身就是指数时间。
至于内存复杂性,您似乎在递归的每一步n - 1
存储n
的所有解决方案,因此内存复杂性对我来说也是指数级的,加上您创建的其他字符串和您在每个步骤中进行的递归调用,这只会增加复杂性。
您可以在不使用指数记忆的情况下解决问题:想想如何摆脱存储所有以前的序列。
答案 1 :(得分:1)
写 n 对正确匹配的括号的方法的数量是 n 加泰罗尼亚数,它实际上呈指数增长,而不是二次方。单独输出的空间复杂度为O(2 ^ n);请参阅the wikipedia article以快速了解加泰罗尼亚语数字。
请注意,您不是在每个深度进行一次递归调用,而是可能进行O(n)递归调用。