首页 > 编程笔记 > C++笔记 阅读:3

最长公共子序列(C++实现)

序列的子序列指序列中的一些元素被省略。给定一个序列 x=<x1,x2,…,xm> 及另一个序列 z=<z1,z2,…,zk>,若 x 的索引存在严格递增的序列 <i1,i2,…,ik>,则对于 j=1,2,…,k 及 xij=zj,z 都是 x 的子序列。

例如,z=<a,b,f,c> 的索引序列是 <1,2,4,6>,它是 x=<a,b,c,f,b,c> 的子序列。若 z 既是 x 的子序列,也是 y 的子序列,则称 z 是 x 和 y 的公共子序列。

给定两个序列 x 和 y,求 x 和 y 的最长公共子序列的长度。

算法设计

本题为最长公共子序列问题:
1) xi=yj:求解 Xi-1 和 Yj-1 的最长公共子序列的长度加 1,dp[i][j]=dp[i-1][j-1]+1。


2) xi≠yj:可以把 xi 去掉,求解 Xi-1 和 Yj 的最长公共子序列的长度,或者把 yj 去掉,求解 Xi 和 Yj-1 的最长公共子序列的长度,取二者的最大值,dp[i][j]=max(dp[i][j-1],dp[i-1][j])。

算法实现

#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;

#define maxn 100

//最长公共子序列,时间复杂度为O(nm)
int dp[maxn][maxn]; //dp[i][j]表示s1[1..i]和s2[1..j]的最长公共子序列的长度
int main() {
    char s1[100],s2[100];
    while(~scanf("%s%s",s1,s2)) {
        int len1=strlen(s1);
        int len2=strlen(s2);
        for(int i=0;i<=len1;i++) dp[i][0]=0;
        for(int j=0;j<=len2;j++) dp[0][j]=0;
        for(int i=1;i<=len1;i++)
            for(int j=1;j<=len2;j++) {
                for(int k=1;k<=len2;k++) {
                    if(s1[i-1]==s2[j-1]) //字符串的下标实际上从0开始
                        dp[i][j]=dp[i-1][j-1]+1;
                    else
                        dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
                }
        }
        printf("%d\n",dp[len1][len2]);
    }
    return 0;
}
运行结果为:

abcfbc abfcab
4

以上算法的时间复杂度和空间复杂度均为 O(nm),n、m 分别为两个字符串的长度。

相关文章