在生物应用中,经常需要比较两个(或多个)不同生物体的DNA,

例如:某种生物的DNA可能为S1=ACCGGTCGAGTGCGCGGAAGCCGGCCGAA,

另一种生物的DNA可能为S2=GTCGTTCGGAATGCCGTTGCTCTGTAAA

我们比较两个DNA串的一个原因是希望确定它们的相似度,作为度量两种生物的近似程度指标

寻找第三个串S3,它所有碱基也都出现在S1和S2中,且三个串中的顺序都相同,但在S1和S2中不要求连续出现。

可以找到的S3越长,就可以认为S1和S2的相似度越高。在这个例子中最长的S3为GTCGTCGGAAGCCGGCCGAA

我们定义C[i, j]表示Xi和Yj的LCS长度。如果i = 0或j = 0,即一个序列长度为0,那么LCS的长度为0

根据LCS问题的最优子结构性质,可得如下公式:

C[i, j] = 0,若i = 0 或 j = 0

C[i, j] = C[i - 1, j - 1] + 1,若i,j > 0 且 Xi = Yj

C[i, j] = max(C[i, j - 1], C[i - 1, j]) ,若i, j > 0且Xi != Yj

代码如下:

package 动态规划;

/**
* Lcs即最长公共子序列问题(longest common subsequence problem)
* @author wangdong20
*
*/
public class Lcs {
public static final int empty = 0;
public static final int upLeft = 1;
public static final int up = 2;
public static final int left = 3; public static int[][][] lcsLength(String x, String y){
int m = x.length();
int n = y.length();
int[][][] result = new int[2][m + 1][n + 1]; // result[0]表示子序列长度 result[1]表示LCS矩阵方向 for(int i = 0; i < m + 1; i++){
result[0][i][0] = 0;
result[1][i][0] = empty;
} for(int j = 0; j < n + 1; j++){
result[0][0][j] = 0;
result[1][0][j] = empty;
} for(int i = 1; i <= m; i++){
for(int j = 1; j <= n; j++){
if(x.charAt(i - 1) == y.charAt(j - 1)){
result[0][i][j] = result[0][i - 1][j - 1] + 1;
result[1][i][j] = upLeft;
}
else if(result[0][i - 1][j] >= result[0][i][j - 1]){
result[0][i][j] = result[0][i - 1][j];
result[1][i][j] = up;
}
else{
result[0][i][j] = result[0][i][j - 1];
result[1][i][j] = left;
}
}
} return result;
} public static void printLcs(int[][][] b, String x, int i, int j){
if(i == 0 || j == 0)
return;
if(b[1][i][j] == upLeft){
printLcs(b, x, i - 1, j - 1);
System.out.print(x.charAt(i - 1));
}
else if(b[1][i][j] == up){
printLcs(b, x, i - 1, j);
}
else{
printLcs(b, x, i, j - 1);
}
} /**
* @param args
*/
public static void main(String[] args) {
// TODO 自动生成方法存根
String s1 = "ACCGGTCGAGTGCGCGGAAGCCGGCCGAA";
String s2 = "GTCGTTCGGAATGCCGTTGCTCTGTAAA";
String s3 = "amputation";
String s4 = "spanking"; System.out.println("s1: " + s1);
System.out.println("s2: " + s2);
System.out.println("最长公共子序列: "); int result[][][] = lcsLength(s1, s2);
printLcs(result, s1, s1.length(), s2.length()); System.out.println("\ns3: " + s3);
System.out.println("s4: " + s4);
System.out.println("最长公共子序列: "); int result2[][][] = lcsLength(s3, s4);
printLcs(result2, s3, s3.length(), s4.length());
} }

实质上lcsLength(s3, s4)返回的是两个二维数组组成的三维数组

代码中result[0][i][j]保存的是图中显示的到字符串Xi, Yj目前的LCS长度

result[1][i][j]保存的是图中显示的字符串Xi, Yj的指引方向关系

得到这幅图我们就可以从中得出表b[m, n]

为了得出最后的LCS字符串,只需要从b[m, n]开始,按照箭头方向追踪下去即可。

当b[i, j]遇到upLeft左上时,意味着Xi = Yj是LCS的一个元素.

按照这种方法可以逆序依次构造出LCS的所有元素

public static void printLcs(int[][][] b, String x, int i, int j){
if(i == 0 || j == 0)
return;
if(b[1][i][j] == upLeft){
printLcs(b, x, i - 1, j - 1);
System.out.print(x.charAt(i - 1));
}
else if(b[1][i][j] == up){
printLcs(b, x, i - 1, j);
}
else{
printLcs(b, x, i, j - 1);
}
}

