算法思想之動(dòng)態(tài)規(guī)劃(五)——最小編輯距離問題

前言

今天我們繼續(xù)討論經(jīng)典的動(dòng)態(tài)規(guī)劃問題之最小編輯距離問題

最小編輯距離問題

問題描述

對(duì)于兩個(gè)字符串A和B,我們需要進(jìn)行插入腰湾、刪除和修改操作將A串變?yōu)锽串,定義c0疆股,c1费坊,c2分別為三種操作的代價(jià),請(qǐng)?jiān)O(shè)計(jì)一個(gè)高效算法旬痹,求出將A串變?yōu)锽串所需要的最少代價(jià)附井。例如將"abc"轉(zhuǎn)化為"adc",c0=5两残,c1=3永毅,c2=100,最小代價(jià)為8人弓。

問題分析

我們先解釋下問題描述中為什么最小代價(jià)是8沼死。如果插入、刪除和修改操作的代價(jià)相同崔赌,顯然意蛀,"abc"->"adc"直接將'b'->'d'即可。但是由于多了c0=5健芭,c1=3县钥,c2=100的條件,所以直接進(jìn)行修改操作其代價(jià)為100慈迈,顯然不是最小代價(jià)若贮。最小代價(jià)對(duì)應(yīng)的操作應(yīng)該是使用插入、刪除操作代替修改操作——先在'a'與'c'中插入'd'痒留,然后刪除'b'谴麦,或者先刪除'b',在插入'd'狭瞎。這樣最小代價(jià)為8细移。
其實(shí),該問題實(shí)質(zhì)上是求解A \to B的最小編輯距離熊锭,只不過對(duì)每種操作賦予了權(quán)值弧轧。假設(shè)兩字符串A和B的長(zhǎng)度分別為nm。我們需要構(gòu)建一個(gè)(n+1) \times (m+1)的矩陣dp碗殷,代表A[0:i] \to B[0:j]的最小代價(jià)為dp[i][j]精绎。可能你會(huì)疑問锌妻,為什么是(n+1) \times (m+1)代乃,而不是n \times m呢? 觀察下面的矩陣,你可能會(huì)找到答案。我們需要在兩字符串前添加空字符串來得到增加搁吓、刪除操作所對(duì)應(yīng)的代價(jià)作為初始值原茅。

'' 'a' 'd' 'c'
'' 0 5 10 15
'a' 3
'b' 6
'c' 9

對(duì)于矩陣第0行第0列,代表由'' \to ''堕仔,顯然代價(jià)為0擂橘,即dp[0][0] = 0;
對(duì)于矩陣第0行第1列,代表由'' \to a摩骨,其代價(jià)為c_0通贞,即dp[0][1] = c_0 = 5;
對(duì)于矩陣第0行第2列,代表由'' \to ad恼五,其代價(jià)為2*c_0昌罩,即dp[0][1] = 2 * c_0 = 10;
依次類推,dp[0][j] = j * c_0灾馒,0 \leq j \leq m茎用。
同樣的,對(duì)于dp[i][0] = i * c_1你虹,0 \leq i \leq n绘搞。
那么當(dāng) 1 \leq i \leq n, 1 \leq j \leq m時(shí),dp[i][j] = ?
下面傅物,我們分兩種情況進(jìn)行討論:
(1) 當(dāng) A[i] == B[j]時(shí)夯辖,可能的操作即最小代價(jià)有以下幾種情況:

  • 不需要進(jìn)行任何操作,此時(shí)最小代價(jià)就是A[0:i-1] \to B[0:j-1]的最小代價(jià)董饰,即dp[i-1][j-1]蒿褂;
  • A[0:i] \to B[0:j-1],然后增加B[j]卒暂,此時(shí)最小代價(jià)為A[0:i] \to B[0:j-1]的最小代價(jià) + c_0啄栓,即dp[i][j-1] + c_0
  • 先將A[0:i-1] \to B[0:j]也祠,然后刪除A[i]昙楚,此時(shí)最小代價(jià)為A[0:i-1] \to B[0:j]的最小代價(jià) + c_1,即dp[i-1][j] + c_1诈嘿。

此時(shí)堪旧,dp[i][j] = min\{dp[i-1][j-1], dp[i][j-1] + c0, dp[i-1][j] + c1\};
(2) 當(dāng) A[i] \neq B[j]時(shí),可能的操作即最小代價(jià)有以下幾種情況:

  • 直接將A[i]替換為B[j]奖亚,此時(shí)最小代價(jià)就是A[0:i-1] \to B[0:j-1]的最小代價(jià) + c_2淳梦,即dp[i-1][j-1] + c_2
  • A[0:i] \to B[0:j-1]昔字,然后增加B[j]爆袍,此時(shí)最小代價(jià)為A[0:i] \to B[0:j-1]的最小代價(jià) + c_0,即dp[i][j-1] + c_0
  • 先將A[0:i-1] \to B[0:j]陨囊,然后刪除A[i]弦疮,此時(shí)最小代價(jià)為A[0:i-1] \to B[0:j]的最小代價(jià) + c_1,即dp[i-1][j] + c_1谆扎。

此時(shí)挂捅,dp[i][j] = min\{dp[i-1][j-1] + c_2, dp[i][j-1] + c0, dp[i-1][j] + c_1\};
需要注意的是,當(dāng)c_2 \geq c_0 + c_1時(shí)堂湖,需要令c_2 = c_0 + c_1,這是因?yàn)樾薷牟僮骺梢杂迷黾?刪除操作代替状土,這樣的代價(jià)比直接進(jìn)行修改操作的代價(jià)要低无蜂。問題分析一開始也給出了說明。

