最长公共子序列

来源:互联网 发布:2017年时代网络诗人奖 编辑:程序博客网 时间:2024/06/17 01:36

Description

本题需要用lcs算法来实现字符串匹配。
一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最长公共子序列。

输入有多行,每一行是一个测试用例,最后的结束标志为EOF标志

每个测试用例是由两个字符串组成的,中间用空格隔开(字符串本身不包含任何空白符)

两个字符串的长度len都满足:0 < len < 1000

Output

对于每一个测试用例,输出它的最长公共子序列的长度,每个输出占一行

Sample Input

ABCDEFG ABDHTK
ABCDEFG ABDHTKCD

Sample Output

3
4

题解:

通过本题来理清LCS算法的思路。

最长公共子串(Longest Common Substring)与最长公共子序列(Longest Common Subsequence)的区别: 子串要求在原字符串中是连续的,而子序列则只需保持相对顺序一致,并不要求连续。比如:对于ABAAC、ABDDC而言,他们的最长公共子串为AB,最长公共子序列为ABC。

(1)求解最长公共子串

对于求解最长公共子串而言,最初的算法必然是暴力求解,即采用嵌套循环遍历源字符串,并已所记录的最大子序列长度作为答案。
显示这样的效率不足以通过测评,我们再对题目进行分析。
假设源字符串A,B长度分别为n,m,构造一个大小为n*m的矩阵C,其中C[i] [j] = 1当且仅当A[i]==B[j],C[i] [j] = 0当且仅当A[i]!=B[j].
那么根据题意,显然最长公共子序列的长度为该矩阵中斜对角线方向上连续的1的最大长度。这样的效率也不高,除去嵌套循环以外还需要计算连续的1的最大长度,显然我们可以令C[i][j] =C[i-1][j-1]+1当且仅当A[i]==B[j],这样只需要记录矩阵中最大数字即可。

(2)求解最长公共子序列

假设源字符串A,B长度分别为n,m,构造一个大小为(n+1)(m+1)的矩阵C,其中C[0][] = 0,C[*][0] = 0.
通过动态规划思想可知,存在转移方程:
if (A[i]==B[j]) C[i][j] = C[i-1][j-1] +1;
else C[i][j] = MAX(C[i-1][j],C[i][j-1]);
显然,这样可以求解出最长公共子序列,但是遇到卡时间、空间的时候,我们需要对其进行优化。
在这道题中,我们采用滚动数组+动态规划来AC这道题。

Code:

// Problem#: 20998// Submission#: 5187697// The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License// URI: http://creativecommons.org/licenses/by-nc-sa/3.0/// All Copyright reserved by Informatic Lab of Sun Yat-sen University#include <stdio.h>#include <memory.h>const int MAXN=1000+10;int dp[2][MAXN];char a[MAXN],b[MAXN];int main(){    while(~scanf("%s%s",a+1,b+1)){        int i = 1,j = 1,m=0;        memset(dp,0,sizeof(dp));        for( i=1;a[i];i++){            m^=1;            for(j=1;b[j];j++){                dp[m][j] = dp[m^1][j];                if (dp[m][j-1]>dp[m][j])dp[m][j]=dp[m][j-1];                if (a[i]==b[j]&&dp[m^1][j-1]+1>dp[m][j]) dp[m][j] = dp[m^1][j-1]+1;            }        }        printf("%d\n",dp[m][j-1]);    }    return 0;}
原创粉丝点击