最后运行结果:

LCS最大公共子序列问题的更多相关文章

  1. python3 lcs 最大公共子序列

    抛出问题: 假定字符串 s1 = 'BDCABA', s2 = 'ABCBDAB',求s1和s2的最大公共子序列. 问题分析: 我们想要求出s1和s2的最大公共子序列,我们可以用c(i,j)表示s1( ...

  2. LCS最大公共子序列【转载】

    在两个字符串中,有些字符会一样,可以形成的子序列也有可能相等,因此,长度最长的相等子序列便是两者间的最长公共字序列,其长度可以使用动态规划来求. 以s1={1,3,4,5,6,7,7,8},s2={3 ...

  3. 动态规划之LCS(最大公共子序列)

    #include <stdio.h> #include <string.h> int b[50][50]; int c[50][50]; int length = 0; voi ...

  4. Poj1159 Palindrome(动态规划DP求最大公共子序列LCS)

    一.Description A palindrome is a symmetrical string, that is, a string read identically from left to ...

  5. Advanced Fruits (最大公共子序列的路径打印)

    The company "21st Century Fruits" has specialized in creating new sorts of fruits by trans ...

  6. hdu 1243 反恐训练营(dp 最大公共子序列变形)

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=1243 d[i][j] 代表第i 个字符与第 j 个字符的最大的得分.,, 最大公共子序列变形 #inclu ...

  7. spoj Longest Common Substring (多串求最大公共子序列)

    题目链接: https://vjudge.net/problem/SPOJ-LCS 题意: 最多10行字符串 求最大公共子序列 数据范围: $1\leq |S| \leq100000$ 分析: 让他们 ...

  8. POJ - 2250 Compromise (LCS打印序列)

    题意:给你两个单词序列,求出他们的最长公共子序列. 多组数据输入,单词序列长度<=100,单词长度<=30 因为所有组成LCS的单词都是通过 a[i] == b[j] 更新的. 打印序列的 ...

  9. Common Subsequence 最大公共子序列问题

    Problem Description A subsequence of a given sequence is the given sequence with some elements (poss ...

随机推荐

  1. 蛋疼的Apple IOS Push通知协议

    简单介绍 Apple Push通知机制事实上非常easy,就是Apple的APNsserver做为中间人,把消息推送到相应的设备上. 一张来自Apple文档的图: 当然,示意图看起来简单,可是另一些实 ...

  2. tab group of firefox

    https://addons.mozilla.org/en-US/firefox/addon/tabgroups-menu/? src=search#detail-relnotes https://g ...

  3. codeforces #267 C George and Job(DP)

    职务地址:http://codeforces.com/contest/467/problem/C 太弱了..这题当时都没做出来..思路是有的,可是自己出的几组数组总是过不去..今天又又一次写了一遍.才 ...

  4. jQuery 删除HTML元�

    jQuery使用以下两个方法来删除或是清空某个HTML元素. remove() – 删除指定的元素(包含其子元素) empty() – 清空指定元素的子元素 比如: <!DOCTYPE html ...

  5. Java基础06 组合

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 我们已经尝试去定义类.定义类,就是新建了一种类型(type).有了类,我们接着构造 ...

  6. 基于visual Studio2013解决C语言竞赛题之1026判断排序

          题目 解决代码及点评 /********************************************************************** ...

  7. UPC 2959: Caoshen like math 这就是个水题

    http://acm.upc.edu.cn/problem.php?id=2959 这就是个水题,之所以要写这个题是感觉很有纪念意义 用力看就是盲……23333333333333333 这个题就是最小 ...

  8. 页面提交进不了Action的原因

    1.进不了action,页面没有任何js报错,可能的原因是数据类型不一致.例如用ajax方式提交所带的参数类型a是String类型,而action中定义的a是Integer类型就会导致这种情况的发生.

  9. JVM类加载过程学习总结

    JVM类加载过程学习总结 先不说JVM类加载的原理,先看实例: NormalTest类,包含了一个静态代码块,执行的任务就是打印一句话. /** * 在正常类加载条件下,看静态代码块是否会执行 * @ ...

  10. 《C陷阱与缺陷》整理二

    1.数组名作实參     在C语言中,我们没有办法将一个数组作为函数參数传递,假设我们使用数组名作为參数.这个时候数组名立马会被转换为指向该数组的第一个元素的指针.     关于这一点的理解能够向前深 ...