问题描述:
该问题在算法导论中引申自求解两个DNA序列相似度的问题。
可以从很多角度定义两个DNA序列的相似度,其中有一种定义方法就是通过序列对齐的方式来定义其相似度。
给定两个DNA序列A和B,对齐的方式是将空格分别插入到A和B序列中,得到具有相同长度的对齐后的序列C和D;空格可以插入到任意的位置(包括两端),但是相同位置不能同时为空格,也即是不存在C[i]和D[i]同时为空格的情况。然后为对齐后的序列的每个位置打分,总分为每个位置得分之和,具体的打分规则如下:
a、如果C[i] == D[i]且都不是空格,得3分;
b、如果C[i] != D[j]且都不是空格,得1分;
c、如果C[i] 或者D[i]是空格,得0分。
求给定原序列A和B的一个对齐方案,使得该对齐方案的总分最高。
例如,序列原序列A和B如下:
String strA = "GATC";
String strB = "ATCG";
则其中一个对齐方案如下:
GATC*
*ATCG
该方案总得分score=2*0+3*3 = 9分。
实际上这是最优的对齐方案,在所有的对齐方案中总得分最高为9分。
问题分析:
为了用更加简单的方式来表示对齐的方案,我们尝试用一些特定的字符记号来表示对齐方案,对此,首先做一个约定,对于打分规则:
1、情况a用“=”字符标记;
2、情况b用“~”字符标记;
3、情况c用“*”字符标记,但是情况c实际上可以细分为两种情况:C[i]为空格时用“+”标记,D[i]为空格时用“-”号标记。这样用“+”和“-”细分的表示相比于统一用“*”来表示,本质的区别在于让对齐方案具有所谓的“方向性”,后面会看到这样的细分对于算法的实现有一定的好处。
有了这样的约定,可以将一个对齐方案用这些字符表示出来,该字符串称之为一个对齐规则字符串R。
例如上面的例子中,对齐规则就可以用字符串“-===+”来表示。
可以推断,任何两个原序列的对齐规则字符串R的长度必然满足:
只要能够求得最优对齐方案的对齐规则字符串,就可以计算出最高分数,还可以还原出各自的对齐序列。
考察该问题的最优子结构性质,与最长公共子序列思考的角度比较类似,
用C(i,j)表示序列A[0]…A[i]和序列B[0]…B[j]的最优对齐方案的得分,不难得出其初始条件和递推求解式:
用R(i,j)表示序列A[0]…A[i]和序列B[0]…B[j]的最优对齐方案的对齐规则字符串,结合上面的递推求解式,不难推出对齐规则字符串的运算规则:
算法实现:
package agdp;
public class Alignment {
//根据对齐骨规则生成相应的对