最长公共子序列实现

最长公共子序列算法
本文介绍如何使用动态规划解决最长公共子序列问题,通过实例详细解释了算法的实现过程,并提供了一段C++代码示例。

一个给定序列的子序列是在该序列中删去若干元素后得到的序列。给定两个序列XY,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序列XY的公共子序列。最长公共子序列就是求给定两个序列的一个最长公共子序列。动态规划可以有效的解决此问题。

给定两个序列
X = { x1 , x2 , ... , xm }
Y = { y1 , y2 , ... , yn }
XY的一个最长公共子序列

举例
X = { a , b , c , b , d , a , b }
Y = { b , d , c , a , b , a }
最长公共子序列为
LSC = { b , c , b , a }

分析:

最长公共子序列问题具有最优子结构性质

X = { x1 , ... , xm }
Y = { y1 , ... , yn }
及它们的最长子序列
Z = { z1 , ... , zk }

1、若 xm = yn   zk = xm = yn,且Z[k-1]  X[m-1]  Y[n-1] 的最长公共子序列
2
、若 xm != yn ,且 zk != xm ,  Z  X[m-1]  Y 的最长公共子序列
3
、若 xm != yn ,  zk != yn ,  Z  Y[n-1]  X 的最长公共子序列

由最长公共子序列问题的子序列的最优子结构性质,可以建立子问题最优的递归关系。用c[i][j]记录序列XiYi的最长公共子序列的长度。

 i = 0 , j = 0  , c[i][j] = 0
 i , j > 0 ; xi = yi 
 , c[i][j] = c[i-1][j-1] + 1
 i , j > 0 ; xi != yi  , c[i][j] = max { c[i][j-1] , c[i-1][j] }

 

 

  1. /**************************************************************
  2.  * File: lcs.cpp
  3.  * Purpose: get the longest common subsequence of two sequences
  4.  * Author: cxf
  5.  * Date: 07/08/2008
  6.  ***************************************************************/
  7. #include <iostream>
  8. using namespace std;
  9. /**************************************
  10.  根据b记录的子问题的类型,求最长子序列                                            
  11. /**************************************/
  12. void lcs(int m, int n, char *x, int **b)
  13. {
  14.     if (0 == m || 0 == n)
  15.     {
  16.         return;
  17.     }
  18.     if ('//' == b[m][n])
  19.     {
  20.         lcs(m - 1, n - 1, x, b);
  21.         cout << x[m] << endl;
  22.     }
  23.     else if ('|' == b[m][n])
  24.     {
  25.         lcs(m - 1, n, x, b);
  26.     }
  27.     else if ('-' == b[m][n])
  28.     {
  29.         lcs(m, n - 1, x, b);
  30.     }
  31. }
  32. /**********************************************
  33.  求两个序列的最长子序列,x和y的元素需从下标1开始
  34.  m--x的长度
  35.  n--y的长度
  36. ***********************************************/
  37. void lcsMain(int m, int n, char *x, char *y, int **c, int **b)
  38. {
  39.     int i, j;
  40.     /* 初始化长度数组 */
  41.     for (i = 0; i < m; i++)
  42.     {
  43.         for (j = 0; j < n; j++)
  44.         {
  45.             c[i][j] = 0;
  46.             b[i][j] = 0;
  47.         }
  48.     }
  49.     /* 求X和Y各个子序列的最大长度,并记录各个长度是由那个子问题得到的,由b保存
  50.      * x和y中的元素需从下标1开始
  51.      */
  52.     for (i = 1; i < m; i++)
  53.     {
  54.         for (j = 1; j < n; j++)
  55.         {
  56.             if (x[i] == y[j])
  57.             {
  58.                 c[i][j] = c[i - 1][j - 1] + 1;
  59.                 b[i][j] = '//';
  60.             }
  61.             else if (c[i - 1][j] > c[i][j - 1])
  62.             {
  63.                 c[i][j] = c[i - 1][j];
  64.                 b[i][j] = '|'
  65.             }
  66.             else
  67.             {
  68.                 c[i][j] = c[i][j - 1];
  69.                 b[i][j] = '-'
  70.             }
  71.         }
  72.     }   
  73.     cout << "最长子序列长度:" << c[i - 1][j - 1] << endl;//打印最长子序列长度
  74.     lcs(m - 1, n - 1, x, b);    //求最长子序列
  75. }
  76. int main()
  77. {
  78.     char *x = " bcdefac";
  79.     char *y = " abafdfa";
  80.     int xLen = strlen(x);
  81.     int yLen = strlen(y);
  82.     /* 申请动态二维数组 */
  83.     int **c = new int*[xLen];
  84.     int **b = new int*[xLen];
  85.     for (int i = 0; i < xLen; i++)
  86.     {
  87.         c[i] = new int[yLen];
  88.         b[i] = new int[yLen];
  89.     }
  90.     lcsMain(xLen, yLen, x, y, c, b);
  91.     /* 释放内存 */
  92.     for (i = 0; i < xLen; i++)
  93.     {
  94.         delete[] c[i];
  95.         delete[] b[i];
  96.     }
  97.     delete[] c;
  98.     delete[] b;
  99.     return 0;
  100. }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值