文章目录
0. 前言
编辑距离:很类似于 LCS
问题,状态表示十分类似。学习 dp
问题必备入门题了
1. 编辑距离模板题
重点: 线性 dp
、LCS 问题及优化
思路:
- 状态定义:
f[i][j]
所有将a[1:i]
变成b[1:j]
的操作次数的最小值
- 状态转移:
- 分类依据:分别三种方式操作
a
中的第i
个字母,使得,a[1:i]
和b[1:j]
匹配- 删除
a
的第i
个字母,使得a[1:i]
与b[1:j]
匹配,等价于f[i-1][j] + 1
,因为a[1:i-1] == b[1:j]
- 增加
a
的第i
个字母,使得a[1:i]
与b[1:j]
匹配,等价f[i][j-1] + 1
,因为a[1:i] == b[1:j-1]
- 修改
a
的第i
个字母,使得a[1:i]
与b[1:j]
匹配,等价f[i-1][j-1]+1/0
,如果a[i] == b[j]
则不需要再修改,如果a[i] != b[j]
则说明a[1:a-1] == b[1:j-1]
,则一步操作就能改过来,所以 +1
- 删除
- 分类依据:分别三种方式操作
- 边界处理及初始化
f[i][0]
需要把第一个字符串连续删i
次才能和b
相等,即,f[i][0] = i
f[0][i]
需要把第二个字符串连续删i
次才能和a
相等,即,f[0][i] = i
- 时间复杂度:
- O ( n 2 ) O(n^2) O(n2)
代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1005;
int n, m;
char a[N], b[N];
int f[N][N];
int main() {
scanf("%d%s", &n, a + 1);
scanf("%d%s", &m, b + 1);
for (int i = 0; i <= m; ++i) f[0][i] = i;
for (int i = 0; i <= n; ++i) f[i][0] = i;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
f[i][j] = min(f[i - 1][j] + 1, f[i][j - 1] + 1);
if (a[i] == b[j]) f[i][j] = min(f[i][j], f[i - 1][j - 1]);
else f[i][j] = min(f[i][j], f[i - 1][j - 1] + 1);
}
}
cout << f[n][m] << endl;
return 0;
}
经典编辑距离问题的变种题
重点: 线性 dp
、编辑距离问题变种
思路:
- 问题解释:
- 给了
n
个固定的字符串,然后再给定一个字符串,后面跟一个数字,是从固定字符串通过编辑,和本串相等的最大的编辑次数限制。让返回n
个固定的字符串中在限制步数中能变成给定串的个数。
- 给了
- 时间复杂度:
- 总共编辑距离需要做
1000
(
n
)
∗
1000
(
m
)
∗
100
(
编
辑
距
离
为
10
∗
10
)
=
1
e
8
1000(n) * 1000(m) * 100(编辑距离为10*10)= 1e8
1000(n)∗1000(m)∗100(编辑距离为10∗10)=1e8 次计算,差不多能过,一般
C++
一秒可求解1e7~1e8
的计算量
- 总共编辑距离需要做
1000
(
n
)
∗
1000
(
m
)
∗
100
(
编
辑
距
离
为
10
∗
10
)
=
1
e
8
1000(n) * 1000(m) * 100(编辑距离为10*10)= 1e8
1000(n)∗1000(m)∗100(编辑距离为10∗10)=1e8 次计算,差不多能过,一般
状态定义及转移、初始化均与上面的编辑距离一样,不再赘述。
代码:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 15, M = 1005;
int n, m;
int f[N][N];
char str[M][N];
int edit_distance(char a[], char b[]) {
int la = strlen(a + 1), lb = strlen(b + 1);
for (int i = 0; i <= lb; ++i) f[0][i] = i;
for (int i = 0; i <= la; ++i) f[i][0] = i;
for (int i = 1; i <= la; ++i)
for (int j = 1; j <= lb; ++j) {
f[i][j] = min(f[i - 1][j] + 1, f[i][j - 1] + 1);
f[i][j] = min(f[i][j], f[i - 1][j - 1] + (a[i] != b[j]));
}
return f[la][lb];
}
int main() {
cin >> n >> m;
for (int i = 0; i < n; ++i) scanf("%s", str[i] + 1);
while (m --) {
char s[N];
int limit;
scanf("%s%d", s + 1, &limit);
int res = 0;
for (int i = 0; i < n; ++i)
if (edit_distance(str[i], s) <= limit)
res ++;
cout << res << endl;
}
return 0;
}