-
问题背景
- 给定两个字符串A和B,现在要将A经过若干操作变为B,求将A变为B所需要的最少操作次数,可进行的操作有:
- 删除–将字符串A中的某个字符删除。
- 插入–在字符串A的某个位置插入某个字符。
- 替换–将字符串A中的某个字符替换为另一个字符。
- 给定两个字符串A和B,现在要将A经过若干操作变为B,求将A变为B所需要的最少操作次数,可进行的操作有:
-
Dp分析
-
状态表示
- 二维状态表示
f(i,j) f(i,j)表示的是哪一个集合:所有满足如下条件的集合- 所有将 a[1 ~ i] 变成 b[1 ~ j] 的操作方式
f(i,j)存的是什么属性:Max,Min,数量;在这里f(i,j)存的应该是最小值,即将 a[1 - i] 变成 b[1- j] 的操作方式的最小值
- 二维状态表示
-
状态计算:
f(i,j)可以怎么算出来?- 这里可以将集合分为三个子集
- 通过一次删除将 a[1 ~ i] 变成 b[1 ~ j]
- f(i, j) = f(i - 1, j) + 1
- 通过一次插入将 a[1 ~ i] 变成 b[1 ~ j]
- f(i, j) = f(i, j - 1) + 1
- 通过一次替换将 a[1 ~ i] 变成 b[1 ~ j]
- f(i, j) = f(i -1, j - 1) + 1 或 f(i -1, j - 1)
- 通过一次删除将 a[1 ~ i] 变成 b[1 ~ j]
- 因此 f(i, j) = min( f(i - 1, j) + 1, f(i, j - 1) + 1, f(i -1, j - 1) + 1 或 f(i -1, j - 1) )
- 这里可以将集合分为三个子集
-
代码
-
//处理边界 for (int i = 1; i <= n; i++) { f[i][0] = i; } for (int i = 1; i <= m; i++) { f[0][i] = i; } for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { f[i][j] = Math.min(f[i - 1][j], f[i][j - 1]) + 1; if (a.charAt(i) == b.charAt(j)) { f[i][j] = Math.min(f[i][j], f[i - 1][j - 1]); } else { f[i][j] = Math.min(f[i][j], f[i - 1][j - 1] + 1); } } }
-
练习
01 最短编辑距离
- 题目
- 题解
import java.io.*;
import java.util.*;
public class Main {
public static final int N = 1010;
public static int[][] f = new int[N][N];
public static int n, m;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
String[] str1 = br.readLine().split(" ");
n = Integer.parseInt(str1[0]);
String a = " " + br.readLine();
String[] str2 = br.readLine().split(" ");
m = Integer.parseInt(str2[0]);
String b = " " + br.readLine();
//处理边界
for (int i = 1; i <= n; i++) {
f[i][0] = i;
}
for (int i = 1; i <= m; i++) {
f[0][i] = i;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
f[i][j] = Math.min(f[i - 1][j], f[i][j - 1]) + 1;
if (a.charAt(i) == b.charAt(j)) {
f[i][j] = Math.min(f[i][j], f[i - 1][j - 1]);
} else {
f[i][j] = Math.min(f[i][j], f[i - 1][j - 1] + 1);
}
}
}
pw.println(f[n][m]);
br.close();
pw.close();
}
}
02 编辑距离
- 题目
- 题解
import java.io.*;
import java.util.*;
public class Main {
public static final int N = 1010;
public static int[][] f = new int[N][N];
public static String[] strs = new String[N];
public static int n, m;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
String[] str1 = br.readLine().split(" ");
n = Integer.parseInt(str1[0]);
m = Integer.parseInt(str1[1]);
for (int i = 0; i < n; i++) {
strs[i] = " " + br.readLine();
}
while (m-- > 0) {
String[] str2 = br.readLine().split(" ");
String s = " " + str2[0];
int a = Integer.parseInt(str2[1]);
int res = 0;
for (int i = 0; i < n; i++) {
int q = query(strs[i], s);
if (q <= a) {
res++;
}
}
pw.println(res);
}
br.close();
pw.close();
}
public static int query(String a, String b) {
int l1 = a.length() - 1;
int l2 = b.length() - 1;
//处理边界
for (int i = 1; i <= l1; i++) {
f[i][0] = i;
}
for (int i = 1; i <= l2; i++) {
f[0][i] = i;
}
for (int i = 1; i <= l1; i++) {
for (int j = 1; j <= l2; j++) {
f[i][j] = Math.min(f[i - 1][j], f[i][j - 1]) + 1;
if (a.charAt(i) == b.charAt(j)) {
f[i][j] = Math.min(f[i][j], f[i - 1][j - 1]);
} else {
f[i][j] = Math.min(f[i][j], f[i - 1][j - 1] + 1);
}
}
}
return f[l1][l2];
}
}