最长公共子序列

来源:互联网 发布:淘宝app下载 电脑 编辑:程序博客网 时间:2024/04/30 05:24

最长公共子序列问题(LCS)

问题描述:

         所谓子序列是子序列是从最初序列通过去除某些元素但不破坏余下元素的相对位置而形成的新序列。形如X=<x1, x2, x3………, xm>这个序列,对于Z=<xi1, xi2, xi3 ………, xik>就是X的子序列。e.g. X=<A,B,C,D,E,F,G,H> Z=<A,D,F>就是X的一个子序列。

         公共子序列就是多个序列(如X,Y),现如果存在Z,且Z是X的子序列,Z又是Y的子序列,则Z就是X和Y的公共子序列。

         最长公共子序列的概念,从以上关于子序列和公共子序列的概念中,我们可以很简单的知道,最长公共子序列就是多个序列的公共子序列中最长的一个。e.g. X=<A,B,C,B,D,A,B>, Y=<B,D,C,A,B,A>则Z1=<B,C,B,A>, Z2=<B,C,A,B>, Z3=<B,D,A,B>都是X和Y的最长公共子序列,长度为4,而且我们从此可以得知最长公共子序列往往不是唯一的哟。

问题求解:

        对此问题用的是DP(动态规划)的方法解决的,即使可以一眼看出来用brute-force(蛮力)依次匹配。但是这个蛮力的效率实在是不行啊。下面我们就开始对LCS问题的DP解法:

        分析:

        记Xi=﹤x1,…,xi﹥即X序列的前i个字符 (1≤i≤m)(前缀)Yj=﹤y1,…,yj﹥即Y序列的前j个字符 (1≤j≤n)(前缀)。假定Z=﹤z1,…,zk﹥∈LCS(X , Y)。

        若xm=yn(最后一个字符相同),则不难用反证法证明:该字符必是X与Y的任一最长公共子序列Z(设长度为k)的最后一个字符,即有zk = xm = yn ,且显然有Zk-1∈LCS(Xm-1 , Yn-1),即Z的前缀Zk-1是Xm-1与Yn-1的最长公共子序列。

        若xm≠yn,则亦不难用反证法证明:要么Z∈LCS(Xm-1, Y),要么Z∈LCS(X , Yn-1)。由于zk≠xm与zk≠yn其中至少有一个必成立因此:若zk≠xm则有Z∈LCS(Xm-1 , Y),若zk≠yn 则有Z∈LCS(X , Yn-1)。     

        ∴若xm=yn,则问题化归成求Xm-1与Yn-1的LCS,即(LCS(X , Y)的长度等于LCS(Xm-1 , Yn-1)的长度加1) 

            若xm≠yn,则问题化归成求Xm-1与Y的LCS及X与Yn-1的LCSLCS(X , Y)的长度为:Max {LCS(Xm-1 , Y)的长度, LCS(X , Yn-1)的长度}

         这两个问题不是相互独立的:

         ∵两者都需要求LCS(Xm-1,Yn-1)的长度,因而具有重叠性。此外,两个序列的LCS中包含了两个序列的前缀的LCS,故问题具有最优子结构性质  考虑用动态规划法。

 

         现引进一个二维数组C,

         用C[i,j]记录Xi与Yj的LCS的长度  如果我们是自底向上进行递推计算,那么在计算C[i,j]之前,

         C[i-1,j-1], C[i-1,j]与C[i,j-1]均已计算出来。此时根据X[i]=Y[j]还是X[i]Y[j],就可以计算出C[i,j]:

         若X[i]=Y[j],则执行C[i,j]←C[i-1,j-1]+1;

         若X[i]≠Y[j],进行下述判断:

               若C[i-1,j]≥C[i,j-1]则C[i,j]取C[i-1,j];

               否则C[i,j]取C[i,j-1]。

         即有

      

        为了构造出LCS,使用一个mn的二维数组b,b[i,j]记录C[i,j]是通过哪一个子问题的值求得的,以决定搜索的方向:

         若X[i]=Y[j],则b[i,j]中记入“↖”;

         否则

                 若C[i-1,j]=C[i,j-1],则b[i,j]中记入“↑或←”

                 若C[i-1,j]>C[i,j-1],则b[i,j]中记入“↑”;

                 若C[i-1,j] < C[i,j-1],则b[i,j]中记入“←”;

         这样就可以记录下来寻找LCS的路径了。

代码示例:

       用C语言对LCS问题进行了实现,基本上得到了预期结果。

