递归最长公共子序列循环还是永远?

时间:2015-07-16 10:17:03

标签: javascript java recursion

我正在开发一个JavaScript应用程序,我需要一个最长公共子序列的递归算法,所以我去了here并尝试了这个。 它是这样的:

function lcs(a, b) {
  var aSub = a.substr(0, a.length - 1);
  var bSub = b.substr(0, b.length - 1);

  if (a.length === 0 || b.length === 0) {
    return '';
  } else if (a.charAt(a.length - 1) === b.charAt(b.length - 1)) {
    return lcs(aSub, bSub) + a.charAt(a.length - 1);
  } else {
    var x = lcs(a, bSub);
    var y = lcs(aSub, b);
    return (x.length > y.length) ? x : y;
  }
}

直到现在我尝试过的几个测试用例都运行良好,但我发现它在以下测试用例中循环:

a:这个实体运作正常

b:这不行,但应该在

之后

它也循环:

a:这个实体运作正常

b:这不起作用

在某些时候应该进入中间分支。

我注意到它是同一算法的Java版本(here)的翻译。它是这样的:

public static String lcs(String a, String b){
    int aLen = a.length();
    int bLen = b.length();
    if(aLen == 0 || bLen == 0){
        return "";
    }else if(a.charAt(aLen-1) == b.charAt(bLen-1)){
        return lcs(a.substring(0,aLen-1),b.substring(0,bLen-1))
            + a.charAt(aLen-1);
    }else{
        String x = lcs(a, b.substring(0,bLen-1));
        String y = lcs(a.substring(0,aLen-1), b);
        return (x.length() > y.length()) ? x : y;
    }
}

我认为假设String.substr()和String.substring()相同(它们不是),JavaScript转换是错误的。 为了确保不是这种情况,我在相同的测试用例here上尝试了Java。

猜猜是什么?此外,java版本也没有结束。

我正在努力调试它,因为它是递归的。 任何人都知道它出了什么问题?

1 个答案:

答案 0 :(得分:1)

正如其他人在评论中指出的那样,该计划本身是正确的。您遇到的问题是,在此实现中,代码具有指数时间复杂度,因此需要花费很长时间才能运行示例输入。如果让它运行一段时间,它将返回正确的结果。

正如其他人在评论中指出的那样,两个字符串之间的LCS可以使用动态编程以较低的时间复杂度来解决,这将更快地解决它。请参考互联网获取更多帮助(wikipedia),或者更好的是,尝试自己解决这个问题,考虑到每个长度为n的字符串确实存在N ^ 2个子字符串。你可以通过检查b中是否存在a的任何子串,在N ^ 2 * M ^ 2(n m是两个字符串的长度)中简单地求解它。问问自己,你是否可以做更好的运动?如果是,如果不是,为什么。