3-5 编辑距离问题
问题描述
设A和B是2个字符串。要用最少的字符操作将字符串A转换为字符串B。这里所说的字符操作包括:
(1)删除一个字符;
(2)插入一个字符;
(3)将一个字符改为另一个字符。
将字符串A变换为字符串B所用的最少字符操作数称为字符串A到B的编辑距离,记为d(A,B)。试设计一个有效算法,对任给的2个字符串A和B,计算出它们的编辑距离d(A,B)。
输入:第1行是字符串A,第2行是字符串B。
输出:字符串A和B的编辑距离d(A,B)
分析
设所给的2个字符串为A[1…m]和B[1…n]。定义D[i, j]=
(A[1…i], B[1…j])。单字符a,b间的距离定义为
(a, b) = 0 当a = b;
(a, b) = 1 当a != b;
考察从字符串A[1…i]到字符串B[1…j]的变换。可分以下几种情况来讨论。
- 字符A[i]改为字符B[j];需要 (A[i], B[j])次操作。
- 删除字符A[i];需要1次操作。
- 插入字符B[j];需要1次操作。
因此,D[i, j]可递归地计算如下:
D[i, j] = min{ D[i-1, j-1]+
(A[i], B[j]), D[i-1, j]+1, D[i, j-1]+1}
D[i, j]的初始值为:
D[i, 0] = i, 0<=i<=m
D[0, j] = j, 0<=j<=n
Java: version 1
import java.util.Scanner;
public class BianJiJuLi {
public static void main(String[] args){
String A, B;
int lenA, lenB;
char[] tmpA, tmpB;
char[] arrA, arrB;
int[][] D;
int i, j;
int MAX = 100000;
int delta;
Scanner input = new Scanner(System.in);
while (true){
A = input.next();//fxpimu
B = input.next();//xwrs
lenA = A.length();
lenB = B.length();
D = new int[lenA+1][lenB+1];
tmpA = A.toCharArray();
tmpB = B.toCharArray();
arrA = new char[lenA+1];
arrB = new char[lenB+1];
System.arraycopy(tmpA, 0, arrA, 1, lenA);
System.arraycopy(tmpB, 0, arrB, 1, lenB);
for(i=1; i<=lenA; i++)
D[i][0] = i;
for(j=1; j<=lenB; j++)
D[0][j] = j;
for(i=1; i<=lenA; i++)
for(j=1; j<=lenB; j++){
D[i][j] = MAX;
if(arrA[i] == arrB[j])
delta = 0;
else
delta = 1;
if(D[i][j] > D[i-1][j-1]+delta)
D[i][j] = D[i-1][j-1]+delta;
if(D[i][j] > D[i-1][j]+1)
D[i][j] = D[i-1][j]+1;
if(D[i][j] > D[i][j-1]+1)
D[i][j] = D[i][j-1]+1;
}
System.out.println(D[lenA][lenB]);
}
}
}
或
import java.util.Scanner;
public class BianJiJuLi {
public static void main(String[] args){
String A, B;
int lenA, lenB;
char[] tmpA, tmpB;
// char[] arrA, arrB;
int[][] D;
int i, j;
int MAX = 100000;
int delta;
Scanner input = new Scanner(System.in);
while (true){
A = input.next();//fxpimu
B = input.next();//xwrs
lenA = A.length();
lenB = B.length();
D = new int[lenA+1][lenB+1];
tmpA = A.toCharArray();
tmpB = B.toCharArray();
// arrA = new char[lenA+1];
// arrB = new char[lenB+1];
// System.arraycopy(tmpA, 0, arrA, 1, lenA);
// System.arraycopy(tmpB, 0, arrB, 1, lenB);
for(i=1; i<=lenA; i++)
D[i][0] = i;
for(j=1; j<=lenB; j++)
D[0][j] = j;
for(i=1; i<=lenA; i++)
for(j=1; j<=lenB; j++){
D[i][j] = MAX;
if(tmpA[i-1] == tmpB[j-1])
// if(arrA[i] == arrB[j])
delta = 0;
else
delta = 1;
if(D[i][j] > D[i-1][j-1]+delta)
D[i][j] = D[i-1][j-1]+delta;
if(D[i][j] > D[i-1][j]+1)
D[i][j] = D[i-1][j]+1;
if(D[i][j] > D[i][j-1]+1)
D[i][j] = D[i][j-1]+1;
}
System.out.println(D[lenA][lenB]);
}
}
}
Input & Output
fxpimu
xwrs
5
fxpimu
fxpimu
0
fxpimu
f
5
fxpimu
mu
4
fxpimu
u
5
fxpimu
q
6
Java: version 2
import java.util.Scanner;
public class BianJiJuLi1 {
public static void main(String[] args){
String A, B;
int lenA, lenB;
char[] arrA, arrB;
int[] D;
int i, j;
int MAX = 100000;
int delta;
int x, y, z;
Scanner input = new Scanner(System.in);
while (true){
A = input.next();//fxpimu
B = input.next();//xwrs
lenA = A.length();
lenB = B.length();
D = new int[lenB+1];
arrA = A.toCharArray();
arrB = B.toCharArray();
for(j=1; j<=lenB; j++)
D[j] = j;
for(i=1; i<=lenA; i++){
y = i-1;
for(j=1; j<=lenB; j++){
x = y;
y = D[j];
D[j] = MAX;
z = j>1?D[j-1]:i;
if(arrA[i-1] == arrB[j-1])
delta = 0;
else
delta = 1;
if(D[j] > (x+delta))
D[j] = x+delta;
if(D[j] > (y+1))
D[j] = y+1;
if(D[j] > z+1)
D[j] = z+1;
}
}
System.out.println(D[lenB]);
}
}
}
Input & Output
fxpimu
fxpimu
0
fxpimu
xwrs
5
fxpimu
f
5
fxpimu
im
4
fxpimu
iq
5
Reference
王晓东《计算机算法设计与分析》(第3版)P89-90