有兩個字符串S1和S2,在從左往右的順序中,有相同元素組成的序列,稱爲相同序列。必須強調的是:序列是不要求元素連續的。以下圖所示:算法
Spring和Spend的子序列是:SPN數組
經過動態規劃來完成題目。首先,要使用動態規劃要明確轉移方程是什麼,而轉移方程須要對問題的理解和抽象才能得出。通常來講,動態規劃也須要把問題分解爲子問題,但不一樣於遞歸的分解過程是互不影響的,動態規劃每每須要前面的結果來決定後面的策略。同時,爲了減小沒必要要的計算,因此一般須要一個記錄的容器來記錄子問題的最優解,從而擴展爲全局最優解。ui
從題目上看:spa
所以,能夠得出如下的的轉移方程:3d
其中:C是存儲子結果的數組,i和j分別是字符串S1和S2的下標。code
下面經過圖解案例的方式來講明:對象
如圖所示,在算法還沒開始的狀態,能夠得知當字符串S1或S2的元素個數爲0時,他們的最長子序列必定是0。blog
接下來,從以Spend爲參照對象,以Spring爲比較對象,從Spring開始填表。遞歸
從表中看出,Spring的第一個元素「S」與比較對象Spend的第一個元素相等,套用轉移方程:C[i-1][j-1]+1,即c[1][1]=0+1。索引
而元素「S「與Spend的後面元素比較都不相等,則套用轉移方程:c[1][2] = Max(C[i-1][j],C[i][j-1])即max(0,1),因此c[1][2]仍是等於1。
還有一個特殊的點是c[2][2],從上表能夠得出,S1[2]和S2[2]的元素都爲」P「,因此知足條件S1[i]==S2[j],因此能夠得出c[2][2]的值爲:c[1][1]+1 = 2。
根據上面的解析,能夠把表填充完整以下圖所示:
那麼咱們要求的最長子序列的長度就是c[m][n],也就是二維數組的右下角的值。
而具體的代碼我也在下面貼出
1 public class Solution { 2 3 public static void main(String[] args) { 4 String str1 = "Spring"; 5 String str2 = "Spend"; 6 char[] s1 = str1.toCharArray(); 7 char[] s2 = str2.toCharArray(); 8 9 //設定一個二維數組存放當前的最長公共子序列,如前i個s1元素與前j個s2元素有多少個公共子序列元素 10 int[][] c = new int[s1.length+1][s2.length+1]; 11 /* 12 * 根據轉移方程:若s1[i]==s2[i] 13 * c[i][j] = c [i-1][j-1]+1 14 * 若s1[i]!=s2[i] 15 * c[i][j] = max(c[i][j-1] , c[i-1][j] ) 16 **/ 17 for (int i =1;i<=s1.length;i++){ 18 for (int j=1;j<=s2.length;j++){ 19 if (s1[i-1] == s2[j-1]) { 20 c[i][j] = c [i-1][j-1]+1; 21 }else { 22 c[i][j] = Math.max(c[i][j-1] , c[i-1][j] ); 23 } 24 } 25 } 26 } 27 }
在上面已經求得存放比較結果的數組,若是題目要求輸出一個最長子序列,那麼能夠根據這個數組來還原。
還原的策略以下:
如圖所示:
完整的代碼以下
public class Solution { public static void main(String[] args) { String str1 = "Spring"; String str2 = "Spend"; char[] s1 = str1.toCharArray(); char[] s2 = str2.toCharArray(); //設定一個二維數組存放當前的最長公共子序列,如前i個s1元素與前j個s2元素有多少個公共子序列元素 int[][] c = new int[s1.length+1][s2.length+1]; /* * 根據轉移方程:若s1[i]==s2[i] * c[i][j] = c [i-1][j-1]+1 * 若s1[i]!=s2[i] * c[i][j] = max(c[i][j-1] , c[i-1][j] ) **/ for (int i =1;i<=s1.length;i++){ for (int j=1;j<=s2.length;j++){ if (s1[i-1] == s2[j-1]) { c[i][j] = c [i-1][j-1]+1; }else { c[i][j] = Math.max(c[i][j-1] , c[i-1][j] ); } } } //根據數組倒推出子序列 StringBuilder result =new StringBuilder(); int i = s1.length; int j = s2.length; while (i>0 && j>0){ //當前元素相等,保存元素,同時縮減i和j if (s1[i-1] == s2[j-1]){ result.insert(0,s1[i-1]); i--;j--; }else{ //元素不相等,往c值較大的方向縮減,若左邊和上方的值相等,則往上邊縮減。 if (c[i-1][j] >= c[i][j-1]){ i--; }else { j--; } } } System.out.println(result.toString()); } }