算法设计与分析 3-5 编辑距离问题

本文介绍了一种计算两个字符串之间的编辑距离的有效算法,并提供了详细的步骤解释和两种Java实现方式。通过递归公式,文章展示了如何计算最少操作数以将一个字符串转换为另一个字符串。

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]的变换。可分以下几种情况来讨论。

  1. 字符A[i]改为字符B[j];需要δδ(A[i], B[j])次操作。
  2. 删除字符A[i];需要1次操作。
  3. 插入字符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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值