实施算法以打印n对括号的所有有效(例如,正确打开和关闭)组合。 例: 输入:3(例如,3对括号) 输出:()()(),()(()),(())(),((()))
答案是:
private static void printPar(int count)
{
char[] str = new char[count*2];
printPar(count,count,str, 0);
}
private static void printPar(int l, int r, char[] str, int count)
{
if(l < 0 || r < l)
return;
if (l ==0 && r == 0)
{
System.out.println(str);
}
else
{
if (l > 0 )
{
str[count] = '(';
printPar(l-1, r, str, count + 1);
}
if (r > 0)
{
str[count] = ')';
printPar(l, r-1, str, count + 1);
}
}
}
但是我并不完全理解这个解决方案,尽管有人声称解释很简单。 (此代码工作正常)
在我看来,这段代码的工作原理是左括号更多,然后添加左括号。因此,只有((())的条件才能满足条件 if(l> 0) 出现在r&gt;之前0,所以,它应该总是首先处理所有左边的。
但是这段代码如何处理这种情况“()(())”?我调试这段代码,并在打印出“((()))”之后发现它。它进入了l = 1,r = 3和str =“((()))”和count = 2的情况。这对我来说没有意义。
另外,如果有人能解释时间/空间的复杂程度,那对我来说会很有帮助。
提前致谢。
答案 0 :(得分:7)
我画了一棵树来展示如何为count = 3
编写括号。每个节点代表一个函数调用,其文本为(
或)
,具体取决于调用函数的添加内容。叶子是打印它的调用。
由于此树的深度(显然)最多为2.count
,因此空间复杂度为O(count)
。
由于每个函数调用都可以添加(
或)
,因此时间复杂度最多为O(2number of function calls)
= O(22 count)
。
但是,由于调用是有条件的,时间复杂度最终会减少,更具体地说,它似乎在O(22 count/count)
左右,尽管我还没有证明这一点。
答案 1 :(得分:3)
代码运行成功,因为它不会让r&lt;湖如果是这样,那么它只是丢弃组合并返回。这意味着右支架只能在左支架后出现。
复杂度的顺序,如果你计算丢弃的递归调用也是(2n)!/( n! * n! )
。这是n'('和n')'的排列数。
如果您尝试跟踪代码,它将运行如下:
(
(
(
)
)
)
((()))
)
(
)
)
(()())
)
(
)
(())()
)
(
(
)
)
()(())
(
)
(
)
(
)
()()()
答案 2 :(得分:3)
在递归时,算法会跟踪剩余左括号的数量(l),剩余右括号的数量(r),到目前为止的结果(str)以及生成的括号数(count)。 / p>
如果没有括号,则会打印结果。
如果剩下至少一个左括号,则使用它,并且函数会递归以生成以当前前缀
开头的所有结果然后,如果至少有一个右括号,并且至少有一个左括号没有关闭,则使用右括号,函数会递归。
但是这段代码如何处理这种情况“()(())”?我调试这段代码, 并在打印出“((()))”之后发现它。它去了 情况l = 1,r = 3,str =“((()))”和count = 2.这不是 对我有意义。
在打印((()))
后,使用参数1
,3
,((()))
和2
调用该函数时,count=2
表示str
唯一有效的部分是((
。然后,在使用参数)
,1
,2
和(()
进行递归之前,它会继续添加3
,从而导致(()())
为打印下一个组合,然后是()(())
和()()()
。