我正在开发一个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版本也没有结束。我正在努力调试它,因为它是递归的。 任何人都知道它出了什么问题?
答案 0 :(得分:1)
正如其他人在评论中指出的那样,该计划本身是正确的。您遇到的问题是,在此实现中,代码具有指数时间复杂度,因此需要花费很长时间才能运行示例输入。如果让它运行一段时间,它将返回正确的结果。
正如其他人在评论中指出的那样,两个字符串之间的LCS可以使用动态编程以较低的时间复杂度来解决,这将更快地解决它。请参考互联网获取更多帮助(wikipedia),或者更好的是,尝试自己解决这个问题,考虑到每个长度为n的字符串确实存在N ^ 2个子字符串。你可以通过检查b中是否存在a的任何子串,在N ^ 2 * M ^ 2(n m是两个字符串的长度)中简单地求解它。问问自己,你是否可以做更好的运动?如果是,如果不是,为什么。