最长公共子序列问题详解(LCS)

最长公共子序列问题 (LCS)

​ 给定两个字符串 S (n) 和 T (m) ,求出两个字符串的最长公共子序列的长度

! \color{Red}! 限制条件

1 <= n, m <= 1000

子序列

​ 字符串S的子序列,是一组按从左到右顺序出现的字符,但不一定是连续的

例如 ,我们有一字符串
A C T T G C G \color{gray}ACTTGCG ACTTGCG

  • ACT ATTCT 这些都是此字符串的子序列
  • TTA 不是此字符串的子序列

公共子序列

例如,我们有字符串 S1S2
S 1 = A A A C C G T G A G T T A T T C G T T C T A G A A \color{gray}S1 =AAACCGT GAGT T AT T CGT T CT AGAA S1=AAACCGTGAGTTATTCGTTCTAGAA

S 2 = C A C C C C T A A G G T A C C T T T G G T T C \color{gray}S2 = CACCCCT AAGGT ACCT T T GGT T C S2=CACCCCTAAGGTACCTTTGGTTC

那么对于 S1S2来说,它们的 LCS 就是:
S 1 = A A A C C G T G A G T T A T T C G T T C T A G A A \color{gray}S1 =\color{gray}AA\color{Red}{ACC}\color{gray}G\color{Red}T\color{gray}G\color{Red}AG\color{gray}T\color{Red} T A\color{gray}T T \color{Red}C\color{gray}G\color{Red}T T \color{gray}C\color{Red}T \color{gray}A\color{Red}G\color{gray}AA S1=AAACCGTGAGTTATTCGTTCTAGAA

S 2 = C A C C C C T A A G G T A C C T T T G G T T C \color{gray}S2 = C\color{Red}A\color{gray}CC\color{Red}CCT A\color{gray}AG\color{Red}GT AC\color{gray}C\color{Red}T T T G\color{gray}GT T C S2=CACCCCTAAGGTACCTTTGGTTC

L C S = A C C T A G T A C T T T G \color{gray}LCS = \color{Red}ACCTAGTACTTTG LCS=ACCTAGTACTTTG

算法分析 \color{Turquoise}算法分析 算法分析

​ 我们的目的是要找出 字符串 X = < x1,x2,···,xm> 和 Y = < y1 , y2,···,yn > 最长公共子序列

假设 Z = < z1, z2,···,zk > 是 它们的最长公共子序列

  1. x m = y n x_m = y_n xm=yn

    • 此时 z k = x m = y n zk = xm = yn zk=xm=yn,我们有 Z k − 1 Z_{k-1} Zk1 X m − 1 与 Y n − 1 X_{m-1} 与 Y_{n-1 } Xm1Yn1的 LCS
  2. x m ! = y n x_m ! = y_n xm!=yn

    • z k ! = x m z_k ! = x_m zk!=xm ,说明 Z k Z_k Zk X m − 1 与 Y n X_{m-1} 与 Y_{n} Xm1Yn的 LCS
    • z k ! = y n z_k ! = y_n zk!=yn ,说明 Z k Z_k Zk X m 与 Y n − 1 X_{m} 与 Y_{n-1 } XmYn1的 LCS

因此,求解LCS的问题则变成递归求解两个子问题。由于在过程中,重复的子问题多,效率低下。故此我们可以采用记忆化搜索 - 空间换时间,用数组保存中间状态,方便以后的计算。这是动态规划(DP)的核心思想

DP 求解 LCS

用二维数组 f [ i ] [ j ] f[ i ] [ j ] f[i][j] 记录字符串 x 1 , x 2 , ⋅ ⋅ ⋅ , x i x1,x2,···,xi x1x2⋅⋅⋅xi y 1 , y 2 , ⋅ ⋅ ⋅ , y j y1 , y2,···,yj y1y2⋅⋅⋅yj 的LCS 长度,则可以得到状态转移方程:
在这里插入图片描述

代码实现

const int N = 1010;

int n, m; // 串 S ,T 的长度
char S[N], T[N];
int f[N][N];

void solve()
{
    for(int i = 1; i <= n; i ++ )
    {
        for(int j = 1; j <= m; j ++ )
        	if(s[i] == T[j])
                f[i][j] = f[i - 1][j - 1] + 1;
        	else
                f[i][j] = max(f[i][j - 1], f[i - 1][j]);
        
    }
    
    printf("%d\n", f[n][m]);
    
}

以上内容尚未完全,随着今后学习的推进,我会继续对其进行补充与完善。

参考资料

[1] cs2035, Longest Common Subsequence.

[2] 最长公共子序列与最长公共子串

[3] GeeksforGeeks, Dynamic Programming | Set 29 (Longest Common Substring).

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值