LCS最长公共子序列

来源:互联网 发布:类似蝰蛇音效的软件 编辑:程序博客网 时间:2024/05/21 10:42
    Procedure LCS_LENGTH(X,Y);      begin        m:=length[X];        n:=length[Y];        for i:=1 to m do c[i,0]:=0;        for j:=1 to n do c[0,j]:=0;        for i:=1 to m do          for j:=1 to n do            if x[i]=y[j] then              begin                c[i,j]:=c[i-1,j-1]+1;                b[i,j]:="↖";              end            else if c[i-1,j]≥c[i,j-1] then              begin                c[i,j]:=c[i-1,j];                b[i,j]:="↑";              end            else              begin                c[i,j]:=c[i,j-1];                b[i,j]:="←"              end;        return(c,b);      end;  


图解

求LCS长度和LCS

[cpp] view plain copy    #include <iostream>      #include <cstring>      using namespace std;            int length_LCS(string s1,string s2,int **c,int **b,int m,int n)  //输出LCS的长度      {          /*处理特殊的0行和0列*/          for(int i=0;i<=m;i++)              c[i][0]=0;          for(int j=0;j<=n;j++)              c[0][j]=0;                /*处理其他行和列*/          for(int i=1;i<=m;i++)          {               for(int j=1;j<=n;j++)               {                   if(s1[i-1]==s2[j-1])                   {                       c[i][j]=c[i-1][j-1]+1;                       b[i-1][j-1]=0;                   }                   else                   {                       if(c[i-1][j]>=c[i][j-1])                       {                           c[i][j]=c[i-1][j];                           b[i-1][j-1]=1;                       }                       else                       {                           c[i][j]=c[i][j-1];                           b[i-1][j-1]=-1;                       }                   }               }          }          return c[m][n];      }            void Print_LCS(int **b,string x,int i,int j) //输出LCS序列      {          if(i==0||j==0)              return ;          if(b[i-1][j-1]==0)          {              Print_LCS(b,x,i-1,j-1);              cout<<x[i-1];          }          else if(b[i-1][j-1]==1)          {              Print_LCS(b,x,i-1,j);          }          else              Print_LCS(b,x,i,j-1);      }            int main()      {          string s1,s2;          cout<<"请输入两个序列:"<<endl;          cin>>s1>>s2;          int m=s1.length(),n=s2.length();          int **c=new int*[m+1]; //动态分配二维数组          for(int i=0;i<=m;i++)              c[i]=new int[n+1];          int **b=new int*[m]; //动态分配二维数组          for(int j=0;j<m;j++)              b[j]=new int[n];          cout<<"LCS的长度:"<<length_LCS(s1,s2,c,b,m,n)<<endl;          cout<<"打印其中的一个LCS:";          Print_LCS(b,s1,m,n);          //此处最好的处理是释放空间          cout<<endl;          return 0;      }  
优化空间
事实上,数组元素c[i,j]的值仅由c[i-1,j-1],c[i-1,j]和c[i,j-1],所以只需要dp[2][n]的空间就行,利用滚动数组

if(s1[i] == s2[j])  dp[(i+1)%2][j+1] = dp[i%2][j]+1;
else dp[(i+1)%2][j+1] = max(dp[(i+1)%2][j], dp[i%2][j+1]);
结果为
dp[n%2][n]
优化时间

转化为最长递增子序列问题,O( n*log(n) )

注意到num[i][j]仅在A[i]==B[j]处才增加,对于不相等的地方对最终值是没有影响的。故而枚举相等点处可以对上述动态规划算法进行优化。

举例说明:

A:abdba

B:dbaaba

则1:先顺序扫描A串,取其在B串的所有位置:

    2:a(2,3,5) b(1,4) d(0)。

    3:用每个字母的反序列替换,则最终的最长严格递增子序列的长度即为解。

 替换结果:532 41 0 41 532

 最大长度为3.

    #include <stdio.h>      #include <ctype.h>      #include <string.h>      #include <iostream>      #include <string>      #include <math.h>      #include <vector>      #include <queue>      #include <algorithm>           using namespace std;           const int maxn = 1501 ;      vector<int> location[26] ;      int c[maxn*maxn] , d[maxn*maxn] ;           inline int get_max(int a,int b) {   return a > b ? a : b ;  }           //nlogn 求lcs      int lcs(char a[],char b[])      {          int i , j , k , w , ans , l , r , mid ;          for( i = 0 ; i < 26 ; i++) location[i].clear() ;          for( i = strlen(b)-1 ; i >= 0 ; i--) location[b[i]-'a'].push_back(i) ;          for( i = k = 0 ; a[i] ; i++)          {              for( j = 0 ; j < location[w=a[i]-'a'].size() ; j++,k++) c[k] = location[w][j] ;          }          d[1] = c[0] ;   d[0] = -1 ;          for( i = ans = 1 ; i < k ; i++)          {              l = 0 ; r = ans ;              while( l <= r )              {                  mid = ( l + r ) >> 1 ;                  if( d[mid] >= c[i] ) r = mid - 1 ;                  else l = mid + 1 ;              }              if( r == ans ) ans++,d[r+1] = c[i] ;              else if( d[r+1] > c[i] ) d[r+1] = c[i] ;          }          return ans ;      }           int main()      {          char a[maxn] , b[maxn] ;          while (~scanf("%s%s",a,b))          {              printf("%d\n",lcs(a,b));          }      } 


原创粉丝点击