LeetCode刷題系列——編輯距離

LeetCode72編輯距離

在這裏插入圖片描述

思路

  • dp[i][j] 表示 word1 到 i 位置 轉換成 word2 到 j 位置需要最少的步數。
  • 當 word1[i] == word2[j],dp[i][j] = dp[i-1][j-1];
  • 當 word1[i] != word2[j],dp[i][j] = min(dp[i-1][j-1],dp[i-1][j],dp[i][j-1])+1;

其中的dp[i-1][j-1]表示代替操作,dp[i-1][j]表示刪除操作,dp[i][j-1]表示插入操作。

以上的替換、刪除、插入操作都是對 word1 來說的。

代碼(自頂向下)暴力遞歸

package leetcode;

/**
 * @author god-jiang
 * @date 2020/2/19  17:08
 */
public class MinDistance {
    public int minDistance(String word1, String word2) {
        int length1 = word1.length();
        int length2 = word2.length();
        return min(word1, word2, length1, length2);
    }

    public int min(String word1, String word2, int i, int j) {
        //base case
        if (i == 0) {
            return j;
        } else if (j == 0) {
            return i;
        } else if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
            return min(word1, word2, i - 1, j - 1);
        } else {
            int len1 = min(word1, word2, i - 1, j - 1) + 1;
            int len2 = min(word1, word2, i - 1, j) + 1;
            int len3 = min(word1, word2, i, j - 1) + 1;
            return Math.min(Math.min(len1, len2), len3);
        }
    }
}

因爲有重複計算的過程,而且無後效性。即一個函數f(n)一旦確定,那麼之後就可以直接調用它的值,不用再關心f(n)的計算過程了,這個就是無後效性。

代碼(自底向上)動態規劃

package leetcode;

/**
 * @author god-jiang
 * @date 2020/2/19  17:08
 */
public class MinDistance {
        public int minDistance(String word1, String word2) {
            int length1 = word1.length();
            int length2 = word2.length();
            int[][] dp = new int[length1 + 1][length2 + 1];
            //初始化base case
            for (int i = 1; i <= length1; i++) {
                dp[i][0] = dp[i - 1][0] + 1;
            }
            for (int j = 1; j <= length2; j++) {
                dp[0][j] = dp[0][j - 1] + 1;
            }
            //填充二維數組dp表
            for (int i = 1; i <= length1; i++) {
                for (int j = 1; j <= length2; j++) {
                    if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
                        dp[i][j] = dp[i - 1][j - 1];
                    } else {
                        dp[i][j] = Math.min(Math.min(dp[i - 1][j - 1], dp[i - 1][j]), dp[i][j - 1]) + 1;
                    }
                }
            }
            return dp[length1][length2];
        }
}

基本上動態規劃都是暴力遞歸改過來的。最長公共子序列、湊硬幣等都是通過這種方法寫出動態規劃的狀態轉移方程。沒有必要去背狀態轉移方程式,也不用一直想着最優子結構等名詞。最需要寫出暴力遞歸,觀察能不能改動態規劃即可。
遞歸就是“暴力的枚舉”,期間可能包括一大堆重複計算,而且一般時間複雜度都是O(2^N)。改成動態規劃就是“聰明的枚舉”,可以省掉重複的計算。

PS:最後看完還覺得暈的話,我建議是再看看我總結的動態規劃套路吧,應該對你會有所收穫的。
動態規劃套路文章的鏈接:動態規劃的高度套路

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章