動態規劃:遞歸導致的問題,很多小問題重複出現,所以有了動態規劃算法,讓許多小問題可以重複利用,減少算法的重複計算。
窮舉法
可使用窮舉法求解字符串A和B的最長公共子序列長度,算法描述如下:
列舉字符串A的除空串之外的所有子序列,設A的長度爲n,A共有2n-1個子序列。
例A=”abcd”,可能的24-1=15個子序列爲:
a、b、c、d、(4個)
ab、ac、ad、bc、bd、cd、(6個)
abc、abd、acd、bcd、(4個)
abcd (1個)
動態規劃法
設A=a1a2…an、B=b1b2…bm,L[i,j]表示a1a2…ai和b1b2…bj的最長公共子序列長度,很容易證明下面的觀察結論:
如果i和j都大於0,那麼
若ai=bj,a1…a(i-1)和b1…b(j-1)的最長子序列 + 1
L[i,j]=L[i-1,j-1]+1;
若ai≠bj,求取a1….ai和b1…b(j-1)的最長子序列
求取a1…a(i-1)和b1…b(j)的最長子序列
然後求取二者的最大值,即
L[i,j]=max(L[i,j-1],L[i-1,j])。
動態規劃實現 推導公式:
算法分析:
動態規劃特點:自下往上求解小問題
動態規劃法求解最長公共子序列。對於每對i和j的值,用一個二維數組L[0..m,0..n]來存放L[i,j]的值。
⑴設字符串A=a1a2…an,字符串B=b1b2…bm。以字符串A爲y軸,字符串B爲x軸。
⑵首先從A子串只有一個字符開始,計算出a1和B中各子串的最大公共子序列長度;然後逐個增加A子串中的字符,分別計算出當前A子串和B各子串的最大公共子序列長度;直至A的全部字符。
⑶L[i,j]表示A子串a1a2…ai(1≤i≤n)和B子串b1b2…bj(1≤j≤m)的最大公共子序列長度。
1. if ai=bj then
2. L[i,j]←L[i-1,j-1]+1
3. else
4. L[i,j]←max{L[i,j-1],L[i-1,j]}
5. end if
算法僞代碼:
輸入:字符串A和B,設A和B的長度分別爲n和m。
輸出:A和B的最長公共子序列的長度
1. for i←0 to n //字符串A爲y軸
2. L[i,0]←0 //字符串B爲空
3. end for
4. for j←0 to m //字符串B爲x軸
5. L[0,j]←0 //字符串A爲空
6. end for
7. for i←1 to n //A子串中字符逐個增加
8. for j←1 to m //當A子串確定,B子串中字符逐個增加。
9. if ai=bj then L[i,j]←L[i-1,j-1]+1 //i-1表示上一行
10. else L[i,j]←max{L[i,j-1],L[i-1,j]} //j-1表示前一列
11. end if
12. end for
13. end for
14. return L[m,n] //返回最長公共子序列長度
算法具體實現:
package Test5;
/**
* 最大公共子序列
*
* @author Mr.洛洛
* @by 2015.12.20
*/
public class LCS {
static String strA = "zxyxyx";
static String strB = "xyyzx";
public static void main(String args[]) {
int[][] arrs = new int[strA.length() + 1][strB.length() + 1];
int maxLCSLength = LCSLength(arrs);
printLCS(arrs);
System.out.println("\n\t最長公共子序列長度爲:" + maxLCSLength);
}
/**
* 最長公共子序列算法實現
*
* @param arrs
*/
public static int LCSLength(int[][] arrs) {
for (int i = 0; i < arrs.length; i++) {
System.out.println("==================最長公共子序列算法===================");
System.out.println("\n======================第 " + (i + 1)
+ " 次循環======================");
if (i > 0) {
System.out.println("strA = " + strA.substring(0, i)
+ " , strB = ' " + strB + " '");
} else {
System.out.println("strA = 空 " + ", strB = " + strB);
}
for (int j = 0; j < arrs[i].length; j++) {
if (i == 0 || j == 0) { // 若i=0 或 j=0
arrs[i][j] = 0;
System.out.println("arrs[" + i + "][" + j + "] = 0");
} else {
if (i > 0 && j > 0
&& (strA.charAt(i - 1) == strB.charAt(j - 1))) { // 若i>0, j>0, 且ai = bj
arrs[i][j] = arrs[i - 1][j - 1] + 1;
System.out.println("arrs[" + i + "][" + j
+ "] = arrs[i-1][j-1] + 1 = arrs[" + (i - 1)
+ "][" + (j - 1) + "] + 1 = " + arrs[i][j]);
}
if (i > 0 && j > 0
&& (strA.charAt(i - 1) != strB.charAt(j - 1))) { // 若i>0, j>0,且ai != bj
arrs[i][j] = MaxNum(arrs[i][j - 1], arrs[i - 1][j]);
System.out
.println("arrs["
+ i
+ "]["
+ j
+ "] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs["
+ (i) + "][" + (j - 1) + "], arrs["
+ (i - 1) + "][" + (j) + "]} = max{"
+ arrs[i][j - 1] + ", "
+ arrs[i - 1][j] + "} = " + arrs[i][j]);
}
}
}
}
return arrs[strA.length()][strB.length()];
}
/**
* 打印數組
*
* @param arrs
*/
public static void printLCS(int[][] arrs) {
System.out.println("===========最後結果===========");
for (int i = 0; i < arrs.length; i++) {
for (int j = 0; j < arrs[i].length; j++) {
System.out.print("\t" + arrs[i][j]);
}
System.out.println();
}
}
/**
* 比較兩個數的較大值
*
* @param num1
* @param num2
* @return
*/
public static int MaxNum(int num1, int num2) {
return num1 > num2 ? num1 : num2;
}
}
打印過程:
======================第 1 次循環======================
strA = 空 , strB = xyyzx
arrs[0][0] = 0
arrs[0][1] = 0
arrs[0][2] = 0
arrs[0][3] = 0
arrs[0][4] = 0
arrs[0][5] = 0
======================第 2 次循環======================
strA = z , strB = 'xyyzx'
arrs[1][0] = 0
arrs[1][1] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[1][0], arrs[0][1]} = max{0, 0} = 0
arrs[1][2] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[1][1], arrs[0][2]} = max{0, 0} = 0
arrs[1][3] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[1][2], arrs[0][3]} = max{0, 0} = 0
arrs[1][4] = arrs[i-1][j-1] + 1 = arrs[0][3] + 1 = 1
arrs[1][5] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[1][4], arrs[0][5]} = max{1, 0} = 1
======================第 3 次循環======================
strA = zx , strB = 'xyyzx'
arrs[2][0] = 0
arrs[2][1] = arrs[i-1][j-1] + 1 = arrs[1][0] + 1 = 1
arrs[2][2] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[2][1], arrs[1][2]} = max{1, 0} = 1
arrs[2][3] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[2][2], arrs[1][3]} = max{1, 0} = 1
arrs[2][4] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[2][3], arrs[1][4]} = max{1, 1} = 1
arrs[2][5] = arrs[i-1][j-1] + 1 = arrs[1][4] + 1 = 2
======================第 4 次循環======================
strA = zxy , strB = 'xyyzx'
arrs[3][0] = 0
arrs[3][1] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[3][0], arrs[2][1]} = max{0, 1} = 1
arrs[3][2] = arrs[i-1][j-1] + 1 = arrs[2][1] + 1 = 2
arrs[3][3] = arrs[i-1][j-1] + 1 = arrs[2][2] + 1 = 2
arrs[3][4] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[3][3], arrs[2][4]} = max{2, 1} = 2
arrs[3][5] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[3][4], arrs[2][5]} = max{2, 2} = 2
======================第 5 次循環======================
strA = zxyx , strB = 'xyyzx'
arrs[4][0] = 0
arrs[4][1] = arrs[i-1][j-1] + 1 = arrs[3][0] + 1 = 1
arrs[4][2] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[4][1], arrs[3][2]} = max{1, 2} = 2
arrs[4][3] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[4][2], arrs[3][3]} = max{2, 2} = 2
arrs[4][4] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[4][3], arrs[3][4]} = max{2, 2} = 2
arrs[4][5] = arrs[i-1][j-1] + 1 = arrs[3][4] + 1 = 3
======================第 6 次循環======================
strA = zxyxy , strB = 'xyyzx'
arrs[5][0] = 0
arrs[5][1] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[5][0], arrs[4][1]} = max{0, 1} = 1
arrs[5][2] = arrs[i-1][j-1] + 1 = arrs[4][1] + 1 = 2
arrs[5][3] = arrs[i-1][j-1] + 1 = arrs[4][2] + 1 = 3
arrs[5][4] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[5][3], arrs[4][4]} = max{3, 2} = 3
arrs[5][5] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[5][4], arrs[4][5]} = max{3, 3} = 3
======================第 7 次循環======================
strA = zxyxyx , strB = 'xyyzx'
arrs[6][0] = 0
arrs[6][1] = arrs[i-1][j-1] + 1 = arrs[5][0] + 1 = 1
arrs[6][2] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[6][1], arrs[5][2]} = max{1, 2} = 2
arrs[6][3] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[6][2], arrs[5][3]} = max{2, 3} = 3
arrs[6][4] = max {arrs[i][j-1] , arrs[i-1][j]} = max{arrs[6][3], arrs[5][4]} = max{3, 3} = 3
arrs[6][5] = arrs[i-1][j-1] + 1 = arrs[5][4] + 1 = 4
===========最後結果===========
0 0 0 0 0 0
0 0 0 0 1 1
0 1 1 1 1 2
0 1 2 2 2 2
0 1 2 2 2 3
0 1 2 3 3 3
0 1 2 3 3 4