動態規劃8:最優編輯str1-->str2

LingLee_荊棘鳥發表於2017-07-19

題目:

對於兩個字串A和B,我們需要進行插入、刪除和修改操作將A串變為B串,定義c0,c1,c2分別為三種操作的代價,求出將A串變為B串所需要的最少代價。給定兩個字串A和B,及它們的長度和三種操作代價,請返回將A串變為B串所需要的最小代價。保證兩串長度均小於等於300,且三種代價值均小於等於100。

樣例:"abc",3,"adc",3,5,3,100返回:8


思路:

將問題拆分成為2個維度的問題(A串作為縱向,B串作為橫向),建立二維陣列來進行解決。在建立二維陣列時要注意是建立n*m的矩陣還是建立(n+1)*(m+1)的矩陣,關鍵是思考對於陣列為””空串的情形是否要作為初始條件,即是否應該讓空串作為初始條件,從實際意義上來理解,空串也是一種字串,且與可能要求將空串編輯成為某個字串,或者將某個字串編輯成為空串,因此需要對字串A,B從空串“”開始進行拆分考慮。但是實際上是否從空串或者0開始分解要看如果分解成為這種初始條件是否可以據此求出後面的所有情況的結果,即所求的第1行,第1列應當是有效的,能夠據此求出後面的一系列情況,而不是固定的記住。

這個題目和找零錢問題類似。



dp[n+1][m+1]  其中dp[i][j]表示s1[0...i-1]轉變成s2[0...j]的代價

插入刪除修改代價分別為 ic  dc  rc

初始情況:

(1)dp[0][0]表示s1 s2都是空串,所以代價為0

(2)dp[0][j]第一行,表示s1是空串,轉變成s2[j],那麼代價就是插入j個字元的代價dp[0][j]=ic*j

(3)dp[i][0]第一列,表示s2是空串,那麼轉換代價就是刪除s1中的i個字元代價 dp[i][0]=dc*i;

遞迴:

d[i][j]來自以下四種情況:最小值

(1)s1[0...i-1]能夠轉換成s2[0...j],此時代價為轉換代價+刪除一個字元的代價。即d[i][j]=d[i-1][j]+dc

(2)s1[0...i]能夠轉換成s2[0...j-1],此時代價為轉換代價+插入一個字元的代價。即d[i][j]=d[i][j-1]+ic

(3)當s1[i]!=s[j]時,d[i][j]=d[i-1][j-1]+rc

(4)當s1[i]==s[j]時,d[i][j]=d[i-1][j-1]


public class MinCost {
    public int findMinCost(String s1, int n, String s2, int m, int c0, int c1, int c2) {//插入刪除修改依次為c0 c1 c2
        // write code here
        if(s1==null&&s2==null) return 0;
        int[][] dp=new int[n+1][m+1];
        
        //初始條件
        dp[0][0]=0;//表示兩個空串的轉換
        for(int i=1;i<=m;i++){//空串轉換成s2=插入i個字元的代價
            dp[0][i]=i*c0;
        }
        for(int i=1;i<=n;i++){//字串轉成空串=刪除i個字元的代價
            dp[i][0]=i*c1;
        }
        
        //遞迴
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                
                dp[i][j]=Math.min( (dp[i-1][j]+c1), (dp[i][j-1]+c0) );
                if(s1.charAt(i-1)==s2.charAt(j-1)){
                    dp[i][j]=Math.min( dp[i][j], dp[i-1][j-1]);
                }else{
                     dp[i][j]=Math.min(dp[i][j], dp[i-1][j-1]+c2);
                }
            }
        }
        return dp[n][m];
    }
}


相關文章