代碼實(shí)現(xiàn)

通過問題分析蒙谓,可以很容易得用代碼實(shí)現(xiàn)斥季,下面給出算法的java實(shí)現(xiàn)。

public class MinCost {
    public int findMinCost(String A, int n, String B, int m, int c0, int c1, int c2) {
        return core(A, n, B, m, c0, c1, c2);
    }

    public int core(String A, int n, String B, int m, int c0, int c1, int c2) {
        if (A.length() == 0 || B.length() == 0) {
            return 0;
        }
        A = " " + A;
        B = " " + B;
        int[][] dp = new int[n + 1][m + 1];
        // 初始化第0行
        dp[0][0] = 0;
        for (int i = 1; i < m + 1; i++) {
            dp[0][i] = c0 * i;
        }

        // 初始化第0列
        for (int j = 1; j < n + 1; j++) {
            dp[j][0] = c1 * j;
        }

        //update=delete+insert,如果update花費(fèi)更多就用delete+insert的花費(fèi)之和替換
        if (c2 >= c0 + c1) {
            c2 = c0 + c1;
        }

        for (int i = 1; i < n + 1; i++) {
            for (int j = 1; j < m + 1; j++) {
                if (A.charAt(i) == B.charAt(j)) {
                    //如果兩個(gè)字符串中A[i],B[j]的字符都一樣的
                    //1.什么都不做就行累驮,0操作
                    int dontChange = dp[i - 1][j - 1];
                    //2.比如由abd→abcd=abc→ab+B串刪除c
                    int delete = dp[i - 1][j] + c1;
                    //3.比如由abcd→abcd=abcd→abc+B串插入d
                    int insert = dp[i][j - 1] + c0;
                    dp[i][j] = Math.min((Math.min(dontChange, delete)), insert);
                } else {
                    //1. A abcd → B abce = A abc→B abc + (A abcd → B abce, 替換d為e)
                    int replace = dp[i - 1][j - 1] + c2;
                    //2.比如由A abcd→B abce=A abc→B abce+B串刪除e
                    int delete = dp[i - 1][j] + c1;
                    //3.比如由A abcd→B abce=A abcd→B abc+B串插入d
                    int insert = dp[i][j - 1] + c0;
                    dp[i][j] = Math.min((Math.min(replace, delete)), insert);
                }
            }
        }
        return dp[n][m];
    }

    public static void main(String[] args) {
        MinCost minCost = new MinCost();
        String A = "abc";
        int n = A.length();
        String B = "adc";
        int m = B.length();
        int c0 = 3;
        int c1 = 5;
        int c2 = 3;
        int res = minCost.findMinCost(A, n, B, m, c0, c1, c2);
        System.out.println(res);
    }
}

經(jīng)典問題

未來幾篇博文酣倾,我將繼續(xù)對(duì)經(jīng)典的動(dòng)態(tài)規(guī)劃問題進(jìn)行整理,敬請(qǐng)關(guān)注~
由于本人水平有限谤专,文章難免有欠妥之處躁锡,歡迎大家多多批評(píng)指正!

寫在最后

歡迎大家關(guān)注我的個(gè)人博客復(fù)旦猿置侍。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末映之,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蜡坊,更是在濱河造成了極大的恐慌杠输,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,744評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件秕衙,死亡現(xiàn)場(chǎng)離奇詭異蠢甲,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)据忘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門鹦牛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人若河,你說我怎么就攤上這事能岩。” “怎么了萧福?”我有些...
    開封第一講書人閱讀 163,105評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵拉鹃,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng)膏燕,這世上最難降的妖魔是什么钥屈? 我笑而不...
    開封第一講書人閱讀 58,242評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮坝辫,結(jié)果婚禮上篷就,老公的妹妹穿的比我還像新娘。我一直安慰自己近忙,他們只是感情好竭业,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,269評(píng)論 6 389
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著及舍,像睡著了一般未辆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上锯玛,一...
    開封第一講書人閱讀 51,215評(píng)論 1 299
  • 那天咐柜,我揣著相機(jī)與錄音,去河邊找鬼攘残。 笑死拙友,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的歼郭。 我是一名探鬼主播遗契,決...
    沈念sama閱讀 40,096評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼实撒!你這毒婦竟也來了姊途?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,939評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤知态,失蹤者是張志新(化名)和其女友劉穎捷兰,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體负敏,經(jīng)...
    沈念sama閱讀 45,354評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡贡茅,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,573評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了其做。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片顶考。...
    茶點(diǎn)故事閱讀 39,745評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖妖泄,靈堂內(nèi)的尸體忽然破棺而出驹沿,到底是詐尸還是另有隱情,我是刑警寧澤蹈胡,帶...
    沈念sama閱讀 35,448評(píng)論 5 344
  • 正文 年R本政府宣布渊季,位于F島的核電站朋蔫,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏却汉。R本人自食惡果不足惜驯妄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,048評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望合砂。 院中可真熱鬧青扔,春花似錦、人聲如沸翩伪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽缘屹。三九已至励两,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間囊颅,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工傅瞻, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留踢代,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,776評(píng)論 2 369
  • 正文 我出身青樓嗅骄,卻偏偏與公主長(zhǎng)得像胳挎,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子溺森,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,652評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容