字符串上的简单动态规划
因?yàn)閿?shù)據(jù)結(jié)構(gòu)快學(xué)串了,以前又做過(guò)一些字符串dp的題,今天突然就想把它們寫在一起吧。
?
直接開始
問(wèn)題1:給兩個(gè)字符串,求最長(zhǎng)公共子串
問(wèn)題2:給兩個(gè)字符串,求最長(zhǎng)公共子序列
問(wèn)題3:給一個(gè)字符串,求最長(zhǎng)回文子串
問(wèn)題4:給一個(gè)字符串,求最長(zhǎng)回文子序列
問(wèn)題5:給一個(gè)字符串,求將這個(gè)字符串變?yōu)榛匚拇枰迦氲淖钌僮址麄€(gè)數(shù)。
問(wèn)題6:最小編輯代價(jià)
問(wèn)題7:判斷交錯(cuò)組成
問(wèn)題8:給一個(gè)字符串,求最長(zhǎng)相同前后綴
問(wèn)題9:給串a(chǎn)和b,判斷b是否在a中出現(xiàn),若出現(xiàn)輸出第一次出現(xiàn)的位置。
問(wèn)題1:給兩個(gè)字符串,求最長(zhǎng)公共子串
串和序列的區(qū)別之前提到過(guò),串連續(xù),序列可以不連續(xù)
如果連續(xù)那就比較好想了,定義DP(i,j)的含義是兩個(gè)串分別以下標(biāo)i和j結(jié)尾最長(zhǎng)的公共子串長(zhǎng)度。
如果a[i]=b[j],那DP(i,j)=DP(i-1,j-1)+1,如果DP(i-1,j-1)=0,還是同樣的操作,僅僅是之前不能構(gòu)成而已,那i和j結(jié)尾的最長(zhǎng)一定是1了。
如果a[i]!=b[j],DP(i,j)=0,因?yàn)槎x是以i和j結(jié)尾,一定不存在這樣的相同子串。
初始化:先打第一行和第一列,相同為1,不同為0即可。
問(wèn)題2:給兩個(gè)字符串,求最長(zhǎng)公共子序列
舉例:
S1=“ABCBDAB.”
S2=“BABCBD.”
可以看出他們的最長(zhǎng)公共子序列有ABCB,ABCD ,BCBD等,長(zhǎng)度為4.
Dp(i,j)表示S的前i位與T的前j位的最長(zhǎng)公共子串長(zhǎng)度。
如果a[i]=b[j],那DP(i,j)=DP(i-1,j-1)+1
否則,DP(i,j)=max(DP(i-1,j),DP(i,j-1))
仔細(xì)體會(huì),手模擬幾個(gè)就懂了。第一次想可能沒(méi)那么容易
拓展:三個(gè)字符串:純dp做
注:多個(gè)字符串要其他做法,以后數(shù)據(jù)結(jié)構(gòu)學(xué)到串了或者樹了再寫。
?
問(wèn)題3:給一個(gè)字符串,求最長(zhǎng)回文子串
馬拉車算法,我確實(shí)覺(jué)得也是動(dòng)態(tài)規(guī)劃思想,跳轉(zhuǎn)看詳細(xì)介紹吧
https://blog.csdn.net/hebtu666/article/details/79822584
?
問(wèn)題4:給一個(gè)字符串,求最長(zhǎng)回文子序列
對(duì)于任意字符串,如果頭尾字符相同,那么字符串的最長(zhǎng)子序列等于去掉首尾的字符串的最長(zhǎng)子序列加上首尾;如果首尾字符不同,則最長(zhǎng)子序列等于去掉頭的字符串的最長(zhǎng)子序列和去掉尾的字符串的最長(zhǎng)子序列的較大者。
因此動(dòng)態(tài)規(guī)劃的狀態(tài)轉(zhuǎn)移方程為:
設(shè)字符串為str,長(zhǎng)度為n,p[i][j]表示第i到第j個(gè)字符間的子序列的個(gè)數(shù)(i<=j),則:
狀態(tài)初始條件:dp[i][i]=1 (i=0:n-1)
狀態(tài)轉(zhuǎn)移方程:dp[i][j]=dp[i+1][j-1] + 2? if(str[i]==str[j])
? ? ? ? ? ? ? ? ? ?dp[i][j]=max(dp[i+1][j],dp[i][j-1])? if (str[i]!=str[j])
計(jì)算dp[i][j]時(shí)需要計(jì)算dp[i+1][*]或dp[*][j-1],因此i應(yīng)該從大到小,即遞減;j應(yīng)該從小到大,即遞增。注意必須滿足i<=j的條件。
問(wèn)題5:給一個(gè)字符串,求將這個(gè)字符串變?yōu)榛匚拇枰迦氲淖钌僮址麄€(gè)數(shù)。
舉例:
ab3bd
只需變?yōu)閍db3bda即可,在前面插入d,在后面插入a;
思路:
設(shè)dp(i,j)為將Ai..Aj變?yōu)榛匚拇淖钚〈鷥r(jià),如果a[i]=a[j],那不用說(shuō)了,肯定是dp(i,j)=dp(i+1,j-1),如果不相同,在前面或者后面插入一個(gè)字符,即dp(i,j)=min(dp(i,j-1),dp(i+1,j))+1
注意dp順序:
for i:=n downto 1
????for j:=i+1 to n
?
?
另一種思路:
將原串與原串的倒序做一次最長(zhǎng)公共子序列,用原串長(zhǎng)度減去最長(zhǎng)公共子序列長(zhǎng)度,即為需要插入字符的個(gè)數(shù)。邏輯很好想,不過(guò)多介紹
?
問(wèn)題6:最小編輯代價(jià)
這個(gè)解釋有點(diǎn)麻煩,思路分的比較多,是個(gè)值得好好思考一下的題。
[題目]
?給定兩個(gè)字符串str1 和str2,再給定三個(gè)整數(shù)ic、dc 和rc,分別代表插入、刪除和替換一個(gè)字符的代價(jià),返回將str1編輯成str2的最小代價(jià)。
(舉例]
??????str1="abc",str2="adc", ic=5, ?dc=3, ?rc=2。
??????從"abc"編輯成"adc",把b'替換成'd是代價(jià)最小的,所以返回2。str1="abc",str2="adc", ic=5, ?dc=3, ?rc=100。
??????從"abc"編輯成"adc",先刪除"b', 然后插入d是代價(jià)最小的,所以返回8。str1="abc",str2="abc", ic=5, ?dc=3, ?rc=2。
??????不用編輯了,本來(lái)就是一樣的字符串,所以返回0。
?
思路:定義dp(i,j)為str1下標(biāo)i之前編輯到str2下標(biāo)j之前需要的最小代價(jià)。
Dp[0][0]=0,空到空,不用改變。
矩陣dp第一列即dp[..M-1][0]。dp[i][0]表 示str1[0..-1]編輯成空串的最小代價(jià),亳無(wú)疑問(wèn),是把str1[..i1]所有的字符刪掉的代價(jià),所以dp[i][0]=dc*i。
.矩陣dp第一行即dp[0][..N-1]。 dp[0][j]表示空串編輯成str2[O.j-1]的最小代價(jià),亳無(wú)疑問(wèn),是在空串里插入str2[0.j-1]所有字符的代價(jià),所以dp[0][]=ic*j。
?
其他位置按照從左到右,再?gòu)纳系较聛?lái)計(jì)算,dp[i][j]的值只可能來(lái)自以下四種情況。
??????str1[0.i-1]可以先編輯成str1[..i-2], 也就是刪除字符str1[i-1], 然后由str1[0.i-2]編輯成str2[0.j-1], dp[i-1][i]表 示str1[0.i-2]編輯成 str2[0.j-1]的 最小代價(jià),那么dp[i][j]可能等于dc+dp[i-1][j]
??????str1[0.i-1]可以先編輯成str2[0.j-2], 然后將str2[0.j-2]插入字符str2[j-1], 編輯成str2[0.j-1],dp[i][j-1]表 示str1[..i-1]編 輯成str2[0.j-2]的最小代價(jià), 那么dp[i][j]可能等于dp[i][j-1]+ic。
??????如果str1[i-1]!=str2[j-1]。先把str1[0.i-1]中str1[..i-2]的 部分變成str2[0.j-2], 然后把字符str1[i-1]替換成str2[-1], 這樣str1[..i-1]就編輯成str2[0.j1]了 。dp[i-1][j-1]表示str1[..i-2]編輯成str2[..i-2]的最小代價(jià),那么dp[i][j]可 能等于dp[i-1]j-1]+rc.
如果str1[i-1]==str2[j-1]. 先把str1[0..i-1]中 str1[0..i-2]的 部分變成str2[0.j-2], ?因?yàn)榇藭r(shí)字符str1[i-1]等 于str2[j-1], 所以str1[0.i-1]已 經(jīng)編輯成str2[0.j-1]了 。dp[i-1][j-1]表示str1[0i-2]編輯 成str2[..i-2]的 最小代價(jià),那么dp[]ij]可能等于dp[i-1][j-1]
?
問(wèn)題7:判斷交錯(cuò)組成
給定三個(gè)字符串strl str2和aim,如果aim包含且僅包含來(lái)自str1 和str2的所有字符,而且在aim中屬于str1的字符之間保持原來(lái)在str1中的順序,屬于str2的字符之間保持原來(lái)在str2中的順序,那么稱aim是str1和str2的交錯(cuò)組成。實(shí)現(xiàn)-一個(gè)函數(shù),判斷aim是否是str1和str2交錯(cuò)組成。
思路:做這個(gè)題一開始腦子沒(méi)開竅,老想三維,表示str1的前i個(gè)和str2的前j個(gè),組成aim的k個(gè),但其實(shí)k只能是i+j,所以,dp[i][j]為str1的前i個(gè)和str2的前j個(gè)能否組成aim(i+j)。
那就簡(jiǎn)單了,要么放i要么放j,都不行就是0,有一個(gè)可以就是1.
問(wèn)題8:給一個(gè)字符串,求最長(zhǎng)相同前后綴,前綴不包括最后一個(gè)字符,后綴不包括第一個(gè)字符。
注意看kmp的next數(shù)組思想。先看下面的再看這個(gè)
https://blog.csdn.net/hebtu666/article/details/82492803
問(wèn)題9:給串a(chǎn)和b,判斷b是否在a中出現(xiàn),若出現(xiàn)輸出第一次出現(xiàn)的位置。
8和9看kmp詳解:https://blog.csdn.net/hebtu666/article/details/79822446
?
?
?
?
總結(jié)
以上是生活随笔為你收集整理的字符串上的简单动态规划的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: git大总结
- 下一篇: Calendar类 set方法 get方