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

前言:学习过的知识,只要不经常使用就会忘记,所以在此写博客,记录下来,方便自己,也可能有利于他人。


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

   1.什么是最长公共子序列?

       最长公共子序列,英文缩写为LCS(Longest Common Subsequence)。其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最长公共子序列。

    注:最长公共子序列和最长公共子串的区别:前者(公共子序列)不必连续,后者(字串)必须是连续的

    如:abccfg与adcf:最长公共子序列为:acf,而最长公共字串为:cf。(一目了然了吧)。

   2.解决方法

     1).求LCS肯能最先想到的就是穷举法,如X和Y两个序列,通过穷举X的每个子序列,看是否在Y中,并选择最长的序列即为最后结果,但是此方法的时间复杂度较大,一般不用此方法。

    如X的一个子序列相对应下标为{1,2,3.....n},那么X共有2^n个子序列(注意包含空序列),Y也同理为2^m个,所以其时间复杂度为O(2^n*2^m)。

     2).动态规划法求解

      关于此方法的详细解答http://blog.csdn.net/v_JULY_v/article/details/6695482已经给出了超详细的描述。此处根据下述思想写出代码。(原文中没有打印出所有的最长公共子序列,此处稍作修改,打印出所有子序列)

 最长公共子序列的结构有如下表示:

    设序列X=<x1, x2, …, xm>和Y=<y1, y2, …, yn>的一个最长公共子序列Z=<z1, z2, …, zk>,则:

  1. 若xm=yn,则zk=xm=yn且Zk-1是Xm-1和Yn-1的最长公共子序列;
  2. 若xm≠yn且zk≠xm ,则Z是Xm-1和Y的最长公共子序列;
  3. 若xm≠yn且zk≠yn ,则Z是X和Yn-1的最长公共子序列。

    其中Xm-1=<x1, x2, …, xm-1>,Yn-1=<y1, y2, …, yn-1>,Zk-1=<z1, z2, …, zk-1>。

  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. #define  x 100             //串的最大长度  
  5. #define  y 100  
  6. char result[x];           //保存序列的结果  
  7. int count=0;             //记录LCS的个数  
  8.   
  9. /*功能:返回最长序列的长度 
  10.     x:字串串x 
  11.     y:字符串y 
  12.     b:标志数组 
  13.     xlen:字符串x的长度 
  14.     ylen:字符串y的长度 
  15. */  
  16.   
  17. int Lcs_length(string x_s,string y_s,int b[][y+1],int xlen,int ylen)  
  18. {  
  19.     int i=0,j=0;  
  20.         int c[x+1][y+1];  
  21.   
  22.     for(i=0;i<=xlen;i++)  
  23.         c[i][0]=0;  
  24.     for(i=0;i<=ylen;i++)  
  25.         c[0][i]=0;  
  26.         // 下面根据上述最长公共子序列结构写出代码。  
  27.     for(i=1;i<=xlen;i++)  
  28.     {  
  29.         for(j=1;j<=ylen;j++)  
  30.         {  
  31.             if(x_s[i-1]==y_s[j-1])  
  32.             {  
  33.                 c[i][j]=c[i-1][j-1]+1;  
  34.                 b[i][j]=1;          //在b数组中进行标志,便于后面打印。  
  35.             }  
  36.             else if(c[i-1][j]>c[i][j-1])  
  37.             {  
  38.                                c[i][j]=c[i-1][j];  
  39.                 b[i][j]=2;  
  40.             }  
  41.             else if(c[i-1][j]<c[i][j-1])  
  42.             {  
  43.                 c[i][j]=c[i][j-1];  
  44.                 b[i][j]=3;  
  45.             }  
  46.             else  
  47.             {  
  48.                 c[i][j]=c[i][j-1];  
  49.                 b[i][j]=4;  
  50.             }  
  51.         }  
  52.     }  
  53.     return c[xlen][ylen];  
  54. }  
  55.   
  56. /*功能:打印出LCS 
  57.         i:字符串x的长度 
  58.         j:字符串y的长度 
  59.         x:字符串x 
  60.         b:标志数组 
  61.         current_len:当前子序列长度 
  62.         lcs_max_len:最长公共子序列长度 
  63. */  
  64. void Display_LCS(int i,int j,string x_s,int b[][y+1],int current_len,int lcs_max_len)  
  65. {  
  66.     if(i==0||j==0)  
  67.     {  
  68.         for(int k=0;k<lcs_max_len;k++)  
  69.         {  
  70.             cout<<result[k];  
  71.         }  
  72.         cout<<endl;  
  73.         count++;  
  74.         return;  
  75.     }  
  76.     if(b[i][j]==1)  
  77.     {  
  78.         current_len--;  //Xm=Yn的情况,就将子序列长度减1,并保存一个元素。  
  79.         result[current_len]=x_s[i-1];  
  80.         Display_LCS(i-1,j-1,x_s,b,current_len,lcs_max_len);  
  81.     }  
  82.     else if(b[i][j]==2)    //Xm!=Zm的情况,(具体参考上述链接博文有详细说明)  
  83.         Display_LCS(i-1,j,x_s,b,current_len,lcs_max_len);  
  84.     else if(b[i][j]==3)    //Yn!=Zm的情况  
  85.         Display_LCS(i,j-1,x_s,b,current_len,lcs_max_len);  
  86.     else       //相等的情况c[i-1][j]==c[i][j-1]  
  87.     {  
  88.         Display_LCS(i-1,j,x_s,b,current_len,lcs_max_len);  
  89.         Display_LCS(i,j-1,x_s,b,current_len,lcs_max_len);  
  90.     }  
  91. }  
  92. int main()  
  93. {  
  94.     string test1 = "ABCBDAB";  
  95.     string test2 = "BDCABA";  
  96.     int xlen = test1.length();  
  97.     int ylen = test2.length();  
  98.       
  99.     int b[x+ 1][y+1];  
  100.       
  101.     int lcs_max_len = Lcs_length( test1,test2,b,xlen,ylen);  
  102.       
  103.     Display_LCS( xlen, ylen, test1, b, lcs_max_len, lcs_max_len );  
  104.     cout << "最长公共子序列共有: "<< count <<"种"<<endl;  
  105.       
  106.       
  107.      return 0;  
  108. }
运行结果如下:

                      

再次推荐此博客http://blog.csdn.net/v_JULY_v/article/details/6695482

cdx   2014.4.25   20:25 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值