本文大部分参考July博客的关于动态规划的分析,代码贴在此仅作记忆和分享。
概念解释:
1) 最长子序列,两个字符串中满足相同顺序的子字符序列,如 abefgs和acehfg的最长子序列为aefg
2) 最长子串,两个字符串中相同的子串,即必须是连续相同
以上两个问题的代码如下:
/**
* 动态规划求解最长子串和最长子序列问题
* @author mwd
* @2013-9-17
*
*/
public class DanymicProgramming {
private final int kLeft = 1;
private final int kUp = 2;
private final int kLeftUp = 3;
/**
* 获取最长公共子串,即必须是连续的
* @param str1
* @param str2
* @return
*/
private int lss(String str1,String str2){
int maxLength = 0;
int xIndex = 0;
int yIndex = 0;
if(str1 == null || str2 == null)
return 0;
int len1 = str1.length();
int len2 = str2.length();
if(len1 == 0 || len2 == 0)
return 0;
int[][] lssLength = new int[len1][len2];
for(int i=0;i<len1;i++){
for(int j=0;j<len2;j++){
if(i==0 || j==0){
if(str1.charAt(i) == str2.charAt(j))
lssLength[i][j] = 1;
else
lssLength[i][j] = 0;
}
else{
if(str1.charAt(i) == str2.charAt(j)){
lssLength[i][j] = lssLength[i-1][j-1]+1;
}
else
lssLength[i][j] = 0;
}
if(lssLength[i][j] > maxLength){
maxLength = lssLength[i][j];
xIndex = i;
yIndex = j;
}
}
}
for(int i = xIndex-maxLength+1;i<=xIndex;i++){
System.out.print(str1.charAt(i)+" ");
}
return maxLength;
}
/**
* 求取最长公共子序列
* @param str1
* @param str2
* @return
*/
private int LCS(String str1,String str2){
if(str1 == null || str2 == null)
return 0;
int len1 = str1.length();
int len2 = str2.length();
if(len1 == 0 || len2 == 0)
return 0;
//方位
int[][] lcsDirection = new int[len1][len2];
for(int i=0;i<len1;i++)
for(int j=0;j<len2;j++)
lcsDirection[i][j] = 0;
//长度初始化
int[][] lcsLength = new int[len1][len2];
for(int i=0;i<len1;i++)
for(int j=0;j<len2;j++)
lcsLength[i][j] = 0;
for(int i=0;i<len1;i++)
for(int j=0;j<len2;j++){
if(i==0 || j==0){
if(str1.charAt(i) == str2.charAt(j)){
lcsLength[i][j] = 1;
lcsDirection[i][j] = kLeftUp;
}
else if(i>0){
lcsLength[i][j] = lcsLength[i-1][j];
lcsDirection[i][j] = kUp;
}
else{
lcsLength[i][j] = lcsLength[i][j-1];
lcsDirection[i][j] = kLeft;
}
}
else if(str1.charAt(i) == str2.charAt(j)){
lcsLength[i][j] = lcsLength[i-1][j-1]+1;
lcsDirection[i][j] = kLeftUp;
}
else if(lcsLength[i-1][j] > lcsLength[i][j-1]){
lcsLength[i][j] = lcsLength[i-1][j];
lcsDirection[i][j] = kUp;
}
else{
lcsLength[i][j] = lcsLength[i][j-1];
lcsDirection[i][j] = kLeft;
}
}
for(int i=0;i<len1;i++){
for(int j=0;j<len2;j++){
System.out.print(lcsLength[i][j]+" ");
}
System.out.println();
}
lcsPrint(lcsDirection, str1, str2, len1-1, len2-1); //打印公共子序列
return lcsLength[len1-1][len2-1]; //返回公共子序列的长度
}
/**
* 利用递归,动态打印公共子序列
* @param lcsDirection
* @param str1
* @param str2
* @param row
* @param col
*/
private void lcsPrint(int[][] lcsDirection,String str1,String str2,int row,int col){
if(str1 == null || str2 == null)
return ;
int len1 = str1.length();
int len2 = str2.length();
if(len1 == 0 || len2 == 0 || !(row < len1 && col < len2))
return ;
if(lcsDirection[row][col] == kLeftUp){
if(row > 0 && col > 0)
lcsPrint(lcsDirection, str1, str2, row-1, col-1);
System.out.print(str1.charAt(row)+" ");
}
else if(lcsDirection[row][col] == kUp){
if(row > 0 )
lcsPrint(lcsDirection, str1, str2, row-1, col);
}
else{
if(col > 0)
lcsPrint(lcsDirection, str1, str2, row, col-1);
}
}
public static void main(String[] args){
String str1 = "acbefg";
String str2 = "abecefg";
DanymicProgramming danymic = new DanymicProgramming();
System.out.println("公共子序列长度为:"+danymic.lss(str1, str2));
}
}