一、题目
OJ链接
给定两个字符串,返回两个字符串的最长公共子序列的长度。
【注意】:
子序列可以不连续,子字符串一定是要连续的
二、题解
2.1 方法一:递归
思路:
对于给定的两个字符串str1,str2
只关心str1[0,i] 和 str2[0,j] 这两个范围内的字符串的最长公共子序列。
递归函数:
对于递归函数只求str1[0…i]和str[0…j]的最长公共子序列
终止条件:
当i和j都为0的时候,说明两个字符串都只有一个字符,如果这两个字符相等就返回1,否则返回0
当i==0但j!=0时,说明str1中只剩一个字符,和str2[0…j]最多只有一个公共子序列,先判断str1中这个字符是否和str1[j]位置字符相等,如果相等直接返回1,不相等的话就不需要考虑j位置对应的字符了,只需找出str2[0…j-1]与str1中这一个字符的最长公共子序列。
当i!=0 但j==0,和上一种情况类似
当i和j都不等于0的时候
源码:
👽
public static int longestCommonSubsequence(String s1, String s2) {
if(s1==null||s1.length()==0||s2==null||s2.length()==0){
return 0;
}
char[] str1=s1.toCharArray();
char[] str2=s2.toCharArray();
return process1(str1,str2,str1.length-1,str2.length-1);
}
//str1[0...i]和str2[0....j]的最长公共子序列
public static int process1(char[] str1,char[] str2,int i,int j){
if(i==0&&j==0){
return str1[i]==str2[j]?1:0;
} else if(i==0){
if(str1[i]==str2[j]){
return 1;
}else{
return process1(str1,str2,i,j-1);
}
} else if(j==0){
if(str1[i]==str2[j]){
return 1;
}else{
return process1(str1,str2,i-1,j);
}
} else { //i!=0 && j!=0
int p1=process1(str1,str2,i-1,j);
int p2=process1(str1,str2,i,j-1);
int p3=str1[i]==str2[j]?(1+process1(str1,str2,i-1,j-1)):0;
return Math.max(p3,Math.max(p1,p2));
}
}
2.2 方法二:动态规划
源码:
😇
public static int longestCommonSubsequence2(String s1, String s2) {
if(s1==null||s1.length()==0||s2==null||s2.length()==0){
return 0;
}
char[] str1=s1.toCharArray();
char[] str2=s2.toCharArray();
int N=str1.length;
int M=str2.length;
int[][] dp=new int[N][M];
dp[0][0]=str1[0]==str2[0]?1:0;
for (int j = 1; j< M; j++) {
dp[0][j]=str1[0]==str2[j]?1:dp[0][j-1];
}
for (int i = 1; i <N ; i++) {
dp[i][0]=str1[i]==str2[0]?1:dp[i-1][0];
}
for (int i = 1; i <N ; i++) {
for (int j = 1; j <M ; j++) {
int p1=dp[i-1][j];
int p2=dp[i][j-1];
int p3=str1[i]==str2[j]?(1+dp[i-1][j-1]):0;
dp[i][j]= Math.max(p3,Math.max(p1,p2));
}
}
return dp[N-1][M-1];
}