我正在寻找序列比对问题的递归代码。在搜索之后我找到了Needleman Wunsch算法,但矩阵表的构建是用两个for循环实现的,除了我找不到任何在正常时间内完成这个技巧的递归代码。有关递归代码实现的任何想法吗? 谢谢!
答案 0 :(得分:2)
为什么需要递归算法?
看起来序列对齐问题可以通过动态编程来解决 - 这就是Needleman Wunsch算法正在做的事情。在维基百科页面(http://en.wikipedia.org/wiki/Needleman-Wunsch_algorithm)中,有一个解决问题的复发。这个是一个递归解决方案。但是,此递归解决方案反复执行相同的子问题计算。动态编程解决方案通过解决问题自下而上,并通过两个for循环存储计算以供将来查找(memoization)。
答案 1 :(得分:2)
索引变得有点乱,因为我在基于0的数组中使用字符串的长度和as 界。但这很接近这与复发有多接近。 以二次方式分配堆栈帧 然而,对于不支持尾调用的VM而言,这不是一个好主意 以及不是尾递归的实现。
运行时间: O(n * m)
public static int solveWithCache(String n, String m) {
String paddedN = " " + n; //makes some indexing easier if we pad.
String paddedM = " " + m;
int[][] cache = new int[paddedN.length()][paddedM.length()];
for(int[] row : cache)
Arrays.fill(row, Integer.MIN_VALUE);
return solveWithCacheCompute(paddedN, paddedM, paddedN.length()-1, paddedM.length()-1, cache);
}
private static int solveWithCacheCompute(String n, String m, int i, int j, int[][] cache) {
if(i == 0 && j == 0) return 0;
if(cache[i][j] != Integer.MIN_VALUE) return cache[i][j];
if(i == 0) return (j) * gapPenalty;
if(j == 0) return (i) * gapPenalty;
int matchScore = (n.charAt(i) == m.charAt(j)) ? matchBenefit : mismatchPenalty;
int leaveIt = solveWithCacheHelper(n, m, i-1, j-1, cache) + matchScore;
int addGapN = solveWithCacheHelper(n, m, i-1, j, cache) + gapPenalty;
int addGapM = solveWithCacheHelper(n, m, i, j-1, cache) + gapPenalty;
return Math.max(leaveIt, Math.max(addGapN, addGapM));
}
(轻松比较) 典型的DP风格。尽管看那些索引;他们很棘手。
public static int solve(String n, String m) {
int nlen = n.length();
int mlen = m.length();
int[][] maxAlign = new int[nlen + 1][mlen + 1];
for(int q = 0; q <= nlen; q++)
maxAlign[q][0] = q * gapPenalty;
for(int r = 0; r <= mlen; r++)
maxAlign[0][r] = r * gapPenalty;
for(int i = 1; i <= nlen; i++) {
for(int j = 1; j <= mlen; j++) {
int matchScore = (n.charAt(i-1) == m.charAt(j-1)) ? matchBenefit : mismatchPenalty;
int leaveIt = maxAlign[i-1][j-1] + matchScore;
int addGapN = maxAlign[i-1][j] + gapPenalty;
int addGapM = maxAlign[i][j-1] + gapPenalty;
maxAlign[i][j] = Math.max(leaveIt, Math.max(addGapN, addGapM));
}
}
return maxAlign[nlen][mlen];
}