Leetcode72-編輯距離,DP經(jīng)典回味匙瘪,深入分析

20201_022201canvas.png

這是一道相當(dāng)經(jīng)典的動(dòng)態(tài)規(guī)劃問(wèn)題铆铆,最初做這道題的時(shí)候,還是在大學(xué)丹喻,當(dāng)時(shí)見(jiàn)到這題一頭霧水薄货,看了別人的解析還是不太理解,而且看狀態(tài)方程時(shí)碍论,僅僅是看到了狀態(tài)的方程的 “形”谅猾,不懂每個(gè)狀態(tài)方程的本質(zhì)是什么。
如今再做時(shí)骑冗,很快就理解了赊瞬。廢話有點(diǎn)多,不過(guò)認(rèn)真看下去贼涩,相信你會(huì)理解的更深一些巧涧。
在做動(dòng)態(tài)規(guī)劃時(shí),往往開(kāi)的dp數(shù)組遥倦,有的題是原始數(shù)據(jù)長(zhǎng)度 + 1谤绳,有的不加一

  int sovle(int n) {
     //n可以理解為題目給的原始數(shù)組長(zhǎng)度,比如斐波那契數(shù)列數(shù)列袒哥,n 表示 第 n 個(gè)值是多少
    //然后根據(jù) n 毫無(wú)猶豫的 定義 dp數(shù)組
    int[] dp = new int[n];
   //有的題目則是如下形式的
   int[] dp = new int[n+1];
  }

我覺(jué)得要想對(duì)一個(gè)dp狀態(tài)轉(zhuǎn)移方程理解更深刻缩筛,就首先對(duì)dp數(shù)組的定義理解透徹,包括dp數(shù)組長(zhǎng)度是+1還是-1堡称。
體會(huì)到了這一點(diǎn)瞎抛,不管你看別人的題解還是自己想dp方程都能在短時(shí)間內(nèi)把握要點(diǎn)。

拿這道題來(lái)說(shuō)却紧,狀態(tài)方程為 dp[i][j]桐臊,i, j 分別對(duì)應(yīng) word1胎撤,word2兩個(gè)字符串的下標(biāo)。
dp數(shù)組意思為:將 word1 i 個(gè)字符 替換成 word2 j個(gè)字符断凶,所需的最少步數(shù)伤提。
注意這里的 “前” 字,理解了這個(gè)字认烁,整個(gè)dp轉(zhuǎn)移方程你就掌握了最精髓的一部分肿男。
對(duì)于本題來(lái)說(shuō):

  int len1 = word1.length();
  int len2 = word2.length();
  /** 
    如果定義成 len1 len2,就會(huì)有問(wèn)題却嗡。數(shù)組遍歷的下標(biāo)范圍是 [0...len1-1]  [0...len2-1 ]
    假設(shè)此時(shí)有這樣兩個(gè)單詞 
    word1:  "abcde"
    word2:  "abc"
    同時(shí)遍歷到兩個(gè)字符串的最后一個(gè)位置時(shí)舶沛,根據(jù)dp數(shù)組定義可得:
    word1的前4個(gè)字符 變成 word2的前2個(gè)字符,所需的步數(shù)稽穆。
    這時(shí)問(wèn)題出現(xiàn)了冠王,len(word1) = 5, len(word2) = 3, 遍歷到最后一個(gè)位置是不是都少了1個(gè)字符舌镶,因?yàn)槭窍聵?biāo)所以取不到完整數(shù)組長(zhǎng)度柱彻。正確的定義應(yīng)該是:word1的前5個(gè)字符 變成 word2的前三個(gè)字符,所需的最小步數(shù)餐胀。
因此正確的定義是:  int[][]  dp = new int[len1+1][len2+1];
  **/
 int[][] dp = new int[len1][len2];

步入正題哟楷,構(gòu)建dp狀態(tài)方程
1. 插入一個(gè)字符
2. 刪除一個(gè)字符
3. 替換一個(gè)字符
三個(gè)操作分別對(duì)應(yīng)三個(gè)dp狀態(tài)方程。根據(jù)dp數(shù)組定義否灾,word1 i 個(gè)字符 替換成 word2 j個(gè)字符卖擅,所需的最少步數(shù)。
假設(shè)現(xiàn)在遍歷到了 word1的 i 位置墨技,word2的 j 位置惩阶。

  1. 如果 word1[i] == word2[j],則 dp[i][j] = dp[i-1][j-1] + 0扣汪,因?yàn)楫?dāng)前位置兩個(gè)字符相等断楷,不需要任何操作,狀態(tài)可直接由前一個(gè)狀態(tài)轉(zhuǎn)移而來(lái)崭别。
  2. 如果 word1[i] == word2[j]冬筒,要分三種情況討論,即茅主,是插入 刪除 or 替換
 word1:  - - - s
 word2:  - - e
