Java動(dòng)態(tài)規(guī)劃之編輯距離問(wèn)題示例代碼
動(dòng)態(tài)規(guī)劃過(guò)程是:每次決策依賴于當(dāng)前狀態(tài),又隨即引起狀態(tài)的轉(zhuǎn)移。一個(gè)決策序列就是在變化的狀態(tài)中產(chǎn)生出來(lái)的,所以,這種多階段最優(yōu)化決策解決問(wèn)題的過(guò)程就稱為動(dòng)態(tài)規(guī)劃。
動(dòng)態(tài)規(guī)劃實(shí)際上是一類(lèi)題目的總稱,并不是指某個(gè)固定的算法。動(dòng)態(tài)規(guī)劃的意義就是通過(guò)采用遞推(或者分而治之)的策略,通過(guò)解決大問(wèn)題的子問(wèn)題從而解決整體的做法。動(dòng)態(tài)規(guī)劃的核心思想是巧妙的將問(wèn)題拆分成多個(gè)子問(wèn)題,通過(guò)計(jì)算子問(wèn)題而得到整體問(wèn)題的解。而子問(wèn)題又可以拆分成更多的子問(wèn)題,從而用類(lèi)似遞推迭代的方法解決要求的問(wèn)題。問(wèn)題描述:
對(duì)于序列S和T,它們之間的距離定義為:對(duì)二者其一進(jìn)行幾次以下操作:1,刪除一個(gè)字符;2,插入一個(gè)字符;3,改變一個(gè)字符.每進(jìn)行一次操作,計(jì)數(shù)增加1.將S和T變?yōu)橄嗟刃蛄械淖钚∮?jì)數(shù)就是兩者的編輯距離(editdistance)或者叫相似度.請(qǐng)給出相應(yīng)算法及其實(shí)現(xiàn).
分析:
假設(shè)序列S和T的長(zhǎng)度分別為m和n,兩者的編輯距離表示為edit[m][n].則對(duì)序列進(jìn)行操作時(shí)存在以下幾種情況:
a,當(dāng)S和T的末尾字符相等時(shí),對(duì)末尾字符不需要進(jìn)行上述定義操作中(亦即"編輯")的任何一個(gè),也就是不需要增加計(jì)數(shù).則滿足條件:edit[m][n]=edit[m-1][n-1].
b,當(dāng)S和T的末尾字符不相等時(shí),則需要對(duì)兩者之一的末尾進(jìn)行編輯,相應(yīng)的計(jì)數(shù)會(huì)增加1.
b1,對(duì)S或T的末尾進(jìn)行修改,以使之與T或S相等,則此時(shí)edit[m][n]=edit[m-1][n-1]+1;
b2,刪除S末尾的元素,使S與T相等,則此時(shí)edit[m][n]=edit[m-1][n]+1;
b3,刪除T末尾的元素,使T與S相等,則此時(shí)edit[m][n]=edit[m][n-1]+1;
b4,在S的末尾添加T的尾元素,使S和T相等,則此時(shí)S的長(zhǎng)度變?yōu)閙+1,但是此時(shí)S和T的末尾元素已經(jīng)相等,只需要比較S的前m個(gè)元素與T的前n-1個(gè)元素,所以滿足edit[m][n]=edit[m][n-1]+1;
b5,在T的末尾添加S的尾元素,使T和S相等,此時(shí)的情況跟b4相同,滿足edit[m][n]=edit[m-1][n]+1;
c,比較特殊的情況是,當(dāng)S為空時(shí),edit[0][n]=n;而當(dāng)T為空時(shí),edit[m][0]=m;這個(gè)很好理解,例如對(duì)于序列""和"abc",則兩者的最少操作為3,即序列""進(jìn)行3次插入操作,或者序列"abc"進(jìn)行3次刪除操作.
所以,以上我們不難推出編輯距離的動(dòng)態(tài)規(guī)劃方程為:
所以, 字符串編輯距離的動(dòng)態(tài)規(guī)劃算法的遞歸實(shí)現(xiàn)可以用如下的Java代碼表示:
public static int editDistance(String a, String b) { if (a == null || b == null) { return -1; } return editDistance(a, a.length() - 1, b, b.length() - 1); } public static int editDistance(String a, int m, String b, int n) { if (m < 0 || n < 0) { return 1; } else if (a.charAt(m) == b.charAt(n)) { return editDistance(a, m - 1, b, n - 1); } else { return Math.min(Math.min(editDistance(a, m - 1, b, n) + 1, editDistance(a, m, b, n - 1) + 1), editDistance(a, m - 1, b, n - 1) + 1); } }
UPDATE:
同時(shí), 由編輯距離的動(dòng)態(tài)規(guī)劃方程我們可以看出, edit[m][n]可以由edit[m - 1][n - 1], edit[m - 1][n], edit[m][n - 1]得出, 而如果edit是一個(gè)二維數(shù)組的話, edit[m][n]可以由它的上, 左, 左上三個(gè)位置的元素通過(guò)條件判斷得出. 亦即我們可以通過(guò)遍歷二維數(shù)組, 然后通過(guò)回溯來(lái)計(jì)算當(dāng)前值.
例如對(duì)于字符串S = "sailn"和T = "failing", 對(duì)二維數(shù)組進(jìn)行初始化為:
m\n | f | a | i | l | i | n | g | |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
s | 1 | 1 | ||||||
a | 2 | |||||||
i | 3 | |||||||
l | 4 | |||||||
n | 5 |
因?yàn)镾[0] = s, T[0] = f, 則S[0] != T[0], 則對(duì)應(yīng)于上述二維矩陣, edit[1][1] = min(edit[0][0], edit[0][1], edit[1][0]) + 1即edit[1][1] = min(0, 1, 1) + 1即edit[1][1] = 0 + 1 = 1.
m\n | f | a | i | l | i | n | g | |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
s | 1 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
a | 2 | 2 | 1 | |||||
i | 3 | |||||||
l | 4 | |||||||
n | 5 |
而對(duì)于S[1] = a, T[1] = a, S[1] = T[1], 則對(duì)應(yīng)于二維矩陣, edit[2][2] = edit[1][1], 所以edit[2][2] = 1. 所以按照這種規(guī)則, 將上述二維矩陣填滿則如下:
m\n | f | a | i | l | i | n | g | |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
s | 1 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
a | 2 | 2 | 1 | 2 | 3 | 4 | 5 | 6 |
i | 3 | 3 | 2 | 1 | 2 | 3 | 4 | 5 |
l | 4 | 4 | 3 | 2 | 1 | 2 | 3 | 4 |
n | 5 | 5 | 4 | 3 | 2 | 2 | 2 | 3 |
所以, 兩者的編輯距離為edit[m][n] = edit[5][7] = 3.
所以, 按照上述思路即動(dòng)態(tài)規(guī)劃的回溯解法的Java版本可以如下進(jìn)行:
public static int editDistance(String a, String b) { if (a == null || b == null) { return -1; } int[][] matrix = new int[a.length() + 1][b.length() + 1]; for (int i = 0; i < a.length() + 1; i++) { for (int j = 0; j < b.length() + 1; j++) { if (i == 0) { matrix[i][j] = j; } else if (j == 0) { matrix[i][j] = i; } else { if (a.charAt(i - 1) == b.charAt(j - 1)) { matrix[i][j] = matrix[i - 1][j - 1]; } else { matrix[i][j] = 1 + Math.min(Math.min(matrix[i - 1][j], matrix[i][j - 1]), matrix[i - 1][j - 1]); } } } } return matrix[a.length()][b.length()]; }
總結(jié)
以上就是本文關(guān)于Java動(dòng)態(tài)規(guī)劃之編輯距離問(wèn)題示例代碼的全部?jī)?nèi)容,希望對(duì)大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關(guān)專(zhuān)題,如有不足之處,歡迎留言指出。
- Java動(dòng)態(tài)規(guī)劃之硬幣找零問(wèn)題實(shí)現(xiàn)示例
- Java使用動(dòng)態(tài)規(guī)劃算法思想解決背包問(wèn)題
- Java實(shí)現(xiàn)動(dòng)態(tài)規(guī)劃背包問(wèn)題
- java背包問(wèn)題動(dòng)態(tài)規(guī)劃算法分析
- 背包問(wèn)題-動(dòng)態(tài)規(guī)劃java實(shí)現(xiàn)的分析與代碼
- java動(dòng)態(tài)規(guī)劃算法——硬幣找零問(wèn)題實(shí)例分析
- Java面試之動(dòng)態(tài)規(guī)劃與組合數(shù)
- Java動(dòng)態(tài)規(guī)劃之硬幣找零問(wèn)題實(shí)現(xiàn)代碼
- Java動(dòng)態(tài)規(guī)劃之丑數(shù)問(wèn)題實(shí)例講解
相關(guān)文章
Java實(shí)現(xiàn)鏈表的常見(jiàn)操作算法詳解
這篇文章主要介紹了Java實(shí)現(xiàn)鏈表的常見(jiàn)操作算法詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09Java?熱更新?Groovy?實(shí)踐及踩坑指南(推薦)
Apache的Groovy是Java平臺(tái)上設(shè)計(jì)的面向?qū)ο缶幊陶Z(yǔ)言,這門(mén)動(dòng)態(tài)語(yǔ)言擁有類(lèi)似Python、Ruby和Smalltalk中的一些特性,可以作為Java平臺(tái)的腳本語(yǔ)言使用,這篇文章主要介紹了Java?熱更新?Groovy?實(shí)踐及踩坑指南,需要的朋友可以參考下2022-09-09MybatisPlus使用Mybatis的XML的動(dòng)態(tài)SQL的功能實(shí)現(xiàn)多表查詢
本文主要介紹了MybatisPlus使用Mybatis的XML的動(dòng)態(tài)SQL的功能實(shí)現(xiàn)多表查詢,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-11-11springboot升級(jí)到j(luò)dk21最新教程(2023年)
你還在使用jdk8?快來(lái)看看最新出爐的SpringBoot+jdk21如何使用,下面這篇文章主要給大家介紹了關(guān)于springboot升級(jí)到j(luò)dk21的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-10-10Java POI讀取excel中數(shù)值精度損失問(wèn)題解決
這篇文章主要介紹了Java POI讀取excel中數(shù)值精度損失問(wèn)題解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04LinkedList學(xué)習(xí)示例模擬堆棧與隊(duì)列數(shù)據(jù)結(jié)構(gòu)
這篇文章主要介紹了LinkedList學(xué)習(xí)示例,模擬一個(gè)堆棧與隊(duì)列數(shù)據(jù)結(jié)構(gòu),大家參考使用吧2014-01-01springcloud 服務(wù)降級(jí)的實(shí)現(xiàn)方法
這篇文章主要介紹了springcloud 服務(wù)降級(jí)的實(shí)現(xiàn)方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12