【谈谈】动态规划——求最长公共子序列
首先,我們要搞清楚所謂最長公共子序列的概念。不然很容易把它和最長公共子串混淆,兩者區別是:子序列只需要字符保持相對順序,并不要求像公共字串那樣組成字符還需連續。
問題:
給定兩個字符串數組序列:
求它們的最長公共子序列,我們可肉眼判斷,這兩個字符串數組序列的最長公共子序列長度為4.
“BDAB” “BCAB” “BCBA”現在用代碼解決這個問題,一般人比如說我最容易想到方法都是窮舉法:
列出X的所有子序列,再在Y中找到和其匹配的最長子序列。
如果用窮舉法解決,時間復雜度最多能達到O(n*2^m),也就是說,在一些特定場合比如校招面試,使用這種方法極易被pass。
再接來考慮遞推
問題的核心就是找到X,Y的最長公共子序列,記為LCS(X,Y)。
如果xm = yn,則Ck = xm = yn 且 Ck-1是Xm-1和Yn-1的一個LCS
如果xm != yn 且 Ck != xm,則C是Xm-1和Y的一個LCS
如果xm != yn 且 Ck != yn,則C是X和Yn-1的一個LCS
但要是完全用遞歸求解,在整個二叉樹的最有求解過程中,會有大量的重復調用。時間復雜度是指數級,并沒有得到太大的優化。所以這里我們建議使用動態規劃求解。
為了杜絕相關不必要重復步驟,我們選擇用動態規劃求解,通過備忘錄或者說一張表來存放數據,避免重復的計算和調用,以空間換時間,同時本問題還符合動態規劃的基本特征,求解最優子結構和重復子問題。
備忘錄方法采用自頂向下方式,為每個解過的子問題建立了備忘錄以備需要時查看,避免了相同子問題的重復求解
public class 備忘錄法 {public static int Lcs(char x[],char y[],int i,int j,int bak[][]) {if(bak[i][j]!=-1) {return bak[i][j];}if(i==0||j==0) {return bak[i][j]=0;}else if(x[i]==y[j]) {return Lcs(x,y,i-1,j-1,bak)+1;}else {bak[i][j]=Max(Lcs(x,y,i-1,j,bak),Lcs(x,y,i,j-1,bak));}return bak[i][j];}private static int Max(int a,int b){if(a>b) {return a;}else {return b;}} public static void main(String[] args) {//System.out.println((int)' ');String s1="ABCBDAB";char[] c1=new char[s1.length()+1];//帶0字符的字符數組char[] t1=s1.toCharArray();c1[0]=(char)0;for(int i=1;i<t1.length;i++) {c1[i+1]=t1[i];}String s2="BDCABA";char[] c2=new char[s2.length()+1];//帶0字符的字符數組char []t2=s2.toCharArray();c2[0]=(char)0;for(int i=1;i<t2.length;i++) {c2[i+1]=t2[i];}//初始化備忘錄數組int [][]bak=new int[c1.length][c2.length];for(int i=0;i<c1.length;i++) {for(int j=0;j<c2.length;j++) {bak[i][j]=-1;}}System.out.println(Lcs(c1,c2,c1.length-1,c2.length-1,bak)) ; } }備忘錄法相比于遞歸以空間換時間,降低了時間復雜度,但占用內存會大大升高,并且它的時間復雜度相比于下面這種方法并不算太過優化。
動態規劃—自底向上法:
采用自底向上方式,保存已求解的子問題,需要時取出,消除對某些子問題的重復求解.
總結
以上是生活随笔為你收集整理的【谈谈】动态规划——求最长公共子序列的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 软件模拟SPI接口程序代码(4种模式)
- 下一篇: matlab 野值剔除,一种基于多项式拟