您的位置:首页 > 其它

最长公共子序列(LCS)

2012-08-20 20:50 183 查看
先介绍LCS问题的性质:记Xm={x0, x1,…xm-1}和Yn={y0,y1,…,yn-1}为两个字符串,而Zk={z0,z1,…zk-1}是它们的LCS,则:

1. 如果xm-1=yn-1,那么zk-1=xm-1=yn-1,并且Zk-1是Xm-1和Yn-1的LCS;

2. 如果xm-1≠yn-1,那么当zk-1≠xm-1时Z是Xm-1和Y的LCS;

3. 如果xm-1≠yn-1,那么当zk-1≠yn-1时Z是Yn-1和X的LCS;

下面简单证明一下这些性质:

1. 如果zk-1≠xm-1,那么我们可以把xm-1(yn-1)加到Z中得到Z’,这样就得到X和Y的一个长度为k+1的公共子串Z’。这就与长度为k的Z是X和Y的LCS相矛盾了。因此一定有zk-1=xm-1=yn-1。

既然zk-1=xm-1=yn-1,那如果我们删除zk-1(xm-1、yn-1)得到的Zk-1,Xm-1和Yn-1,显然Zk-1是Xm-1和Yn-1的一个公共子串,现在我们证明Zk-1是Xm-1和Yn-1的LCS。用反证法不难证明。假设有Xm-1和Yn-1有一个长度超过k-1的公共子串W,那么我们把加到W中得到W’,那W’就是X和Y的公共子串,并且长度超过k,这就和已知条件相矛盾了。

2. 还是用反证法证明。假设Z不是Xm-1和Y的LCS,则存在一个长度超过k的W是Xm-1和Y的LCS,那W肯定也X和Y的公共子串,而已知条件中X和Y的公共子串的最大长度为k。矛盾。

3. 证明同2。

有了上面的性质,我们可以得出如下的思路:求两字符串Xm={x0,x1,…xm-1}和Yn={y0,y1,…,yn-1}的LCS,如果xm-1=yn-1,那么只需求得Xm-1和Yn-1的LCS,并在其后添加xm-1(yn-1)即可;如果xm-1≠yn-1,我们分别求得Xm-1和Y的LCS和Yn-1和X的LCS,并且这两个LCS中较长的一个为X和Y的LCS。

如果我们记字符串Xi和Yj的LCS的长度为c[i,j],我们可以递归地求c[i,j]:

/ 0
if i<0 or j<0

c[i,j]= c[i-1,j-1]+1 ifi,j>=0
and xi=xj

\
max(c[i,j-1],c[i-1,j] ifi,j>=0 and xi≠xj

上面的公式用递归函数不难求得。

#include <string.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;

// directions of LCS generation
enum decreaseDir
{
kInit = 0, kLeft, kUp, kLeftUp
};
void LCS_Print(int **LCS_direction, char* pStr1, char* pStr2, size_t row,
size_t col);
/////////////////////////////////////////////////////////////////////////////
// Get the length of two strings' LCSs, and print one of the LCSs
// Input: pStr1         - the first string
//        pStr2         - the second string
// Output: the length of two strings' LCSs
/////////////////////////////////////////////////////////////////////////////
int LCS(char* pStr1, char* pStr2)
{
if (!pStr1 || !pStr2)
return 0;

size_t length1 = strlen(pStr1);
size_t length2 = strlen(pStr2);
if (!length1 || !length2)
return 0;

size_t i, j;

// initiate the length matrix
int **LCS_length;
LCS_length = (int**) (new int[length1]);
for (i = 0; i < length1; ++i)
LCS_length[i] = (int*) new int[length2];

for (i = 0; i < length1; ++i)
for (j = 0; j < length2; ++j)
LCS_length[i][j] = 0;

// initiate the direction matrix
int **LCS_direction;
LCS_direction = (int**) (new int[length1]);
for (i = 0; i < length1; ++i)
LCS_direction[i] = (int*) new int[length2];

for (i = 0; i < length1; ++i)
for (j = 0; j < length2; ++j)
LCS_direction[i][j] = kInit;

for (i = 0; i < length1; ++i)
{
for (j = 0; j < length2; ++j)
{
if (i == 0 || j == 0)
{
if (pStr1[i] == pStr2[j])
{
LCS_length[i][j] = 1;
LCS_direction[i][j] = kLeftUp;
}
else
LCS_length[i][j] = 0;
}
// a char of LCS is found,
// it comes from the left up entry in the direction matrix
else if (pStr1[i] == pStr2[j])
{
LCS_length[i][j] = LCS_length[i - 1][j - 1] + 1;
LCS_direction[i][j] = kLeftUp;
}
// it comes from the up entry in the direction matrix
else if (LCS_length[i - 1][j] > LCS_length[i][j - 1])
{
LCS_length[i][j] = LCS_length[i - 1][j];
LCS_direction[i][j] = kUp;
}
// it comes from the left entry in the direction matrix
else
{
LCS_length[i][j] = LCS_length[i][j - 1];
LCS_direction[i][j] = kLeft;
}
}
}
LCS_Print(LCS_direction, pStr1, pStr2, length1 - 1, length2 - 1);
/*for (i = 0; i < length1; i++)
{
printf("\n");
for (j = 0; j < length2; j++)
{
printf("%d%s\t", LCS_length[i][j],
(LCS_direction[i][j] == kUp ?
"↑" :	(LCS_direction[i][j] == kLeft ?	"←" :
(LCS_direction[i][j] == kLeftUp ? "↖" : " "))));
}
}*/
int len = LCS_length[length1 - 1][length2 - 1];
for (i = 0; i < length1; ++i)
delete[] LCS_length[i];
delete[] LCS_length;
return len;
}

/////////////////////////////////////////////////////////////////////////////
// Print a LCS for two strings
// Input: LCS_direction - a 2d matrix which records the direction of
//                        LCS generation
//        pStr1         - the first string
//        pStr2         - the second string
//        row           - the row index in the matrix LCS_direction
//        col           - the column index in the matrix LCS_direction
/////////////////////////////////////////////////////////////////////////////
void LCS_Print(int **LCS_direction, char* pStr1, char* pStr2, size_t row,
size_t col)
{
if (pStr1 == NULL || pStr2 == NULL)
return;

size_t length1 = strlen(pStr1);
size_t length2 = strlen(pStr2);

if (length1 == 0 || length2 == 0 || !(row < length1 && col < length2))
return;

// kLeftUp implies a char in the LCS is found
if (LCS_direction[row][col] == kLeftUp)
{
if (row > 0 && col > 0)
LCS_Print(LCS_direction, pStr1, pStr2, row - 1, col - 1);

// print the char
printf("%c", pStr1[row]);
}
else if (LCS_direction[row][col] == kLeft)
{
// move to the left entry in the direction matrix
if (col > 0)
LCS_Print(LCS_direction, pStr1, pStr2, row, col - 1);
}
else if (LCS_direction[row][col] == kUp)
{
// move to the up entry in the direction matrix
if (row > 0)
LCS_Print(LCS_direction, pStr1, pStr2, row - 1, col);
}
}

int main(void)
{
LCS("ABCBDAB", "BDCABA");//结果:BDAB
return 0;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: