在C ++中生成一组有效的括号

时间:2017-07-27 00:40:39

标签: java recursion

给定一个数字,比如说n,我需要输出有效的括号。我在网上找到了以下代码,并希望更好地理解它,因为它比我的更有效:

public List<String> generateParenthesis(int n) {
    List<String> list = new ArrayList<String>();
    backtrack(list, "", 0, 0, n);
    return list;
}

public void backtrack(List<String> list, String str, int open, int close, int max){

    if(str.length() == max*2){
        list.add(str);
        return;
    }

    if(open < max)
        backtrack(list, str+"(", open+1, close, max);
    if(close < open)
        backtrack(list, str+")", open, close+1, max);
}

因此,给定输入n=3,我希望它生成以下一组括号:

  

[&#34;((()))&#34;&#34;(()())&#34;&#34;(())()&#34;,& #34;()(())&#34;&#34;()()()&#34;]

我或多或少能够理解他做了什么;但不是 为什么他已经完成了它。我特别提到了两个问题:

  1. 为什么他称之为回溯?在这里使用回溯的确切位置?
  2. 我理解第一个输出字符串((()))是如何生成的;但其余的如何生成?
  3. 谢谢!

3 个答案:

答案 0 :(得分:0)

我不清楚为什么调用辅助方法backtrack

至于字符串的生成方式,backtrack是一种递归方法,所以......

第一次调用它时,str = ""open < maxclose = open,因此只执行一次对回溯的递归调用。

现在str = "("open < maxclose < open,因此都会进行递归调用。

在一个电话str = "(("和另一个电话str = "()"中。在第一次调用open < maxclose < open中,进行两次递归调用。在另一个调用open < maxclose = open中,因此只进行了一次递归调用。

现在我们有3个电话,str = (((str = "(()str = "()(",此过程仍在继续,我认为很清楚如何创建所有排列。

答案 1 :(得分:0)

在没有看到原始代码的情况下,我无法说明其比较效率,但我可以解释Java代码的工作原理。让我们分解代码的递归部分。

public void backtrack(List<String> list,
                      String str,
                      int open,
                      int close,
                      int max) {

我们的功能将采取五个论点。第一个参数将用作 out 参数,这意味着我们将结果存储到其中。然后我们到目前为止采取字符串,开放的parens的数量,以及关闭parens的数量。最后,我们采用最大长度,该长度应保持不变。

if(str.length() == max*2){
    list.add(str);
    return;
}

这是基本情况。这很容易。变量max存储括号对的数量,因此如果我们构建的字符串的长度为max * 2,则我们有max个开放的parens和max关闭的parens,意思是我们有一个完整的字符串所以我们将当前字符串添加到累加器列表中并停止递归。

if(open < max)
    backtrack(list, str+"(", open+1, close, max);

现在,如果我们允许的max开放括号少于backtrack,我们应该尝试添加一个新的左括号。在这里使用这些参数调用if(close < open) backtrack(list, str+")", open, close+1, max); 将向字符串附加一个开放的paren,然后为该字符串的其余部分执行所有可能的组合(在该过程中就地修改list参数),然后返回到此在代码中指出。

backtrack

接下来,如果我们关闭的parens比开放的parens少,我们还想尝试在字符串的末尾添加一个close paren。此List调用将尝试添加关闭paren的所有可能性,并将所有成功结果添加到累加器列表。

这里的诀窍是我们多次将累加器传递给我们的调用堆栈。列表本身通过引用传递 ,因为它是一个Java对象。所以,实际上,只有一个list.add(str)对象被传递,每次我们generateParenthesis时,它都会将当前结果添加到这个&#34; global-ish&#34 ;名单。然后,当我们到达您调用int* ret() { int x=0; int y=0; int *b = malloc(2 * sizeof(*b)); b[0] = x; b[1] = y; return b; } 的方法的末尾时,我们所要做的就是返回这个我们一直在变异的列表对象。

答案 2 :(得分:0)

如下所示,必须用c ++重写你的java程序。对不起,摆脱了清单。它打印出递归中的每一步。希望它会让你的理解变得更好。

#include <iostream>
#include <string>

using namespace std;

void backtrack(string str, int open, int close, int max);

void generateParenthesis(int n) {
  cout << "Generating parenthesises for n = " << n << endl;
  backtrack( "", 0, 0, n);
}

void backtrack(string str, int open, int close, int max){

  if(str.length() == max*2){
    cout << "==> " << open << " " << close << ": \"" << str << "\"" << endl;
    return;
  }
  cout << "+++ " << open << " " << close << ": \"" << str << "\"" << endl;

  if(open < max)
    backtrack(str+"(", open+1, close, max);
  if(close < open)
    backtrack(str+")", open, close+1, max);
}

int main() {
  generateParenthesis(3);
  return 0;
}

结果如下:

$ ./p1
Generating parenthesises for n = 3
+++ 0 0: ""
+++ 1 0: "("
+++ 2 0: "(("
+++ 3 0: "((("
+++ 3 1: "((()"
+++ 3 2: "((())"
==> 3 3: "((()))"
+++ 2 1: "(()"
+++ 3 1: "(()("
+++ 3 2: "(()()"
==> 3 3: "(()())"
+++ 2 2: "(())"
+++ 3 2: "(())("
==> 3 3: "(())()"
+++ 1 1: "()"
+++ 2 1: "()("
+++ 3 1: "()(("
+++ 3 2: "()(()"
==> 3 3: "()(())"
+++ 2 2: "()()"
+++ 3 2: "()()("
==> 3 3: "()()()"