问题描述:给出两个字符串,求它们最长的公共子字符串。
形如:abcfbc 和 abfcab,其中adb,adcb,abfc都是它们的公共子串,而abcb,abfc是它们的最长公共子串。
¡
¡ 状态选择:
dp[i][j]代表第一个字符串前i个字符组成的字符串与第二个字符串前j个字符组成的字符串的最长公共子串的长度.
状态转移方程:
如果str1[i-1]==str2[j-1],dp[i][j]=dp[i-1] [j-1]+1;
否则dp[i][j]=max{ dp[i-1][j],dp[i] [j-1]}.
初始条件:
dp[0][j]=0,0<=j<=len2;
dp[i][0]=0,0<=i<=len1.
dp[i][j]代表第一个字符串前i个字符组成的字符串与第二个字符串前j个字符组成的字符串的最长公共子串的长度.
状态转移方程:
如果str1[i-1]==str2[j-1],dp[i][j]=dp[i-1] [j-1]+1;
否则dp[i][j]=max{ dp[i-1][j],dp[i] [j-1]}.
初始条件:
dp[0][j]=0,0<=j<=len2;
dp[i][0]=0,0<=i<=len1.
核心代码:
for(i=0;i<=len1;i++) dp[i][0]=0; //初始化条件
for(j=0;j<=len2;j++) dp[0][j]=0; //初始化条件
for(i=1;i<=len1;i++){ //求第一个串的第i个字符与第二个串中的前j个字符的最长公共串
for(j=1;j<=len2;j++)
{
if(str1[i-1]==str2[j-1]) //如果相等就表示该处的值比前一个点处的值多1
dp[i][j]=dp[i-1][j-1]+1;
else //否则是能去同行前一列和前一行同列值中的较大者
{
if(str1[i-1]==str2[j-1]) //如果相等就表示该处的值比前一个点处的值多1
dp[i][j]=dp[i-1][j-1]+1;
else //否则是能去同行前一列和前一行同列值中的较大者
dp[i][j]=dp[i-1][j]>dp[i][j-1]?dp[i-1][j]:dp[i][j-1];
}
}
}
输出:
经过以上的处理,dp[i][j]中已经保存了许多值,如今我们只需要里面的一个最大值即可。
max=0;
for(i=1;i<=lena;i++){ //寻最大数
for(j=1;j<=lenb;j++){
if(dp[i][j]>max)max=dp[i][j];
}
}
for(j=1;j<=lenb;j++){
if(dp[i][j]>max)max=dp[i][j];
}
}
则,max极为所求。
/*
* POJ_1458.cpp
*
* Created on: 2013年12月17日
* Author: Administrator
*/
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 1005;
int dp[maxn][maxn];
int main() {
char str1[maxn], str2[maxn];
while (scanf("%s %s", str1, str2) != EOF) {
memset(dp, 0, sizeof(dp));
int len1 = strlen(str1);
int len2 = strlen(str2);
int i, j;
for (i = 1; i <= len1; ++i) {
for (j = 1; j <= len2; ++j) {
if(str1[i-1] == str2[j-1]){//***这里是需要注意的,因为第i个字符的下标为i-1
dp[i][j] = dp[i-1][j-1] + 1;
}else{
dp[i][j] = max(dp[i-1][j],dp[i][j-1]);
}
}
}
printf("%d\n", dp[len1][len2]);
}
}