word1[3] != word2[2]
插入:  
     在word1后插入一個(gè)字符 e, 即 word1:- - - s e舞痰,就可以與word2最后一個(gè)字符匹配了。word1插入一個(gè)字符 e 之后诀姚,與word2最后一個(gè)位置的 相抵消了响牛。
這時(shí)的狀態(tài)方程為: dp[i][j] = dp[i][j-1] + 1。為什么 是 j-1? 因?yàn)?i 插入的那個(gè)字符與 j  位置的字符抵消了。
刪除:
     因?yàn)?i 位置 與 j  位置 不匹配娃善,這時(shí)也可以選擇將 i  位置刪除论衍,有的人可能會(huì)問(wèn),既然不匹配聚磺,為什么不刪除 j 位置呢? 這時(shí)回到dp數(shù)組的本身含義:將 word1前 i 個(gè) 替換成word2 前j個(gè)
。 前者 即 word1屬于主動(dòng)做事情的一方炬丸,所以刪除 i  位置瘫寝,這時(shí)狀態(tài)方程為:  dp[i][j] = dp[i-1][j] + 1。加1表示稠炬,進(jìn)行了一次刪除操作焕阿。
插入:
    可將 word1的  i 位置字符替換成  j 位置的e, 這樣兩個(gè)位置就匹配了:dp[i][j] = dp[i-1][j-1] + 1首启。

具體細(xì)節(jié)參見(jiàn)源碼:

public int minDistance(String word1, String word2) {
        int len1 = word1.length();
        int len2 = word2.length();
        
        if(len1*len2 == 0)
            return len1+len2;
        
        int dp[][] = new int[len1+ 1][len2+1];
        
        /**
         從有到無(wú)
         初始化條件:將word1的前 i個(gè)字符替換成word2的 前0個(gè)字符所需要的步數(shù)
         即:在word1中進(jìn)行刪除操作
        **/
        for(int i = 0; i < len1 + 1; i++) {
            dp[i][0] = i;
        }
        //添加操作  從無(wú)到有 
        for(int j = 0; j < len2 + 1; j++) {
            dp[0][j] = j;
        }
        
        for(int i = 1; i < len1 + 1; i++) {
            for(int j = 1; j < len2 + 1; j++) {
                int insert = dp[i][j-1] + 1;
                int delete = dp[i-1][j] + 1;
                int replace = dp[i-1][j-1];
                
                if(word1.charAt(i-1) != word2.charAt(j-1)) {
                    replace += 1;
                }
                dp[i][j] = Math.min(insert, Math.min(delete, replace));
            }
        }
        return dp[len1][len2];
        
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末暮屡,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子毅桃,更是在濱河造成了極大的恐慌褒纲,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,607評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钥飞,死亡現(xiàn)場(chǎng)離奇詭異莺掠,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)读宙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)彻秆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人结闸,你說(shuō)我怎么就攤上這事唇兑。” “怎么了桦锄?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,960評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵扎附,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我察纯,道長(zhǎng)帕棉,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,750評(píng)論 1 294
  • 正文 為了忘掉前任饼记,我火速辦了婚禮香伴,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘具则。我一直安慰自己即纲,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布博肋。 她就那樣靜靜地躺著低斋,像睡著了一般蜂厅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上膊畴,一...
    開(kāi)封第一講書(shū)人閱讀 51,604評(píng)論 1 305
  • 那天掘猿,我揣著相機(jī)與錄音,去河邊找鬼唇跨。 笑死稠通,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的买猖。 我是一名探鬼主播改橘,決...
    沈念sama閱讀 40,347評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼玉控!你這毒婦竟也來(lái)了飞主?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,253評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤高诺,失蹤者是張志新(化名)和其女友劉穎碌识,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體懒叛,經(jīng)...
    沈念sama閱讀 45,702評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡丸冕,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了薛窥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片胖烛。...
    茶點(diǎn)故事閱讀 40,015評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖诅迷,靈堂內(nèi)的尸體忽然破棺而出佩番,到底是詐尸還是另有隱情,我是刑警寧澤罢杉,帶...
    沈念sama閱讀 35,734評(píng)論 5 346
  • 正文 年R本政府宣布趟畏,位于F島的核電站,受9級(jí)特大地震影響滩租,放射性物質(zhì)發(fā)生泄漏赋秀。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評(píng)論 3 330
  • 文/蒙蒙 一律想、第九天 我趴在偏房一處隱蔽的房頂上張望猎莲。 院中可真熱鬧,春花似錦技即、人聲如沸著洼。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,934評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)身笤。三九已至豹悬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間液荸,已是汗流浹背瞻佛。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,052評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留莹弊,地道東北人涤久。 一個(gè)月前我還...
    沈念sama閱讀 48,216評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像忍弛,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子考抄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評(píng)論 2 355