题目传送门
思路:
这道题是经典的编辑距离问题(Edit Distance),通常使用动态规划(Dynamic Programming, DP)来解决。编辑距离是指将一个字符串转换成另一个字符串所需的最少操作次数,操作包括插入、删除和替换字符。
思路
-
定义状态:
- 设
dp[i][j]
表示将字符串A
的前i
个字符转换成字符串B
的前j
个字符所需的最少操作次数。
- 设
-
状态转移方程:
- 如果
A[i-1] == B[j-1]
,则dp[i][j] = dp[i-1][j-1]
,因为当前字符相同,不需要额外操作。 - 如果
A[i-1] != B[j-1]
,则需要考虑三种操作:- 插入:
dp[i][j] = dp[i][j-1] + 1
,即在A
的第i
个位置插入一个字符使得A[i] == B[j-1]
。 - 删除:
dp[i][j] = dp[i-1][j] + 1
,即删除A
的第i
个字符。 - 替换:
dp[i][j] = dp[i-1][j-1] + 1
,即将A
的第i
个字符替换为B
的第j
个字符。
- 插入:
- 综上,
dp[i][j] = min(dp[i][j-1], dp[i-1][j], dp[i-1][j-1]) + 1
。
- 如果
-
初始化:
dp[0][j] = j
,即将空字符串转换为B
的前j
个字符需要j
次插入操作。dp[i][0] = i
,即将A
的前i
个字符转换为空字符串需要i
次删除操作。
-
结果:
dp[len(A)][len(B)]
即为将字符串A
转换为字符串B
所需的最少操作次数。
Python代码(现打的,WA了不怪我):
def edit_distance(A, B):
len_A = len(A)
len_B = len(B)
# 创建一个 (len_A + 1) x (len_B + 1) 的二维数组
dp = [[0] * (len_B + 1) for _ in range(len_A + 1)]
# 初始化
for i in range(len_A + 1):
dp[i][0] = i
for j in range(len_B + 1):
dp[0][j] = j
# 状态转移
for i in range(1, len_A + 1):
for j in range(1, len_B + 1):
if A[i - 1] == B[j - 1]:
dp[i][j] = dp[i - 1][j - 1]
else:
dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1
return dp[len_A][len_B]
# 输入
A = input().strip()
B = input().strip()
# 输出
print(edit_distance(A, B))
Pascal代码(现打的,WA了不怪我):
program EditDistance;
var
A, B: string;
len_A, len_B: integer;
dp: array[0..2000, 0..2000] of integer;
i, j: integer;
begin
readln(A);
readln(B);
len_A := length(A);
len_B := length(B);
// 初始化
for i := 0 to len_A do
dp[i, 0] := i;
for j := 0 to len_B do
dp[0, j] := j;
// 状态转移
for i := 1 to len_A do
for j := 1 to len_B do
if A[i] = B[j] then
dp[i, j] := dp[i - 1, j - 1]
else
dp[i, j] := min(dp[i - 1, j] + 1, min(dp[i, j - 1] + 1, dp[i - 1, j - 1] + 1));
writeln(dp[len_A, len_B]);
end.
c++代码(100pts):
#include<iostream>
#include<istream>
#include<ostream>
#include<string>
#include<algorithm>
#include<bitset>
#include<cmath>
#include<queue>
#include<map>
#include<iomanip>
#include<cstdio>
#include<cstring>
using namespace std;
int f[5000][5000]; //f表示将str串的前x个字符改成target串最少需要多少步
char str[5000],target[5000]; //str:原来的字符串,target:改后的字符串
int main(){ //主函数
cin>>str; //输入原来的字符串
cin>>target; //输入改后的字符串
for(int i = 1;i <= strlen(str);i++) f[i][0] = i; //删i个字符,编辑距离为i
for(int i = 1;i <= strlen(target);i++) f[0][i] = i; //同上
for(int i = 1;i <= strlen(str);i++){
for(int j = 1;j <= strlen(target);j++){
if(str[i - 1] == target[j - 1]) f[i][j] = f[i - 1][j - 1]; //如果两个字符串的第i个字符一样,就不用改距离
else f[i][j] = min(min(f[i - 1][j - 1] + 1,f[i - 1][j] + 1),f[i][j - 1] + 1); //找删字符、插入字符、替换字符中操作次数的最小值
}
}
cout<<f[strlen(str)][strlen(target)]<<endl; //输出需要最少的操作次数(最小的编辑距离)
return 0;
}