1. 程式人生 > 其它 >java中字串拼接

java中字串拼接

最小編輯代價

題目:最小編輯代價

《程式設計師程式碼面試指南》第68題 P230 難度:校★★★☆

同樣分為經典動態規劃經典動態規劃結合空間壓縮兩種方法。

經典動態規劃方法:

同樣建立二維動態規劃表,大小為(M+1)×(N+1)的矩陣dp,dp[i][j]的值代表str1[0..i-1]編輯成str2[0..j-1]的最小代價。

dp矩陣每個位置的值計算如下:

  1. dp[0][0]=0
  2. 第一列dp[i][0]=dc*i
  3. 第一行dp[0][j]=ic*j
  4. 其它位置dp[i][j],取以下四種可能的值中的最小值
    1. dc+dp[i-1][j]
    2. dp[i][j-1]+ic
    3. 如果str1[i-1]!=str2[j-1]
      dp[i-1][j-1]+rc
    4. 如果str1[i-1]==str2[j-1]dp[i-1][j-1]
public int minCost1(String str1, String str2, int ic, int dc, int rc) {
    if (str1 == null || str2 == null) {
        return 0;
    }
    char[] chs1 = str1.toCharArray();
    char[] chs2 = str2.toCharArray();
    int row = chs1.length + 1;
    int col = chs2.length + 1;
    int[][] dp = new int[row][col];
    for (int i = 1; i < row; i++) {
        dp[i][0] = dc * i;
    }
    for (int j = 1; j < col; j++) {
        dp[0][j] = ic * j;
    }
    for (int i = 1; i < row; i++) {
        for (int j = 1; j < col; j++) {
            if (chs1[i - 1] == chs2[j - 1]) {
                dp[i][j] = dp[i - 1][j - 1];
            } else {
                dp[i][j] = dp[i - 1][j - 1] + rc;
            }
            dp[i][j] = Math.min(dp[i][j], dp[i][j - 1] + ic);
            dp[i][j] = Math.min(dp[i][j], dp[i - 1][j] + dc);
        }
    }
    return dp[row - 1][col - 1];
}

經典動態規劃結合空間壓縮方法:

與“矩陣的最小路徑和”問題不同,本題dp[i][j]依賴dp[i-1][j]、dp[i][j-1]、dp[i-1][j-1]。還需要一個變數儲存dp[j-1]沒更新之前的值,即dp[i-1][j-1]

此外,選擇str1和str2中長度較的一個作為對應的字串,長度較的一個作為對應的字串。如果str1做了對應的字串,把插入代價ic和刪除代價dc交換一下即可。

public int minCost2(String str1, String str2, int ic, int dc, int rc) {
    if (str1 == null || str2 == null) {
        return 0;
    }
    char[] chs1 = str1.toCharArray();
    char[] chs2 = str2.toCharArray();
    char[] longs = chs1.length >= chs2.length ? chs1 : chs2;
    char[] shorts = chs1.length < chs2.length ? chs1 : chs2;
    if (chs1.length < chs2.length) { // str2較長就交換ic和dc的值
        int tmp = ic;
        ic = dc;
        dc = tmp;
    }
    int[] dp = new int[shorts.length + 1];
    for (int i = 1; i <= shorts.length; i++) {
        dp[i] = ic * i;
    }
    for (int i = 1; i <= longs.length; i++) {
        int pre = dp[0]; // pre代表左上角的值ֵ
        dp[0] = dc * i;
        for (int j = 1; j <= shorts.length; j++) {
            int tmp = dp[j]; // dp[j]沒更新前先儲存下來
            if (longs[i - 1] == shorts[j - 1]) {
                dp[j] = pre;
            } else {
                dp[j] = pre + rc;
            }
            dp[j] = Math.min(dp[j], dp[j - 1] + ic);
            dp[j] = Math.min(dp[j], tmp + dc);
            pre = tmp; // pre變成dp[j]沒更新前的值
        }
    }
    return dp[shorts.length];
}