双塔问题实际上就是在两个字符串中寻找最大公共子字符串。
借由双塔问题来具体理解分析一下最大公共子字符串问题。
本文包含以下内容
1.数学模型的建立
2.递推伪代码
3.具体程序
1.数学模型的建立
我们可以想象有两根指针i、j,分别指向数组a,数组b的起始位置。
如果当前两根指针指向的字符是相同的,我们可以把两根指针同时向后移动一位,同时公共子字符串的数目增加1.
如果两根指针指向的字符是不同的,我们可以考虑移动i或者j.
现在定义状态(i,j)表示截止到a[i]、b[j]
d[i][j] 表示 截止到a[i]、b[j]时最大公共子字符串长度,考虑状态转移过程
d[i][j]可能是由三种状态转移得来的,即d[i-1][j-1],d[i-1][j],d[i][j-1]. 根据d[i][j]的含义,我们可得状态转移方程:
if(a[i-1] == b[j-1] ) d[i][j] = d[i-1][j-1]+1;
else d[i][j] = max{d[i-1][j],d[i][j-1]}
2.递推伪代码
一问:我们最终要求的结果是谁
答:d[len1][lenb] len1为a的元素个数,len2位b的元素个数
二问:起始状态有哪些?
答:已知d[0][0] = 0;d[0][0->len2]=0;d[0->len1][0] = 0;
接下来计算
d[1][1],d[1][2],d[1][3]....d[1][len]
d[2][1]...........................d[2][len]
因此i是第一层循环且i:1->len1
j是第二层循环且j:1->len2
综上,递推形式的位代码为:
d[0][0->len2]=0;d[0->len1][0] = 0;
for i:1->len1
do for j:1->len2
if(a[i-1]==b[j-1]) d[i][j] = d[i-1][j-1]+1
else d[i][j] = max{d[i-1][j],d[i][j-1]}
3.具体实现代码
#include<iostream>
using namespace std;
int a[100];
int b[100];
int len1, len2;
int main(){
while (cin >> len1 >> len2)
{
if (len1 == 0)break;
for (int i = 0; i < len1; i++)
cin >> a[i];
for (int j = 0; j < len2; j++)
cin >> b[j];
int d[100][100];
memset(d, 0, sizeof(d));
for (int i = 1; i <= len1; i++)
for (int j = 1; j <= len2; j++){
if (a[i - 1] == b[j - 1]) d[i][j] = d[i - 1][j - 1] + 1;
else{
if (d[i - 1][j]>d[i][j - 1])
d[i][j] = d[i - 1][j];
else
d[i][j] = d[i][j - 1];
}
}
cout << d[len1][len2];
}
return 0;
}