Acw902.最短编辑距离
902.最短编辑距离
题目描述
给定两个字符串 \(A\) 和 \(B\),现在要将 \(A\) 经过若干操作变为 \(B\),可进行的操作有:
- 删除–将字符串 \(A\) 中的某个字符删除。
- 插入–在字符串 \(A\) 的某个位置插入某个字符。
- 替换–将字符串 \(A\) 中的某个字符替换为另一个字符。
现在请你求出,将 \(A\) 变为 \(B\) 至少需要进行多少次操作。
输入描述
第一行包含整数 \(1\leq n \leq 1000\) ,表示字符串 \(A\) 的长度。
第二行包含一个长度为 \(n\) 的字符串 \(A\) 。
第三行包含整数 \(1\leq m \leq 1000\) ,表示字符串 \(B\) 的长度。
第四行包含一个长度为 \(m\) 的字符串 \(B\) 。
字符串中均只包含大小写字母。
输出描述
输出一个整数,表示最少操作次数。
解题思路
根据题目很容易想到暴力求解,但是复杂度显然不允许,可以发现长字符串的变化可以由短字符串得到,因此考虑使用动态规划来解决这个问题。
首先创建一个二维的dp数组,一维删除,一维插入。 \(dp[i][0]\) 表示将前 \(i\) 个字符的字符串变为空字符串所需的操作数,即删除操作的次数; \(dp[0][i]\) 表示将空字符串变为前 \(i\) 个字符的字符串所需的操作数,即插入操作的次数。总的来说, \(dp[i][j]\) 表示把 \(s1[1]\) - \(s1[i]\) 变成 \(s2[1]\) - \(s2[j]\) 需要操作的最少操作次数。
初始化 \(dp[0][0]\) 为 \(0\) ,表示从空字符串到空字符串需要操作的次数是 \(0\) 。
对于每个字符 \(s1[i]\) 和 \(s2[j]\) ,如果它们不同,则可以有三种操作:
- 删除 \(s1[i]\) ,即 \(dp[i-1][j]+1\)
- 插入 \(s2[j]\) ,即 \(dp[i][j-1]+1\)
- 替换 \(s1[i]\) 为 \(s2[j]\) :即 \(dp[i-1][j-1]+1\)
如果它们相同,则不需要进行操作,操作数为 \(dp[i-1][j-1]\)
因此我们可以得到以下状态转移方程:
\[dp[i][j]=min
\begin{cases}
dp[i−1][j]+1 , (删除操作) \\
dp[i][j−1]+1 , (插入操作) \\
dp[i−1][j−1]+cost , (替换操作,如果s1[i-1]==s2[j-1],cost=0,否则cost=1)
\end{cases}
\]
结合上述步骤即可得到最终答案。
代码实现
#include <bits/stdc++.h>
using i64 = long long;
const int inf = 2e9;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
int n, m;
std::string s1, s2;
std::cin >> n >> s1 >> m >> s2;
s1 = " " + s1;
s2 = " " + s2;
std::vector<std::vector<int>> dp(n + 1, std::vector<int>(m + 1, inf));
for (int i = 1; i <= n; i++) {
dp[i][0] = i;
}
for (int i = 1; i <= m; i++) {
dp[0][i] = i;
}
dp[0][0] = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
dp[i][j] = std::min(dp[i - 1][j], dp[i][j - 1]) + 1;
if (s1[i] == s2[j]) {
dp[i][j] = std::min(dp[i][j], dp[i - 1][j - 1]);
} else {
dp[i][j] = std::min(dp[i][j], dp[i - 1][j - 1] + 1);
}
}
}
std::cout << dp[n][m];
}

浙公网安备 33010602011771号