您的位置:首页 > 其它

同一问题的递归与动态规划解法

2016-10-03 14:39 381 查看
问题:

给定一个源串和目标串,能够对串进行入戏操作:

1、在给定的位置上插入一个字符;

2、替换任意字符;

3、删除任意字符;

写一个程序,返回最小的操作数,使得进行这些操作后源串等于目标串,假设源串和目标串的长度都小于2000;

例如:

修改一个字符(如把“a”替换为“b”);

增加一个字符串(如把“abdd”变为“aebdd”);

删除一个字符串(如把“travelling”变为“traveling”);

现在给定源字符串"abcdefg"和目标“abcdef”,那么从源目标转换为目标字符串只需要以此删除操作,所以,最小操作数为1;

解析:

利用递归的方式,我们首先要考虑如何能够将问题从一个大问题转化为一个规模相同的小问题。如果两个字符串A=xabcdae和B=xfdfa,他们的第一个字符相同,则只要计算A[2,...7]=abcdae和B[2,...5]=fdfa的距离就可以了。但如果两个字符不相同,那么就要分别进行讨论,

1、删除A串的第一个字符,然后计算A[2,...lenA】和B[1,...lenB]的距离;

2、删除B串的第一个字符,然后计算A[1,...lenA]和B[2,...lenB]的距离;

3、修改A串的第一个字符为B串的第一个字符,然后计算A[2,...lenA]和B[2,...lenB]的距离;

4、修改B串的第一个字符为A串的第一个字符,然后计算A[2,...lenA]和B[2,...lenB]的距离;

5、增加A串的第一个字符到B串的第一个字符之前,然后计算A[2,...lenA]和B[1,...lenB]的距离;

6、增加B串的第一个字符到A串的第一个字符之前,然后计算A[1,...lenA]和B[2,...lenB]的距离;

我么并不在乎如果当这两个字符串变的相等之后字符串是怎样的。所以,将上面6中情况合并为:

1、一步操作之后,再将A[2,...lenA]和B[1,...,lenB]变成相等字符串;

2、一步操作之后,再将A[2,...lenA]和B[2,...,lenB]变成相等字符串;

3、一步操作之后,再将A[1,...lenA]和B[2,...,lenB]变成相等字符串;

最终得到递归过程代码如下:

#include<iostream>
#include<string>
using namespace std;

int minValue(int t1, int t2, int t3)
{
int temp;
if (t1 >= t2){
temp = t2;
}
else{
temp = t1;
}
if (temp > t3){
temp = t3;
}
return temp;
}
int calculateStringDistance(string strA, int pABegin, int pAEend, string strB, int pBBegin, int pBEnd){
if (pABegin > pAEend){
if (pBBegin>pBEnd)
{
return 0;
}
else{
return pBEnd - pBBegin + 1;
}
}
if (pBBegin > pBEnd){
if (pABegin > pBEnd){
return 0;
}
else{
return pAEend - pABegin + 1;
}
}
if (strA[pABegin] == strB[pBBegin]){
return calculateStringDistance(strA, pABegin + 1, pAEend, strB, pBBegin + 1, pBEnd);
}
else{
int t1 = calculateStringDistance(strA, pABegin, pAEend, strB, pBBegin + 1, pBEnd);
int t2 = calculateStringDistance(strA, pABegin + 1, pAEend, strB, pBBegin, pBEnd);
int t3 = calculateStringDistance(strA, pABegin + 1, pAEend, strB, pBBegin + 1, pBEnd);
return minValue(t1, t2, t3) + 1;
}
}
int main(){

string A = "abcdefg";
string B = "abcdefgh";
cout << calculateStringDistance(A, 0, 6, B, 0, 7) << endl;
return 0;
}根据上面的递归过程,该问题明显符合动态规划的两个因素(最优子结构+重复子问题)使用动态规划的解法,首先给出递推公式:
设f[i,j]表示strA[i,lenA]与strB[j,lenB]的最小距离,则问题描述为:



根据递推公式,我们可以写出dp数组,如下:

我们假设字符数组A=“abcd”,字符数组B=“abcde”,那么:



右下角即为我们要求的最小值。程序如下:

#include<iostream>
#include<string>
using namespace std;
int minValue(int t1, int t2, int t3)
{
int temp;
if (t1 >= t2){
temp = t2;
}
else{
temp = t1;
}
if (temp > t3){
temp = t3;
}
return temp;
}
int calculateStringDistance(string strA, string strB){
int lenA = strA.length()+1;
int lenB =strB.length()+1;
int **dp = new int *[lenA];
for (int i = 0; i < lenA; i++){
dp[i] = new int[lenB];
}
for (int i = 0; i < lenA; i++){
dp[i][0] = i;
}
for (int j = 1; j < lenB; j++){
dp[0][j] = j;
}
for (int i = 1; i < lenA; i++){
for (int j = 1; j < lenB; j++){
if (strA[i] == strB[j]){
dp[i][j] = dp[i - 1][j - 1];
}
else{
dp[i][j] = minValue(dp[i][j - 1], dp[i - 1][j], dp[i - 1][j - 1]) + 1;
}
}
}
int result = dp[lenA-1][lenB-1];
for (int i = 0; i < lenA; i++){
delete[]dp[i];
}
delete[]dp;
return result;
}
int main(){

string A = "abcdefg";
string B = "adefgh";
cout << calculateStringDistance(A,B) << endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: