1. 问题描述:
给定两个字符串(或者是数字序列)A和B,求一个字符串,使得这个字符串是A和B的最长公共部分(子序列可以不连续),例如字符串"sadstory","adminsorry"的最长公共子序列是"adsory",长度为6
2. 思路分析:
① 首先是可以使用暴力破解的,但是在写暴力破解的时候感觉很麻烦,主要是子序列不要求连续导致起点与终点是比较难确定的
② 比较推荐的方法是采用的是动态规划的思想来进行解决的,令dp[i][j]的含义是字符串A的第i个位置与字符串B的第j个位置之前的LCS长度(下标是从1开始的),根据A[i]与B[j]的情况可以分为两种:
1)当A[i]==B[j]时,例如在上面的例子中dp[4][6]表示"sads"与"admins"的LCS长度,比较A[4]与B[6]发现两者都是's'所以dp[4][6]就等于了dp[3][5]的基础上加1,即3
2)当A[i]!=B[j]时,则字符串A的i号位于字符串B的j号位之前的LCS无法延长,因此dp[i][j]或继承dp[i - 1][j]与dp[i][j - 1]的最大值,例如在上面的例子中,dp[3][3]表示"sad"与"adm"的LCS长度,我们比较A[3]与B[3]发现'd'不等于'm'这样dp[3][3]无法在原来的基础上延长,因此继承自"sa"与"adm"的LCS长度与"sad"与"ad"的LCS中的较大值,即"sad"与"ad"的LCS长度是2
3. 下面是具体的代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int n = 100;
char A[n], B[n];
int dp[n][n];
int main(void){
int n;
//从下表为1开始读入
gets(A + 1);
gets(B + 1);
int lenA = strlen(A + 1);
int lenB = strlen(B + 1);
//边界
for(int i = 0; i <= lenA; ++i){
dp[i][0] = 0;
}
for(int j = 0; j <= lenB; ++j){
dp[0][j] = 0;
}
//状态转移方程
for(int i = 1; i <= lenA; ++i){
for(int j = 0; j <= lenB; ++j){
if(A[i] == B[j]){
dp[i][j] = dp[i - 1][j - 1] + 1;
}else{
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
printf("%d", dp[lenA][lenB]);
return 0;
}