Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/388.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 了解多个递归调用的用例_Java_Recursion_Dynamic Programming - Fatal编程技术网

Java 了解多个递归调用的用例

Java 了解多个递归调用的用例,java,recursion,dynamic-programming,Java,Recursion,Dynamic Programming,我试图解决一个问题,在给定一个整数的情况下,得到所有可能的有效括号组合。例如,输入:n=2,输出:(()),(()) 显然,随着n的增加,当前输出建立在前一个n的输出的基础上。因此,通过获取前面的结果并将其相加以获得当前结果,很容易得出递归结果: HashSet<String> getCombinations(int n) { HashSet<String> result = new HashSet<String>(); if (n <=

我试图解决一个问题,在给定一个整数的情况下,得到所有可能的有效括号组合。例如,
输入:n=2,输出:(()),(())

显然,随着
n
的增加,当前输出建立在前一个n的输出的基础上。因此,通过获取前面的结果并将其相加以获得当前结果,很容易得出递归结果:

HashSet<String> getCombinations(int n)
{
    HashSet<String> result = new HashSet<String>();
    if (n <= 0) return null;
    if (n == 1)
    {
        result.add("()");
        return result;
    }
    for (String str: getCombinations(n - 1))
    {
        for (int i = 0; i < str.length(); i++)
        {
            result.add(new StringBuffer(str).insert(i, "()").toString());
        }
    }
    return result;
}
HashSet-getcombines(int-n)
{
HashSet result=新的HashSet();
如果(n右)返回;
如果(nLeft==0&&nRight==0)
{
结果:添加(str);
返回;
}
getCombinations(索引+1,nLeft-1,nRight,新的StringBuffer(str).insert(索引,“(”).toString());
getcompositions(索引+1,nLeft,nRight-1,新的StringBuffer(str).insert(索引“)”).toString();
}
我理解这个解决方案是如何工作的,以及为什么它比第一个更好。但即使是现在,我也无法想象先看到第一个解决方案,然后再想到第二个解决方案。我如何直观地理解何时使用多个递归调用?换句话说,在实现了解决方案1之后,我怎么能认为使用多个递归调用可能会更好呢


我的问题不是针对上述问题,而是一般问题的类型。

您可以将此问题视为1和-1的排列,当将其相加时,运行总和(从左到右相加时的临时值)不得小于0,或者如果是圆括号,右括号不能多于左括号。 因此:

如果
n=1
,则只能执行
1+(-1)
。 如果
n=2
,则可以执行
1+-1)+1+-1
1+1+-1+-1


因此,当您创建这些排列时,您会发现在每个递归调用中只能使用这两个选项中的一个,即
1
-1
,并且通过跟踪
nLeft
nRight
使用的内容,您可以让程序知道何时停止

我想你是在试图解释上述解决方案是如何工作的。这不是我要问的。我理解逻辑和停止条件等。我不理解的是我如何直觉地从解决方案1跳到解决方案2。我怎么能想到“嗯,在这种情况下,我最好使用多个递归调用”。这不是一个容易问的问题:)好吧,一旦你明白你只能附加两个函数中的一个——或者
或者
,你就会发现这是一个二叉树,你需要多次递归调用来探索所有的叶子。如何从解决方案1跳到解决方案2只是选择了不同的方法。我无法将这个问题想象为一个二叉树。你能详细说明一下吗?我想关键的提示是“分而治之”。()它通常意味着多次递归调用。我不确定我是否同意。我认为这更多地属于动态规划领域,而不是分而治之,尽管我可能错了。就像合并排序是分而治之-我可以将问题清楚地划分为两个子问题,并最终合并结果。这里的情况似乎不是这样。我没有把输入像这样插入2。你确定吗?在我看来,你把你的问题分为两个问题:左手边的问题和右手边的问题。不,我不完全确定。这就是我在这里发帖的原因。虽然我觉得不是。当我考虑合并排序或矩阵乘法时,我清楚地将输入问题分为2,求解和合并。虽然这里似乎不是这样,或者至少(对我来说)不明显!
ArrayList<String> result = new ArrayList<>();
void getCombinations(int index, int nLeft, int nRight, String str)
{
    if (nLeft < 0 || nRight < 0 || nLeft > nRight) return;
    if (nLeft == 0 && nRight == 0)
    {
        result.add(str);
        return;
    }
    getCombinations(index + 1, nLeft - 1, nRight, new StringBuffer(str).insert(index, "(").toString());
    getCombinations(index + 1, nLeft, nRight - 1, new StringBuffer(str).insert(index, ")").toString());
}