递归回溯仅适用于少量输入。输入较大会导致stackOverFlow

时间:2018-10-16 01:45:11

标签: java recursion backtracking

我正在解决一个似乎需要某种回溯的问题。我有一个有效的递归方法,但stackOverFlow发生在较大的输入中。可以通过迭代实现解决吗?我正在尝试实现一个采用两个目标值a和b的方法。从a = 1和b = 1开始,要达到目标a和b值需要多少次“加法”?加法可以使a = a + b或b = b + a,但不能两者都做。 例如,如果目标a = 2和目标b = 1,则需要1个“加”。 a = 1&b = 1,a = a + b =2。

public static String answer(String M, String F) { 
    return answerRecur(new BigInteger(M), new BigInteger(F), 0);
}   

public static String answerRecur(BigInteger M, BigInteger F, int its) {
    if(M.toString().equals("1") && F.toString().equals("1")) {
        return "" + its;
    }
    else if(M.compareTo(new BigInteger("0")) <=0 || F.compareTo(new BigInteger("0")) <=0) {
        return "impossible";
    }
    String addM = answerRecur(M.subtract(F), F, its +1);
    String addF = answerRecur(M, F.subtract(M), its +1);
    if(!addM.equals("impossible")) {
        return addM;
    }
    if(!addF.equals("impossible")) {
        return addF;
    }
    return "impossible";
}

1 个答案:

答案 0 :(得分:0)

递归回溯通过遍历所有候选步骤,执行步骤,递归和撤消该步骤来进行。

这意味着,如果一个解决方案包含N个项目,则理想情况下,递归深度不会超过N。

所以:预计不会发生溢出,可能会尝试过多,甚至无限地重复发生。

但是,在您的情况下,BigInteger可能足够大,而当使用较小的步骤(1)时,递归深度会非常大。每个电话都会产生足够的收益。最好是int或long而不是BigInteger。

在每个电话中,您都有两个候选人:

  • M.subtract(F)
  • F.subtract(M)

您对两者都进行了评估,发现结果可能会停止。

缺少(数学上的!)智力:很好的办法是防止太多的步骤,尽可能地找到解决方案。通常,这可以通过对(2)个候选者进行排序的方式来实现。

如何提供一种智能解决方案?首先,数学必须是可读的,而BigInteger则少。手动尝试一些示例解决方案,然后寻找一种 smart 方法来对尝试进行排序。

假设M和F保持正数,您可以缩短递归:

if (M.compareTo(BigInteger.ZERO) <= 0 || F.compareTo(BigInteger.ZERO) <= 0) {
    return "impossible";
}
if (M.equals(BigInteger.ONE)) {
    return String.valueOf(F.intValue() - 1 + its);
}
if (F.equals(BigInteger.ONE)) {
    return String.valueOf(M.intValue() - 1 + its);
}

对于整数除法(和取模)可以做到这一点:

if (M.compareTo(F) > 0) {
    String addM = answerRecur(M.mod(F), F, its + M.divided(F).intValue());
}

尽管有多个递归调用,实际上仍然可以考虑使用迭代解决方案,但这不会增加质量。

备注:

  • 根据Java惯例,变量名称应使用fm
  • 真的需要BigInteger吗?这会导致代码有些尴尬。