问题描述:
输入一个字符串如:ABACBDAD,经过若干操作后变为:BDCABA
问题描述:设s和t是两个字符串,要用最少的字符操作将字符串s转换为字符串t,这里所说的字符操作包括
(1):删除一个字符;
(2):插入一个字符;
(3):修改一个字符。
将s转换为t所用的最少字符操作数称为s到t的编辑距离
问题分析:
设字符串s,t的长度分别是m、n,用字符S、T来存放
设置一个动态规划二维数组D,D[i][j]表示S与T的最优编辑距离(即S转换为T的最少操作步数)
显然,当t串空的时候要删除s中的全部字符转换为t,即D[i][0]=i;(删除s中的i个字符,共i次操作)。同理,当s串空时在s中插入t中的全部字符转换为t,即D[0][j]=j;(向s中插入t的j个字符,共j次操作)
对于非空的情况,当S[i-1]=T[j-1]时,这两个字符不需要任何操作,即D[i][j]=D[i-1][j-1]+0;当S[i-1]!=T[j-1]时,有3中操作可以达到目的
- 将S[i-1]替换为T[j-1],即D[i][j]=D[i-1][j-1]+1(一次替换操作的次数为1)
② 在S[i-1]字符后插入T[j-1]字符,即D[i][j]=D[i][j-1]+1(一次插入操作的次数为1)
- 删除S[i-1]字符,即D[i][j]=D[i-1][j]+1(一次删除操作的次数为1)
此时D[i][j]取3中操作的最小值,转换方程为:
实验代码:
import java.util.Scanner;
public class Minimum_Edit_Distance {
/**
*
* @Description 找出a,b,c三者的最小值
* @author chen
* @datem 2021年11月3日下午3:17:29
* @param a
* @param b
* @param c
* @return minNumber最小值
*/
public static int minNumber(int a, int b, int c) {
int temp = (a > b) ? b : a;
int mintemp = (temp > c) ? c : temp;
return mintemp;
}
/**
* @Description 距离步数和方式
* @author chen
* @datem 2021年11月3日下午3:18:43
* @param D 距离操作的步数的数组
* @param Rec 记录操作的方式(插入、删除、替换)的数组
* @param s
* @param t
*/
public static void Minimum_Edit_Distance(int D[][], String Rec[][], String s, String t) {
char S[] = s.toCharArray();
char T[] = t.toCharArray();
int n = S.length;// 7
int m = T.length;
// 初始化
D[0][0] = 0;
for (int i = 1; i <= n; i++) {
D[i][0] = i;
Rec[i][0] = "U";
}
// 初始化
Rec[0][0] = "0";
for (int j = 1; j <= m; j++) {
D[0][j] = j;
Rec[0][j] = "L";
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
// 替换/无需操作
int c = 0;
if (S[i - 1] != T[j - 1]) {
c = 1;
}
int replace = D[i - 1][j - 1] + c;// 替换
int delete = D[i - 1][j] + 1;// 删除
int insert = D[i][j - 1] + 1;// 插入
int min = minNumber(replace, delete, insert);
if (replace == min) {// 替换
D[i][j] = D[i - 1][j - 1] + c;
Rec[i][j] = "LU";
} else if (insert == min) {// 插入
D[i][j] = D[i][j - 1] + 1;
Rec[i][j] = "L";
} else if (delete == min) {// 删除
D[i][j] = D[i - 1][j] + 1;
Rec[i][j] = "U";
}
}
}
}
/**
*
* @Description 输出操作方式
* @author chen
* @datem 2021年11月3日下午4:43:27
* @param Rec 记录操作的方式(插入、删除、替换)的数组
* @param s
* @param t
* @param i
* @param j
*/
public static void Print_MED(String Rec[][], String s, String t, int i, int j) {
char S[] = s.toCharArray();
char T[] = t.toCharArray();
if (i == 0 && j == 0) {
return;
}
// 替换/无需操作
if (Rec[i][j] == "LU") {
Print_MED(Rec, s, t, i - 1, j - 1);
if (S[i - 1] == T[j - 1]) {
System.out.println("无需操作");
} else {
System.out.println("用" + T[j - 1] + "替换" + S[i - 1] + ",");
}
} else if (Rec[i][j] == "U") {// 删除
Print_MED(Rec, s, t, i - 1, j);
System.out.println("删除" + S[i - 1]);
} else if (Rec[i][j] == "L") {// 插入
Print_MED(Rec, s, t, i, j - 1);
System.out.println("插入" + T[j - 1]);
}
}
/**
*
* @Description 遍历String数组
* @author chen
* @datem 2021年11月3日下午3:56:36
* @param Rec
*/
public static void PrintArray(String Rec[][]) {
int count = 0;
for (int i = 0; i < Rec.length; i++) {
for (int j = 0; j < Rec[i].length; j++) {
System.out.print(Rec[i][j] + " ");
count++;
if (count % Rec[i].length == 0) {
System.out.println();
}
}
}
}
/**
*
* @Description 遍历int数组
* @author chen
* @datem 2021年11月3日下午3:56:12
* @param D
*/
public static void PrintArray(int D[][]) {
int count = 0;
for (int i = 0; i < D.length; i++) {
for (int j = 0; j < D[i].length; j++) {
System.out.print(D[i][j] + " ");
count++;
if (count % D[i].length == 0) {
System.out.println();
}
}
}
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.println("请输入第一个字符串:");
String s = scan.next();
System.out.println("请输入第二个字符串:");
String t = scan.next();
// 记录编辑距离
int D[][] = new int[s.length() + 1][t.length() + 1];
// 记录编辑方式
String Rec[][] = new String[s.length() + 1][t.length() + 1];
Minimum_Edit_Distance(D, Rec, s, t);
Print_MED(Rec, s, t, s.length(), t.length());
System.out.println("最短编辑距离为" + D[s.length()][t.length()]);
}
}
实验结果: