問題解讀
最長公共子序列問題,就是找出兩個字符串中,存在的最長的
子序列
什么是子序列呢?
子序列不同於公共子串,子串是每個字符連續的,子序列不一定要連續,見下例 [example]
[example]: 比如 mStringA = "abc11google11111111", mStringB = "1111111141615" 這兩個字符串
那么,mStringA 和 mStringB 的最長公共子序列就是 1111111111
如何求解
我們對於問題進行白話講解,假如現在有兩個字符串,並且有兩個指針,這每個指針,各自指向這兩個字符串,我們把這兩個指針設置為 i 和 j,即,i 指向 mStringA 的某個字符,j 指向 mStringB 的某個字符,那么,此時的狀態方程為 f(i, j)
,表示 i 指向 mStringA 的某個字符和 j 指向 mStringB 的某個字符的情況
- 當兩個指針指向的字符相等時,那么代表這是一個成功的狀態,此時,狀態記為
f(i + 1, j + 1) + 1
,表示 i 和 j 兩個指針可以同時向右方移動- 當兩個指針指向的字符不相等的試試,那么代表這是一個待完成的狀態,此時,狀態記為
f(i + 1, j)
和f(i, j + 1)
Talk is cheap, show me code ~~~
package com.company;
import org.junit.Test;
public class LongestCommonSequence {
// 用來存儲匹配過程中存取的記錄
public StringBuilder sb = new StringBuilder();
/*
* 獲得最長公共子序列的方法
* 傳入兩個參數,即為需要處理的字符串
* 核心實現方法在 longestCommonSequence(...)
*/
public String getLongestCommonSequence(String mStringA, String mStringB) {
// 1. 拿到最長公共子序列的長度
int strLength = longestCommonSequence(0, mStringA, 0, mStringB);
// 2. 將 StringBuilder 轉為 String 類
String mString = new String(sb);
// 3. 對記錄進行裁剪,最后的 strLength 個字符,是最終的結果
return mString.substring(
strLength - longestCommonSequence(0, mStringA, 0, mStringB),
strLength);
}
// 最長公共子序列的實現方法
public int longestCommonSequence(int i, String mStringA, int j, String mStringB) {
// 1. 邊界條件判斷,當指針到頭的時候,返回 0
if (i == mStringA.length() || j == mStringB.length()) {
return 0;
}
// 2. 當兩個指針指向的字符相等的時候,這是狀態方程為:f(i + 1, j + 1) + 1
if (mStringA.charAt(i) == mStringB.charAt(j)) {
sb.append(mStringA.charAt(i));
return longestCommonSequence(i + 1, mStringA, j + 1, mStringB) + 1;
} else { // 3. 當兩個指針指向的字符不相等的時候,這是狀態方程為:f(i + 1, j) 或者 f(i, j + 1)
return Math.max(longestCommonSequence(i + 1, mStringA, j, mStringB),
longestCommonSequence(i, mStringA, j + 1, mStringB));
}
}
// 測試方法
@Test
public void test() {
// 1111111111
System.out.println(
getLongestCommonSequence("abc11google11111111",
"1111111141615")
);
}
}