您的位置:首页 > 其它

动态规划——最长公共子串

2014-04-29 21:07 295 查看
引入:

最长公共子序列常用于解决字符串的相似度问题。

最长公共子序列(Longest Common Subsequence,LCS)与最长公共字串(Longest Common Substring):子串是串的一个连续的部分,子序列则是从不改变序列顺序,而从序列中去掉任意多个元素而获得的新的序列;也就是说,子串中字符的位置一定是连续的,而子序列不一定连续。

a not the 之一(得到的未必就是唯一的那个最长公共子串,只有长度是唯一的)

——其余字符串问题,待续

解决方案:

[b]1、穷举法(Bruke force alg )[/b]

a[m] and b

check every sequence of a ,to see if it is a sequence of b .

analysis:

check = O(N)

2^m subsequence of a

so O(n*2^m)=slow

不可取:一个长度为N的字符串,其子序列有2^N个,指数级的复杂度。

2、递归法

对于字符串a[ ]和 b[ ],当a与b位置上的字符相同时,则直接求解下一个位置,当不同时取两种情况下较大的数值。

#include<stdio.h>

#include<string.h>

char a[500],b[500];

char num[501][501]; ///记录中间结果的数组

char flag[501][501];    ///标记数组,用于标识下标的走向,构造出公共子序列

void LCS(); ///动态规划求解

void getLCS();    ///采用倒推方式求最长公共子序列

int main()

{

int i;

strcpy(a,"ABCBDAB");

strcpy(b,"BDCABA");

memset(num,0,sizeof(num));

memset(flag,0,sizeof(flag));

LCS();

printf("%d\n",num[strlen(a)][strlen(b)]);

getLCS();

return 0;

}

void LCS()

{

int i,j;

for(i=1;i<=strlen(a);i++)

{

for(j=1;j<=strlen(b);j++)

{

if(a[i-1]==b[j-1])   ///注意这里的下标是i-1与j-1

{

num[i][j]=num[i-1][j-1]+1;

flag[i][j]=1;  ///斜向下标记

}

else if(num[i][j-1]>num[i-1][j])

{

num[i][j]=num[i][j-1];

flag[i][j]=2;  ///向右标记

}

else

{

num[i][j]=num[i-1][j];

flag[i][j]=3;  ///向下标记

}

}

}

}

void getLCS()

{

char res[500];

int i=strlen(a);

int j=strlen(b);

int k=0;    ///用于保存结果的数组标志位

while(i>0 && j>0)

{

if(flag[i][j]==1)   ///如果是斜向下标记

{

res[k]=a[i-1];

k++;

i--;

j--;

}

else if(flag[i][j]==2)  ///如果是斜向右标记

j--;

else if(flag[i][j]==3)  ///如果是斜向下标记

i--;

}

for(i=k-1;i>=0;i--)

printf("%c",res[i]);

}


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