【leetCode-DP】 72. 編輯距離

給定兩個單詞 word1 和 word2,計算出將 word1 轉換成 word2 所使用的最少操作數 。

你可以對一個單詞進行如下三種操作:

插入一個字符
刪除一個字符
替換一個字符
示例 1:

輸入: word1 = "horse", word2 = "ros"
輸出: 3
解釋: 
horse -> rorse (將 'h' 替換爲 'r')
rorse -> rose (刪除 'r')
rose -> ros (刪除 'e')
示例 2:

輸入: word1 = "intention", word2 = "execution"
輸出: 5
解釋: 
intention -> inention (刪除 't')
inention -> enention (將 'i' 替換爲 'e')
enention -> exention (將 'n' 替換爲 'x')
exention -> exection (將 'n' 替換爲 'c')
exection -> execution (插入 'u')

依然按照步驟來:

1).定義一個能夠清楚描述最優子問題的數組(明確數組描述的含義)。

2).找出數組元素之間的關係式(狀態轉移方程)

3).找出初始值

 

1).dp[i][j] 代表第一個單詞的第i個字符變換到第二個單詞的第j個字符需要最少的步驟

2).狀態轉移方程 :

    當兩個字符串中的某個字符相等時既 char1[i] == char2[j] dp[i][j] = dp[i-1][j-1]

    否則,需要通過新增、修改、刪除等操作轉換 dp[i][j] =  min(dp[i-1][j-1],min(dp[i-1][j],dp[i][j-1]))+1  { PS:其中dp[i-1][j-1]表示dp[i][j] 由修改的狀態轉移過來 ,dp[i-1][j] 表示第一個單詞要刪除 ,dp[i][j-1]表示第一個單詞 新增}

3)初始化

        for(int i = 0;i <= row;i++)
                dp[i][0] = i;
        for(int i = 0;i <= col;i++)
            dp[0][i] = i;

 

code:

    public static int minDistance(String word1, String word2) {
        int row = word1.length();
        int col = word2.length();
        char[] char1 = word1.toCharArray();
        char[] char2 = word2.toCharArray();
        if (row == 0) {
            return col;
        }
        if (col == 0) {
            return row;
        }
        int dp[][] = new int[row + 2][col + 2]; //當字符串 word1 的長度爲 i,字符串 word2 的長度爲 j 時,將 word1 轉化爲 word2 所使用的最少操作次數爲 dp[i] [j]。
        for(int i = 0;i <= row;i++)
            dp[i][0] = i;
        for(int i = 0;i <= col;i++)
            dp[0][i] = i;
        for(int i = 1;i <= row;i++) {
            for(int j = 1;j <= col;j++) {
                //字符串相同的話向下 無累加 移動
                if(char1[i-1] == char2[j-1]) {
                    dp[i][j] = dp[i-1][j-1];
                } else {
                    /**
                     * 修改、增加、刪除
                     */
                    // 修改
                    int xg = dp[i - 1][j-1] ;
                    // 刪除
                    int sc = dp[i-1][j] ;
                    // 新增
                    int xz = dp[i][j-1] ;
                    dp[i][j] = Math.min(xg,Math.min(sc,xz)) + 1;
                }
            }
        }
        for(int i = 0;i <= row ;i++){
            for(int j = 0;j <= col;j++){
                System.out.print(dp[i][j] +" ");
            }
            System.out.println();
        }
        return dp[row][col];
    }

 

優化

同我們之前做的DP類似,在求解的時候發現並不需要保存整個矩陣的狀態,只需要保存當前行對應的列即可。但是不同之處在於在當前位置dp[i][j]的左上角還有一個狀態,爲了同時保存左上角的狀態 解決的辦法是使用兩個變量temppre保存,在更新之前,使用temp保存dp[j],然後dp[j]要被更新,然後將dp[j]賦值給pre,下次遞推的時候,左上角的值就是pre

 

     public int minDistance(String word1, String word2) {
        char[] chs1 = word1.toCharArray();
        char[] chs2 = word2.toCharArray();
        int[] dp = new int[word2.length() + 1]; //注意要 + 1因爲一開始是空串
        for (int j = 0; j < word2.length() + 1; j++) dp[j] = j;
        char c1, c2;
        int temp, pre;
        for (int i = 1; i < word1.length() + 1; i++) {
            pre = dp[0]; //上一排的
            dp[0] = i;   //這一排新dp[0]
            for (int j = 1; j < word2.length() + 1; j++) {
                c1 = word1.charAt(i - 1);
                c2 = word2.charAt(j - 1); //注意下標對應的關係
                temp = dp[j];  // 先要保存,因爲等下就更新了
                dp[j] = c1 == c2 ? pre : min(dp[j], dp[j - 1], pre) + 1;
                pre = temp;      //記得先保存一下左上角的 pre的值(在二維的dp中就是dp[i-1][j-1])
            }
        }
        return dp[word2.length()];
    }

加強問題(ic,dc,rc)


題目:
給定兩個字符串str1和str2,再給定三個整數ic、dc和rc,分別代表插入、刪除和替換一個字符的代價,返回將str1編輯成str2的最小代價。

這個問題是上面問題的加強版,不同的地方在於這裏三個編輯的代價不同,所以我們要更加的清楚是哪個編輯的更新:

code:

class Solution {

    /**
     * 給定的  ic,  dc  ,rc  分別代表的是 插入,刪除 取代的代價
     *  普通二維dp
     */
    public int minDistance(String word1, String word2, int ic, int dc, int rc) {
        char[] chs1 = word1.toCharArray();
        char[] chs2 = word2.toCharArray();

        int[][] dp = new int[chs1.length + 1][chs2.length + 1];

        for (int i = 0; i < chs1.length + 1; i++) dp[i][0] = i * dc; //chs1是   , chs2是""   ->要刪除
        for (int j = 0; j < chs2.length + 1; j++) dp[0][j] = j * ic; //chs1 是"" 轉換成chs2   -> 要添加

        for (int i = 1; i < chs1.length + 1; i++) {
            for (int j = 1; j < chs2.length + 1; j++) {
                dp[i][j] = chs1[i - 1] == chs2[j - 1] ? dp[i - 1][j - 1]
                        : min(dp[i][j - 1] + ic, dp[i - 1][j] + dc, dp[i - 1][j - 1] + rc); //dp[i-1][j]代表的是刪除了 chs1[i-1] 所以加上dc
            }
        }
        return dp[chs1.length][chs2.length];
    }

    public int min(int a, int b, int c) {
        return Math.min(Math.min(a, b), c);
    }
    
}

reference : https://blog.csdn.net/zxzxzx0119/article/details/82054807

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