我试图回答以下问题:“实施一种算法来打印n对括号的所有有效(即正确打开和关闭)组合。”
答案说:“我们的第一个想法可能是应用递归方法,我们通过将一对括号添加到f(n - 1)来构建f(n)的解决方案。我们可以通过插入一个每对现有括号内的一对括号,以及字符串开头的一对括号。“
我很难理解如何保证在每对现有括号内插入一对括号,以及在字符串开头插入一对括号,将创建所有可能的解决方案。我们怎么知道这不会产生重复的解决方案,或者遗漏一些正确的解决方案?有人可以解释一下吗?
(报价来源:破解编码面试)
答案 0 :(得分:1)
您描述的方法适用于f(1)和f(2)。对于n> 2,它不会错过任何,但它会产生重复。
对于f(3),这是在开始生成重复项时。在f(2)的基础上,你有"()()"的2个解决方案。和"(())"。当您在该算法之后插入括号时,您最终会生成两个生成"()(())"的解决方案。你最终会得到6个f(3)的解,而不是实际的5个因为这个副本。
如果将算法应用于f(5),它将生成33个f(1)到f(5)的总解。应该只有22个解决方案,所以你在那里得到10个重复。
这里有一个非常常见的递归解决方案,涉及多个括号打开和关闭的计数。我见过的最好的解释是https://anonymouscoders.wordpress.com/2015/06/16/all-balanced-permutation-of-number-of-given-parentheses/
以下是C中解决方案之一的示例:
// Source: http://www.geeksforgeeks.org/print-all-combinations-of-balanced-parentheses/
# include<stdio.h>
# define MAX_SIZE 100
void _printParenthesis(int pos, int n, int open, int close);
/* Wrapper over _printParenthesis()*/
void printParenthesis(int n)
{
if(n > 0)
_printParenthesis(0, n, 0, 0);
return;
}
void _printParenthesis(int pos, int n, int open, int close)
{
static char str[MAX_SIZE];
if(close == n)
{
printf("%s \n", str);
return;
}
else
{
if(open > close) {
str[pos] = '}';
_printParenthesis(pos+1, n, open, close+1);
}
if(open < n) {
str[pos] = '{';
_printParenthesis(pos+1, n, open+1, close);
}
}
}
/* driver program to test above functions */
int main()
{
int n = 4;
printParenthesis(n);
getchar();
return 0;
}
作为参考,这里是我为您提供的算法做的C#版本:
// Initial funtion call
void f(int n)
{
f(1, n, "");
}
// Recursive call
void f(int n, int max, string output)
{
for (int i = 0; i < output.Length; i++)
{
if (output[i] == '(')
{
var inserted = output.Insert(i + 1, "()");
Console.WriteLine(inserted);
if (n < max)
f(n + 1, max, inserted);
}
}
// Pre-pend parens
output = "()" + output;
Console.WriteLine(output);
if (n < max)
f(n + 1, max, output);
}
f(4);