#include <stdio.h>#include <stdlib.h>#include <string.h>#defineMAX_LEN512#defineTRACE_END0#defineUP1#defineLEFT2#defineUP_AND_LEFT3#defineUP_OR_LEFT4typedef char **(sub_strs_ptr);//to store lcs resualtsint is_exited_sstrs(sub_strs_ptr sstrs,int sstrs_len,char *new_str){int i;for(i=0;i<sstrs_len;i++)if(!strcmp(*(sstrs+i),new_str)) return 1;return 0;}void display_lcs(int *trace_tab,char* str,int n,int i,int j,char* out,int k,sub_strs_ptr sstrs,int *sstrs_num){if(trace_tab[i*(n+1)+j] == TRACE_END) {if(!is_exited_sstrs(sstrs,*sstrs_num,out)){strcpy(*(sstrs+*sstrs_num),out);(*sstrs_num)++;printf("%d:%s\n",*sstrs_num,out);}return;}if(trace_tab[i*(n+1)+j] == UP_AND_LEFT){out[k--]=str[i-1];//got a chardisplay_lcs(trace_tab,str,n,i-1,j-1,out,k,sstrs,sstrs_num);}else if(trace_tab[i*(n+1)+j] == UP)display_lcs(trace_tab,str,n,i-1,j,out,k,sstrs,sstrs_num);else if(trace_tab[i*(n+1)+j] == LEFT)display_lcs(trace_tab,str,n,i,j-1,out,k,sstrs,sstrs_num);else{//UP OR LEFTdisplay_lcs(trace_tab,str,n,i-1,j,out,k,sstrs,sstrs_num);display_lcs(trace_tab,str,n,i,j-1,out,k,sstrs,sstrs_num);}}int main(){int i,j;int m,n,*lcs_tab,*trace_tab,lcs_len,sstrs_num;char str_a[MAX_LEN],str_b[MAX_LEN],out[MAX_LEN];sub_strs_ptr sstrs;scanf("%s%s",str_a,str_b);m=strlen(str_a);n=strlen(str_b);lcs_tab=(int*)malloc((m+1)*(n+1)*sizeof(int));trace_tab=(int*)malloc((m+1)*(n+1)*sizeof(int));/*store by row*/if(!lcs_tab || !trace_tab) exit(-2);for(i=0;i<=m;i++) { lcs_tab[(n+1)*i]=0;trace_tab[(n+1)*i]=TRACE_END;}for(i=0;i<=n;i++) { lcs_tab[i]=0;trace_tab[i]=TRACE_END;}for(i=1;i<=m;i++)for(j=1;j<=n;j++){if(str_a[i-1] == str_b[j-1]){lcs_tab[i*(n+1)+j]=lcs_tab[(i-1)*(n+1)+(j-1)]+1;trace_tab[i*(n+1)+j]=UP_AND_LEFT;}else{if(lcs_tab[(i-1)*(n+1)+j] == lcs_tab[i*(n+1)+j-1]){lcs_tab[i*(n+1)+j]=lcs_tab[(i-1)*(n+1)+j];trace_tab[i*(n+1)+j]=UP_OR_LEFT;}else if(lcs_tab[(i-1)*(n+1)+j] > lcs_tab[i*(n+1)+j-1]){lcs_tab[i*(n+1)+j]=lcs_tab[(i-1)*(n+1)+j];trace_tab[i*(n+1)+j]=UP;}else{lcs_tab[i*(n+1)+j]=lcs_tab[i*(n+1)+j-1];trace_tab[i*(n+1)+j]=LEFT;}}}printf("lcs_tab:\n");for(i=0;i<=m;i++){for(j=0;j<=n;j++)printf("%-2d",lcs_tab[i*(n+1)+j]);printf("\n");}printf("\ntarce_tab:\n");for(i=0;i<=m;i++){for(j=0;j<=n;j++){switch(trace_tab[i*(n+1)+j]){case TRACE_END:printf("●   ");break;case UP:printf("↑   ");break;case LEFT:printf("←   ");break;case UP_AND_LEFT:printf("↖   ");break;case UP_OR_LEFT:printf("←↑ ");break;}//printf("%-2d",trace_tab[i*(n+1)+j]);}printf("\n");}lcs_len=lcs_tab[m*(n+1)+n];printf("\nlcs's len = %d\n",lcs_len);int min_len=m>n?n:m;sstrs=(char**)malloc(min_len*sizeof(char*));for(i=0;i<min_len;i++)*(sstrs+i)=(char*)malloc(MAX_LEN*sizeof(char));sstrs_num=0;if(lcs_len != 0){out[lcs_len]='\0';display_lcs(trace_tab,str_a,n,m,n,out,lcs_len-1,sstrs,&sstrs_num);}printf("in total %d kinds lcs!\n",sstrs_num);return 0;}


运行结果示意图为:

       

LCS问题就到这里啦~

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 手机上查询详单忘记服务密码怎么办 淘宝上的东西买过就找不到了怎么办 刚刚开的淘宝企业店没有流量怎么办 有图片怎么在淘宝找不到商品怎么办 白色高跟鞋鞋面磨脏了怎么办弄干净 我跟鞋后跟磨烂的脚怎么办? 内衣买回来有一股刺鼻的味道怎么办 裁剪袖子开口偏了1公分怎么办 对于这乱扔垃圾不听劝者该怎么办 感觉被南通蒲公英店铺骗了怎么办 6个月宝宝吃米粉不吃奶怎么办 十个月的宝宝不吃辅食怎么办 5个月宝宝拉肚子有泡沫怎么办 生完孩子后皮肤暗黄怎么办 开服装店批发服装的吊牌怎么办 天虹的鞋一天就坏了怎么办 车被钥匙划了露底漆了怎么办 数控铣z轴回不了参考点怎么办 白色衣服被黑色衣服染了怎么办 夏天出汗衣服粘身上都是毛毛怎么办 支付宝租的手机坏了怎么办 新买的衣服布料扎人怎么办 洗衣服的时候卫生纸沾裤子上怎么办 洗衣服给白衣服染上色了怎么办 不小心喝了游泳池的水怎么办 铁水中硅的含量高了怎么办 视频拍摄单人变双人是怎么办的 四季青进来的货比淘宝还贵怎么办 淘宝还没收货价格买贵了怎么办 在微信上赌博庄跑了怎么办 微信赌博输了10000多怎么办 欠了信用卡说来来家里调查怎么办 没用过的超市购物卡丢了怎么办 体验服抢号成功手机号填错了怎么办 起亚kx3一键启动钥匙没电怎么办 逆战下载的时候显示文件损坏怎么办 移动公司买手机送话费套路怎么办 开通京东白条身份信息被占用怎么办 丰巢快递柜把东西寄丢了怎么办? 圆通快递把我寄的东西弄丢了怎么办 快递把我寄出去的东西弄丢了怎么办