【動態規劃】字串最小編輯距離Java實現

王世暉發表於2016-03-23

問題:給定一個源串和目標串,能夠對源串進行如下操作:

在給定位置上插入一個字元

替換任意字元

刪除任意字元

要求寫一個程式,返回最少的運算元,使得對源串進行這些操作後等於目標串。源串和目標串的長度都小於2000

 

關於編輯距離

編輯距離(Edit Distance),又稱Levenshtein距離,是指兩個字串之間,由一個轉成另一個所需的最少編輯操作次數。許可的編輯操作包括將一個字元替換成另一個字元,插入一個字元,刪除一個字元。

例如:字串abc和字串adbe之間的最小編輯距離是2 因為adbe刪除b然後將e替換為c經過這兩部


a[m]表示第一個字串,m表示該字串字元的下標為0~m

b[n]表示第二個字串,n表示該字串字元的下標為0~n

d[i][j]表示子串a[i]和子串a[j]的最小編輯距離

那麼邊界條件:

d[i][0]=i, 0=<i<=m

d[0][j]=j, 0=<j<=n

狀態轉移方程:d[i][j]=min{d[i-1][j]+1,d[i][j-1]+1,d[i-1][j-1]+lastCharCommon}

lastCharCommon=1,如果a[i-1]等於b[j-1]

lastCharCommon=0,如果a[i-1]不等於b[j-1]

下邊給出java實現:

class StringEditDistance{
    /*輸入兩個字串,返回這兩個字串的編輯距離*/
    public static int getDistance(String strA, String strB){
        int distance=-1;
        /*輸入引數合法性檢查*/
        if(null==strA||null==strB||strA.isEmpty()||strB.isEmpty()){
            return distance;
        }
        /*兩個字串相等,編輯距離為0*/
        if (strA.equals(strB)) {
            return 0;
        }
        System.out.println("第一個字串:"+strA);
        System.out.println("第二個字串:"+strB);
        int lengthA=strA.length();
        int lengthB=strB.length();
        int length=Math.max(lengthA,lengthB);
        /*申請一個二維陣列,儲存轉移矩陣*/
        int array[][]=new int[length+1][length+1];
        /*邊界條件初始化*/
        for(int i=0;i<=length;i++){
            array[i][0]=i;

        }
        /*邊界條件初始化*/
        for(int j=0;j<=length;j++){
            array[0][j]=j;
        }
        /*狀態轉移方程*/
        for(int i=1;i<=lengthA;i++){
            for(int j=1;j<=lengthB;j++){
                array[i][j]=min(array[i-1][j]+1,
                                array[i][j-1]+1,
                                array[i-1][j-1]+(strA.charAt(i-1)==strB.charAt(j-1)?0:1));
            }
        }
        /*列印轉移表格*/
        System.out.println("狀態轉移表格:");
        for(int i=0;i<=lengthA;i++){
            for(int j=0;j<=lengthB;j++){
               System.out.print( array[i][j]+"    ");
            }
            System.out.println();
        }
        return array[lengthA][lengthB];

    }
    /*取三個數中的最小值*/
    public static int  min(int a,int b, int c){
        return Math.min(Math.min(a,b),c);
    }
}

測試用例:

String a=null;
String b="abd";

System.out.println("case 1:編輯距離為:"+StringEditDistance.getDistance(a,b));
System.out.println();

a="Program";
b="P-r-o-g-r-a-m";
System.out.println("case 2:編輯距離為"+StringEditDistance.getDistance(a,b));
System.out.println();

a="2333";
b="6666666";
System.out.println("case 3:編輯距離為"+StringEditDistance.getDistance(a,b));
System.out.println();

a="adbe";
b="abc";
System.out.println("case 4:編輯距離為"+StringEditDistance.getDistance(a,b));
System.out.println();

a="hehe";
b="hehe";
System.out.println("case 5:編輯距離為"+StringEditDistance.getDistance(a,b));
System.out.println();


執行結果:


case 1:編輯距離為:-1


第一個字串:Program
第二個字串:P-r-o-g-r-a-m
狀態轉移表格:
0    1    2    3    4    5    6    7    8    9    10    11    12    13    
1    0    1    2    3    4    5    6    7    8    9    10    11    12    
2    1    1    1    2    3    4    5    6    7    8    9    10    11    
3    2    2    2    2    2    3    4    5    6    7    8    9    10    
4    3    3    3    3    3    3    3    4    5    6    7    8    9    
5    4    4    3    4    4    4    4    4    4    5    6    7    8    
6    5    5    4    4    5    5    5    5    5    5    5    6    7    
7    6    6    5    5    5    6    6    6    6    6    6    6    6    
case 2:編輯距離為6


第一個字串:2333
第二個字串:6666666
狀態轉移表格:
0    1    2    3    4    5    6    7    
1    1    2    3    4    5    6    7    
2    2    2    3    4    5    6    7    
3    3    3    3    4    5    6    7    
4    4    4    4    4    5    6    7    
case 3:編輯距離為7


第一個字串:adbe
第二個字串:abc
狀態轉移表格:
0    1    2    3    
1    0    1    2    
2    1    1    2    
3    2    1    2    
4    3    2    2    
case 4:編輯距離為2


case 5:編輯距離為0

相關文章