Coincidence (九度教程第98题) 最长公共子序列(LCS) 动态规划

Find a longest common subsequence of two strings.
输入描述:
First and second line of each input case contain two strings of lowercase character a…z. There are no spaces before, inside or after the strings. Lengths of strings do not exceed 100.
输出描述:
For each case, output k – the length of a longest common subsequence in one line.
示例1
输入
abcd
cxbydz
输出
2

题目大意:
求出两个字符串的最长公共子串长度,典型的最长公共子序列问题。
解题思路:动态规划

与求最长递增子序列一样,我们首先将原问题分割成一些子问题,我们用
dp[ i ][ j ]表示 S1 中前 i 个字符与 S2 中前 j 个字符分别组成的两个前缀字符串的最
长公共子串长度
。显然的,当 i、j 较小时我们可以直接得出答案,如 dp[ 0 ][ j ]必
等于 0。那么,假设我们已经求得 dp[ i ][ j ](0<=i<x || 0<=j<y)的所有值,考虑如何由
这些值继而推得 dp[x][y],求得 S1 前 x 个字符组成的前缀子串和 S2 前 y 个字符
组成的前缀子串的最长公共子序列长度。
若 S1[x] = =S2[y],即 S1 中的第 x 个字符和 S2 中的第 y 个字符相同,同时由于他们都是各自前缀子串的最后一个字符,那么必存在一个最长公共子串以 S1[x]或 S2[y]结尾,其它部分等价于 S1 中前 x-1个字符和S2中前y-1个字符的最长公共子串。所以这个子串的长度比dp[x-1][y-1]又增加 1,即 dp[x][y] = dp[x-1][y-1] + 1。
相反的,若 S1[x] != S2[y],此时其最长公共子串长度为 S1 中前 x-1 个字符和 S2 中前 y 个字符的最长公共子串长度与S1 中前 x 个字符和 S2 中前 y-1 个字符的最长公共子串长度的较大者,即在两种情况下得到的最长公共子串都不会因为其中一个字符串又增加了一个字符长度发生改变。综上所述,dp[x][y] = max{dp[x-1][y],dp[x][y-1]}。

综上所述,最长公共子序列问题的递推条件:

//字符串s1长度为n, 字符串s2长度为m
//dp[i][j]表示s1中前i个字符与s2中前j个字符分别组成的两个前缀字符串的最长公共子串长度
//dp[0][j]=0    0<=j<=m
//dp[i][0]=0    0<=i<=n
//dp[n][m]中保存的值即为两个原始字符串的最长公共子序列长度
if(s1[i]==s2[j]){ dp[i][j] = dp[i-1][j-1] + 1;}
else dp[i][j] = max(dp[i-1][j], dp[i][j-1]);

AC代码

//最长公共子序列问题
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
 
int dp[101][101];
char s1[101], s2[101];
int main() {
    cin >> s1;
    cin >> s2;
    int a = strlen(s1);
    int b = strlen(s2);
    for (int i = 0; i <= a; i++) { dp[i][0] = 0; }
    for (int i = 0; i <= b; i++) { dp[0][i] = 0; }
    for (int i = 1; i <= a; i++) {
        for (int j = 1; j <= b; j++) {
            if (s1[i-1] == s2[j-1]) dp[i][j] = dp[i - 1][j - 1] + 1;
            else dp[i][j] = max( dp[i][j - 1], dp[i - 1][j] );
        }
    }
    cout << dp[a][b] << endl;
    //system("pause");
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值