动态规划——最长公共子序列
Posted 牧空
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态规划——最长公共子序列相关的知识,希望对你有一定的参考价值。
问题
在字符串S中按照先后顺序依次取出若干字符(不必连续),并将他们排列成一个新的字符串,这个字符串称为原字符串的子串。现在给定两个字符串S1和S2,求一个最长公共子串和其长度。
分析
- 最基础的方法就是枚举所有子序列,然后逐一判断子序列是否相同,时间复杂度 O ( n n + m ) O(n^{n+m}) O(nn+m)
- 使用动态规划可将时间复杂度降为
O
(
n
m
)
O(nm)
O(nm)
- 设置二维数组
dp[][]
,令dp[i][j]
表示以S1[i]
作为结尾和以S2[j]
为结尾的最长子序列的长度,最长为dp[n][m]
- 当
S1[i]=S2[j]
,此时必定存在一个最长公共子序列以这个字符为结尾,其他部分等价于S1
中前i-1
个字符和S2
中前j-1
个字符中的最长公共子串,也就是dp[i][j]=dp[i-1][j-1]+1
- 当
S1[i]!=S2[j]
,则此时最长公共子串为S1
中前i-1
个字符和S2
中前j-1
个字符中的较大的最长公共子串,即dp[i][j]=max{dp[i-1][j],dp[i][j-1]}
- 对于边界条件,如果两个字符串中有一个为空串,那么公共字符串的长度必然为0,即
dp[i][0]=dp[0][j]=0
- 设置二维数组
例题
描述
寻找两个字符出的最长子串
输入描述:
输入的两行字符串有小写英文字母构成,且最大长度不会超过100
输出描述:
对于每个例子输出k表示最长公共子串的长度
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#define MAXN 101
using namespace std;
int dp[MAXN][MAXN];
string s1, s2;
int LCS(){
int n = s1.size(), m = s2.size();
memset(dp, 0, sizeof(dp));
// 这里的i,j在dp中表示的所取得子串长度(或者说是所在字符串的第几个字符)
// 在字符串中要与dp相对应就要-1
for (int i = 1; i <= n; i++){
for (int j = 1; j <= m; j++){
// 上述的两个状态转换
if (s1[i - 1] == s2[j - 1])
dp[i][j] = dp[i - 1][j - 1] + 1;
else
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
}
}
return dp[n][m];
}
int main(int argc, char const *argv[])
{
while (cin >> s1 >> s2){
int k = 0;
k = LCS();
printf("%d\\n", k);
}
return 0;
}
以上是关于动态规划——最长公共子序列的主要内容,如果未能解决你的问题,请参考以下文章