一个给定序列的子序列是在该序列中删去若干元素后得到的序列。给定两个序列X和Y,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列。最长公共子序列就是求给定两个序列的一个最长公共子序列。动态规划可以有效的解决此问题。
给定两个序列
X = { x1 , x2 , ... , xm }
Y = { y1 , y2 , ... , yn }
求X和Y的一个最长公共子序列
举例
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]记录序列Xi和Yi的最长公共子序列的长度。
当 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] }
- /**************************************************************
- * File: lcs.cpp
- * Purpose: get the longest common subsequence of two sequences
- * Author: cxf
- * Date: 07/08/2008
- ***************************************************************/
- #include <iostream>
- using namespace std;
- /**************************************
- 根据b记录的子问题的类型,求最长子序列
- /**************************************/
- void lcs(int m, int n, char *x, int **b)
- {
- if (0 == m || 0 == n)
- {
- return;
- }
- if ('//' == b[m][n])
- {
- lcs(m - 1, n - 1, x, b);
- cout << x[m] << endl;
- }
- else if ('|' == b[m][n])
- {
- lcs(m - 1, n, x, b);
- }
- else if ('-' == b[m][n])
- {
- lcs(m, n - 1, x, b);
- }
- }
- /**********************************************
- 求两个序列的最长子序列,x和y的元素需从下标1开始
- m--x的长度
- n--y的长度
- ***********************************************/
- void lcsMain(int m, int n, char *x, char *y, int **c, int **b)
- {
- int i, j;
- /* 初始化长度数组 */
- for (i = 0; i < m; i++)
- {
- for (j = 0; j < n; j++)
- {
- c[i][j] = 0;
- b[i][j] = 0;
- }
- }
- /* 求X和Y各个子序列的最大长度,并记录各个长度是由那个子问题得到的,由b保存
- * x和y中的元素需从下标1开始
- */
- for (i = 1; i < m; i++)
- {
- for (j = 1; j < n; j++)
- {
- if (x[i] == y[j])
- {
- c[i][j] = c[i - 1][j - 1] + 1;
- b[i][j] = '//';
- }
- else if (c[i - 1][j] > c[i][j - 1])
- {
- c[i][j] = c[i - 1][j];
- b[i][j] = '|';
- }
- else
- {
- c[i][j] = c[i][j - 1];
- b[i][j] = '-';
- }
- }
- }
- cout << "最长子序列长度:" << c[i - 1][j - 1] << endl;//打印最长子序列长度
- lcs(m - 1, n - 1, x, b); //求最长子序列
- }
- int main()
- {
- char *x = " bcdefac";
- char *y = " abafdfa";
- int xLen = strlen(x);
- int yLen = strlen(y);
- /* 申请动态二维数组 */
- int **c = new int*[xLen];
- int **b = new int*[xLen];
- for (int i = 0; i < xLen; i++)
- {
- c[i] = new int[yLen];
- b[i] = new int[yLen];
- }
- lcsMain(xLen, yLen, x, y, c, b);
- /* 释放内存 */
- for (i = 0; i < xLen; i++)
- {
- delete[] c[i];
- delete[] b[i];
- }
- delete[] c;
- delete[] b;
- return 0;
- }
最长公共子序列算法
本文介绍如何使用动态规划解决最长公共子序列问题,通过实例详细解释了算法的实现过程,并提供了一段C++代码示例。
9808

被折叠的 条评论
为什么被折叠?



