除了揹包問題和走金字塔問題,最長公共子序列也是常見動態規劃例子,本篇文章簡單分析該問題。
最長公共子序列問題形式如下:有兩個字符串,求出最長公共子序列的長度。示例如:
字符串A: a s d h e j f
字符串B: a r s g k l g d
則字符串A和B的最長公共子序列爲“asd”,最大公共子序列長度爲3。最長公共子序列與最長公共子串不同的是:最長公共子序列是兩個字符串中抽取出來的出現順序相同、但不必連續的子串,最長公共子串是兩個字符串中抽取出來的出現順序相同、也要連續的子串。
與0-1問題的解法類似,此問題分析步驟如下:
1、用一個多維數組dp的形式來模擬計算過程,數組的初始值可以用0來填充。
2、定義狀態。如dp[ i ][ j ],定義爲字符串A[0...i]和字符串B[0...j]的最長公共子序列長度。關於dp[ i ][ j ] 的變化過程,可以分爲兩類:
1>當A[ i ]和B[ j ]相等時,則兩個字符串需要公共減去共有序列,然後最長公共子序列數量+1,即dp[ i ][ j ] = dp[ i-1 ][ j-1 ] +1。
2>當A[ i ]和B[ j ]不相等時,就需要將A或B的字符串減去1個元素,然後取兩者的最大值,即dp[ i ][ j ] = max(dp[ i-1 ][ j ],dp[ i ][ j-1 ])。
當最後填滿數組dp時,dp[ A.length() ][ B.length() ]即爲所求的最長公共子序列長度。
Java代碼如下:
String str1 = "asdhejf";
String str2 = "arsgklgd";
//構建動態規劃表
int[ ][ ] dp = new int[str1.length() + 1][str2.length() + 1];
//賦予動態規劃表初始值
for (int i = 0; i <= str1.length(); i++) {
for (int j = 0; j <= str2.length(); j++) {
dp[ i ][ j ] = 0;
}
}
for (int i = 1; i <= str1.length(); i++) {
for (int j = 1; j <= str2.length(); j++) {
if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
//兩個字符串中要比較的元素相等
dp[ i ][ j ] = dp[i - 1][j - 1] + 1;
} else {
//兩個字符串中要比較的元素不相等,分別在兩個字符串中減去一元素,取較大值
dp[ i ][ j ] = Math.max(dp[i - 1][j],dp[i][j - 1]);
}
}
}