算法实战3:最长公共子序列

来源:互联网 发布:微信小程序跳转到淘宝 编辑:程序博客网 时间:2024/04/29 12:44

在很多实际应用中,经常需要比较两个序列的相似性,例如DNA,或者文档的查重,但是往往这些序列相同部分不一定是相连,中间可能存在一些干扰元素,这就需要找出这种最长的公共子序列。

序列:X=<A,B,C,B,D,A,B>  Y=<B,D,C,A,B,A>

这两个序列最长的公共子序列(Longest Common Subsequence)是Z=<B,C,A,B>  Z=<B,D,A,B>

如何用程序找出来呢?

-----------------

这道题是一个很经典的动态规划的题目,所以大家得好好掌握动态规划其中的奥秘。

通常,动态规划的解题思路是希望能够找到大问题的子问题,通过求解子问题的最优解,然后再合并找出大问题的最优解。

往往这种子问题的划分需要从后开始,就是从问题解决开始逆推。

假设我们这里找到了X和Y 的一个LCS,那么这里的LCS是否包括来X和Y的最后一个字符呢?

所以分类分成两类


这里两类情况,就是如果XY最后一个元素相等,则LCS的元素也是这个。

如果不等,则分别考虑各自的子问题。

最后得到递推式,根据递推式我们可以很好的写出程序,借助一个map记录已经得到的LCS


下面给出打印其中一个解的例子

主要是借助map来解题来

//============================================================================// Name        : LCS.cpp// Author      : YLF// Version     :// Copyright   : Your copyright notice// Description : Hello World in C++, Ansi-style//============================================================================#include <iostream>#include <string.h>using namespace std;void FindLCS(char* str1, char* str2);void PrintLCS(char* str1, char* str2, int** map);int main() {char str1[]="ABCBDAB";char str2[]="BDCABA";FindLCS(str1,str2);return 0;}void FindLCS(char* str1, char* str2){int len1 = strlen(str1);int len2 = strlen(str2);int i = 0,j = 0;int **map = new int*[len1+1];for(i=0;i<len1+1;i++)map[i] = new int[len2+1];//根据分类的第一个 i或j=0for(i=0;i<len1+1;i++)map[i][0] = 0;for(i=0;i<len2+1;i++)map[0][i] = 0;//根据剩下的两个条件for(i=1;i<len1+1;i++){for(j=1;j<len2+1;j++){if(str1[i-1] == str2[j-1])map[i][j] = map[i-1][j-1] + 1;elsemap[i][j] = map[i-1][j]>map[i][j-1]?map[i-1][j]:map[i][j-1];}}//PrintMapcout<<endl;for(i=0;i<len1+1;i++){for(j=0;j<len2+1;j++)cout<<map[i][j]<<" ";cout<<endl;}//PrintLCSPrintLCS(str1,str2,map);}void PrintLCS(char* str1, char* str2, int** map){int len1 = strlen(str1);int len2 = strlen(str2);int min = len1>len2?len2:len1;char* LCS = new char[min];min=0;int i = len1 ,j = len2;while(i!=0 && j!=0){if(map[i][j]>map[i-1][j] && map[i][j]>map[i][j-1]){LCS[min++] = str1[i-1];i--;j--;}else{if(map[i-1][j]>map[i][j-1])i--;elsej--;}}while(min>0){min--;cout<<LCS[min];}}

这个map格式如下

__________________

0  A  B  C  B  D  A  B

C

A

B

A

----------------------------------

0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 1 1 1 2 2 0 1 1 2 2 2 2 0 1 1 2 2 3 3 0 1 2 2 2 3 3 0 1 2 2 3 3 4 0 1 2 2 3 4 4 BDAB