问题:给字符串A,字符串B。有三种操作:1,在字符串的前端或后端加上一个字符2,删掉前端或后端一个字符,改变字符串中间一个字符。求将一个A的子串变成B最少的操作数。
我们要求A一个子串,和B的子串有着最大匹配
说一下最大匹配:这个可能是和B的子串相同,也有可能是和B的子串在中间有几个位置不同其他都相同。
我们再用B的长度减去最大匹配中相同的字符个数,得到答案。
我见了两种解法。都写写吧。
暴力
借鉴大佬博客 Orz
两遍暴力,每次二重循环求一个串对另一个串的匹配
A:abc
B:bd
匹配过程:
a-b,b-d
b-b,c-d
c-b
(如果还不太清楚就去看看上面的博客)
#include<bits/stdc++.h>
using namespace std;
char A[2010], B[2010];
int dp[2010][2010];
int main() {
int ans = 0, idx = 0, lena, lenb, u = 0, v = 0;
A[0] = B[0] = 1;
scanf("%s%s", &A[1], &B[1]);
lena = strlen(A), lenb = strlen(B);
for(int i=1; i<lena; i++) {
u = (A[i] == B[1]);
for(int j=1; j+1<lenb&&i+j<lena; j++) {
u += (A[i+j]==B[j+1]);
}
v = max(v, u);
}
for(int i=1; i<lenb; i++) {
u = (B[i] == A[1]);
for(int j=1; j+1<lena&&i+j<lenb; j++) {
u += (B[i+j] == A[j+1]);
}
v = max(v, u);
}
printf("%d", lenb-v-1);
return 0;
}
动态规划
就解释代码吧
#include<bits/stdc++.h>
using namespace std;
char A[2010], B[2010];
int dp[2010][2010];
int main() {
int ans = 0, idx = 0, lena, lenb, u, v;
A[0] = B[0] = 1;
scanf("%s%s", &A[1], &B[1]);
lena = strlen(A), lenb = strlen(B);
for(int i=1; A[i]; i++) {
for(int j=1; B[j]; j++) {
ans = max(ans, dp[i][j] = dp[i-1][j-1] + (A[i] == B[j]));
}
}
printf("%d", lenb-ans-1);
return 0;
}
ans = max(ans, dp[i][j] = dp[i-1][j-1] + (A[i] == B[j]));
dp[i][j]是从dp[i-1][j-1]得到的。我们可以打印dp数组观察最大匹配;
举个例子:A:abcd,B:acc;
dp | a | c | c |
---|---|---|---|
a | 1 | 0 | 0 |
b | 0 | 1 | 0 |
c | 0 | 1 | 2 |
d | 0 | 0 | 1 |
我们可以发现最大匹配是A:abc,B:acc,相同字符数为2。
解决怎样在中间改变使最少操作数的问题