动态规划 -- 最长公共子序列

来源:互联网 发布:网络主播排行榜2017 编辑:程序博客网 时间:2024/06/06 09:29
动态规划之最长公共子序列

参考资料

1 算法导论
2 v_JULY_v
何海涛

最长公共子序列(Longest Common Subsequence)

给定两个序列 X 和 Y ,称序列 Z 是 X 和 Y 的公共子序列,如果 Z 即是 X 的一个子序列又是 Y 的一个子序列, 该公共子序列不要求是连续的,只是要求Z的元素在X和Y中是以相同的顺序出现。例如,如果 X = { A , B , C , B , D , A , B } ,Y = { B , D , C , A , B , A } ,则序列 { B , C , B , A } 即为 X 和 Y 的一个公共子序列。序列 { B , C, A } 不是 X 和 Y 的一个最长公共子序列,因为长度只是3 ,不是最长的。

递归解

在找X= ( x1,⋯,xm )和 Y = ( y1,⋯,yn ) 的一个 LCS时,需要检查一个或两个子问题。如果 xm = yn,必须找出 xm-1 和 yn-1的一个LCS。将 xm = yn 添加到这个 LCS上,可以产生 X 和 Y 的一个 LCS 。如果 xm != yn ,就必须解决两个子问题,找出xm-1和Y 的一个LCS,以及找出 X 和 yn-1 的一个LCS 。这两个LCS中,较长的就是 X和 Y 的一个 LCS 。

所以 LCS的递归式如下:


计算 LCS 的长度


LCS-LENGTH ( X , Y)     m  ← length[ X ]     n   ← length[ Y ]    for  i ← 1 to mdo c[i,0] ← 0    for  j ← 0 to n do  c[0,j] ← 0    for i ← 1 to mdo  for  j ← 1 to ndo if  xi = yjthen c[i,j]  ← c[i-1,j-1] +1 b[i,j] ← “ \”else if c[i-1,j] > c[i,j-1]    then  c[i,j] ← c[i-1,j]      b[i,j] ← " |"else c[i,j] ← c[i,j-1]b[i,j] ← “---”   return c and b

构造一个LCS 

  1.    
PRINT-LCS(b,X,i,j)   if i=0 or j=0 then return;    if b[i,j]="\" then LCS(b,X,i-1,j-1);              print(x[i]);    else if b[i,j]="|"            then LCS(b,X,i-1,j)     else LCS(b,X,i,j-1); 

代码实现

#include "string.h"// directions of LCS generationenum decreaseDir {kInit = 0, kLeft, kUp, kLeftUp};/////////////////////////////////////////////////////////////////////////////// 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++)      {         delete [] LCS_length[i];        delete [] LCS_direction[i];     }             return LCS_length[length1 - 1][length2 - 1];}/////////////////////////////////////////////////////////////////////////////// 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);      }}

原创粉丝点击