動態規劃算法--字符串轉換最小代價問題

題目描述

給定兩個字符串str1和str2,再給定三個整數ic,dc,rc,分別代表插入、刪除、替換一個字符的代價,返回將str1編輯成str2的最小代價。
舉例:
str1="abc"   str2="adc"  ic=5    dc=3   rc=2,從"abc"編輯到"adc"把b替換成d代價最小,爲2;
str1="abc"   str2="adc"  ic=5    dc=3   rc=10,從"abc"編輯到"adc",先刪除b再插入d代價最小,爲8;

分析

假設str1長度爲M[0.....M-1],str2長度爲N[0.......N-1],dp大小爲(M+1)*(N+1);

dp[i][j]表示str1[0......i-1]編輯成str2[0......j-1]的最小編輯代價,dp大小爲(M+1)*(N+1)是爲了從空串開始計算,即dp[0][0]表示空串編輯到空串的最小編輯代價。
如何生成dp[][]:

  1. dp[0][0]表示空串編輯成空串,故dp[0][0]=0;
  2. 求第一行dp[0][j],空串編輯成str2[0....j-1],則dp[0][j]=ic*j;
  3. 求第一列dp[i][0],str1[0......i-1]編輯成空串,則dp[i][0]=dc*i;
  4. 求dp[i][j],即str1[0....i-1]編輯成str2[0.....j-1],四種可能的途徑:
  • str1[0....i-1]先編輯成str2[0.....j-2],再由str2[0.....j-2]到str2[0.....j-1],即dp[i][j-1]+ic;
  • str1[0....i-1]先編輯成str1[0.....i-2],再由str1[0.....i-2]到str2[0.....j-1],即dc+dp[i-1][j];
  • 如果str1[i-1]==str2[j-1],則dp[i][j]=dp[i-1][j-1];啥都不用幹(cost=0)
  • 如果str1[i-1]!=str2[j-1],則dp[i][j]=dp[i-1][j-1]+rc;

總之dp[i][j]肯定是經過增、刪、改某一項操作後、或者啥都不用幹(cost=0)生成的

import org.apache.commons.lang3.RandomStringUtils;
import org.junit.Test;

/**
 * Author: zxh
 * Date: 2019/2/21 16:49
 * Email: 
 * Desc:
 */
public class TestDynamicPlanTransferStringLeastCost {

    private static final int aLen = 5;
    private static final int bLen = 5;
    private static final int insertCost = 5;
    private static final int deleteCost = 6;
    private static final int replaceCost = 7;


    @Test
    public void test() {
        String source = RandomStringUtils.random(aLen, false, true);
        String target = RandomStringUtils.random(bLen, false, true);

//        String source = "123";
//        String target = "124";

        System.out.println("source字符串:" + source);
        System.out.println("target字符串:" + target);
        //dp[i][j]代表a前i個(0個,1個...不是index值)字符,調整到b前j個(0個,1個...不是index值)字符的最小代價
        int[][] dp = new int[aLen + 1][bLen + 1];

        //源字符串是空字符串時,不是index=0的元素時
        for (int j = 0; j <= bLen; j++) {
            dp[0][j] = j * insertCost;
        }
        //目標字符串是空字符串,不是index=0的元素時
        for (int i = 0; i < aLen + 1; i++) {
            dp[i][0] = i * deleteCost;
        }

        for (int i = 0; i < aLen; i++) {
            for (int j = 0; j < bLen; j++) {
                char charA = source.charAt(i);
                char charB = target.charAt(j);
                if (charA == charB) {
                    dp[i + 1][j + 1] = dp[i][j];
                } else {
                    dp[i + 1][j + 1] = Math.min(Math.min(dp[i + 1][j] + insertCost, dp[i][j + 1] + deleteCost), dp[i][j] + replaceCost);
                }
            }
        }

        System.out.println("開始打印dp:");
        for (int i = 0; i <= aLen; i++) {
            for (int j = 0; j <= bLen; j++) {
                System.out.print(dp[i][j] + ",");
            }
            System.out.println();
        }
    }
}

結果示例

source字符串:02118
target字符串:89406
開始打印dp:
0,5,10,15,20,25,
6,7,12,17,15,20,
12,13,14,19,21,22,
18,19,20,21,26,28,
24,25,26,27,28,33,
30,24,29,33,34,35,

Process finished with exit code 0

 

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