最长公共子序列 Longest Common Subsequence
问题描述:
给定两个字符串a 和 b, 求两个字符串的最长公共子序列。
分析:
首先,要弄清楚最长公共子序列和最长公共子串的区别,最长公共子序列只要保证元素的顺序不变,中间是可以有间断的,但是最长公用子串要求中间不能有间断。
这个是典型的DP问题,从题目中求最长(最优化)应该可以想到尝试DP。
这个题可以分解为两步,第一步求最长公共子序列的长度,第二步,根据这个长度来构造最长公共子序列。
子问题:
从头数,a中长度为 i, b 中长度为 j 的两子串的最长公共子序列的长度。
状态转移方程:
若a[i] == b[j], 那么 dp[i+1][j+1] = dp[i][j] + 1 ;
若a[i] != b[j], 那么 dp[i+1][j+1] = dp[i+1][j] 或者 dp[i+1][j+1] = dp[i][j+1],两者取最大,所以:
dp[i+1][j+1] = max{ dp[i+1][j] , dp[i][j+1] }
public class LCS{
public static String lcs(String a, String b) {
int[][] dp = new int[a.length()+1][b.length()+1];
// row 0 and column 0 are initialized to 0 already
for (int i = 0; i < a.length(); i++)
for (int j = 0; j < b.length(); j++)
if (a.charAt(i) == b.charAt(j))
dp[i+1][j+1] = dp[i][j] + 1;
else
dp[i+1][j+1] =
Math.max(dp[i+1][j], dp[i][j+1]);
// read the substring out from the matrix
StringBuffer sb = new StringBuffer();
for (int x = a.length(), y = b.length(); x != 0 && y != 0; ) {
if (dp[x][y] == dp[x-1][y])
x--;
else if (dp[x][y] == dp[x][y-1])
y--;
else {
// if has equal element at up or left, do not add to the string
sb.append(a.charAt(x-1));
x--;
y--;
}
}
return sb.reverse().toString();
}
public static void main(String[] args) {
String str1 = new String("binghaven");
String str2 = new String("jingseven");
System.out.println(lcs(str1,str2));
}
}
最长公共子串 Longest Common SubString
问题描述:
给定两个字符串a和b,求两个字符串的最长公共子串。
分析:
这个还是动规问题,还是记录最长公共子串的长度。
子问题:
从头开始,a 中到i 和 b 中到 j 的子串的最长公共子串长度.
状态转移方程:
如果 a[i] == b[j], 则 dp[i+1][j+1] = dp[i][j] + 1;
如果a[i] != b[j], 则 dp[i+1][j+1] = 0
为了能输出最长公共子串,用一个max来记录当前最长公共子串的长度,并用list来按顺序记录最长公共子串最后一个字符的下标(记录在其中一个字符串中的小标就可以了)。
package javainterview.string;
import java.util.ArrayList;
public class LCSubString {
public static String[] getLCString(String a, String b){
int aLen = a.length();
int bLen = b.length();
ArrayList<Integer> list = new ArrayList<Integer>();
int max = 0;
int[][] dp = new int[aLen+1][bLen+1];
for(int i=0; i<aLen; i++){
for(int j=0; j<bLen; j++){
if(a.charAt(i) == b.charAt(j)){
dp[i+1][j+1] = dp[i][j] + 1;
}else{
dp[i+1][j+1] = 0;
}
if(dp[i+1][j+1] > max){
max = dp[i+1][j+1];
list.clear();
list.add(j);//键入其中一个就行
}else if(dp[i+1][j+1] == max){
list.add(j);
}
}
}
//构造结果
String[] result = new String[list.size()];
for(int i=0; i<list.size(); i++){
int k = list.get(i);
result[i] = b.substring(k-max+1, k+1);
}
return result;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
String a = "ginghaven";
String b = "jingseven";
String[] result = getLCString(a, b);
for(String item : result){
System.out.println(item);
}
}
}
Reference:
http://blog.csdn.net/biangren/article/details/8038605
http://rosettacode.org/wiki/Longest_common_subsequence