【题目】
给定两个字符串str1和str2,返回两个字符串的最长公共子序列。
【举例】
str1=”1A2C3D4B56”
str2=”B1D23CA45B6A”
“123456”或者”12C4B6”都是最长公共子序列,返回哪个都行。
【代码】
public static void main(String[] args) {
String str1="1A2C3D4B56";
String str2="B1D23CA45B6A";
System.out.println(lcse(str1,str2));//123456
}
//最长公共子序列问题
//获得公共序列长度
public static int[][] getdp(char[] str1,char[] str2){
int[][] dp=new int[str1.length][str2.length];
//dp[i][j]代表:str1[0..i]与str2[0..j]最长公共子序列的长度
dp[0][0]=str1[0]==str2[0]?1:0;
for(int i=1;i<str1.length;i++){//第1列,str1[0..i]与str2[0]公共长度
dp[i][0]=Math.max(dp[i-1][0], str1[i]==str2[0]?1:0);
}
for(int j=1;j<str2.length;j++){//第1行,str1[0]与str2[0..j]公共长度
dp[0][j]=Math.max(dp[0][j-1], str1[0]==str2[j]?1:0);
}
for(int i=1;i<str1.length;i++){
for(int j=1;j<str2.length;j++){
dp[i][j]=Math.max(dp[i-1][j], dp[i][j-1]);
if(str1[i]==str2[j]){
dp[i][j]=Math.max(dp[i][j], dp[i-1][j-1])+1;
}
}
}
return dp;
//矩阵右下角的值:两个str整体的最长公共子序列的长度
}
public static String lcse(String str1,String str2){
if(str1==null || str2==null || str1.equals("") || str2.equals("")){
return "";
}
char[] chs1=str1.toCharArray();
char[] chs2=str2.toCharArray();
int[][] dp=getdp(chs1,chs2);
int m=chs1.length-1;
int n=chs2.length-1;
char[] res=new char[dp[m][n]];
int index=res.length-1;
//从矩阵的右下角开始移动,移动方式:向上、向左、左上
while(index>=0){
if(n>0 && dp[m][n]==dp[m][n-1]){
n--;//左移
}
else if(m>0 && dp[m][n]==dp[m-1][n]){
m--;//上移
}else{
//如果dp[i][j]>Math.max(dp[i-1][j],dp[i][j-1])
//说明dp[i][j]=dp[i-1][j-1]+1
//可以确定str1[i]=str2[j],且这个字符属于最长公共子序列,放进res
res[index--]=chs1[m];//公共字符
m--;
n--;
}
}
return String.valueOf(res);
}