我们有两个字符串m和n,如果它们的子串a和b内容相同,则称a和b是m和n的公共子序列。子串中的字符不一定在原字符串中连续。例如字符串“abcfbc”和“abfcab”,其中“abc”同时出现在两个字符串中,因此“abc”是它们的公共子序列。此外,“ab”、“af”等都是它们的字串。现在给你两个任意字符串(不包含空格),请帮忙计算它们的最长公共子序列的长度。
输入包含多组数据。
每组数据包含两个字符串m和n,它们仅包含字母,并且长度不超过1024。
对应每组输入,输出最长公共子序列的长度。
思路:建立一个dp矩阵,是两个字符串一个纵对应,一个横向对应。
dp[i][j]表示m[0…i]和n[0…j]的最长公共子序列的长度
求解 dp[i][j]为:
若m[i] == n[j],则 dp[i][j] = max( dp[i-1][j], dp[i][j-1], dp[i-1][j-1]+1 )
若m[i] != n[j],则 dp[i][j] = max( dp[i-1][j], dp[i][j-1] )
最后返回dp[M-1][N-1],M、N为两个字符串的长度.
代码如下:
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
String m = sc.next();
String n = sc.next();
int lenM = m.length();
int lenN = n.length();
int[][] dp = new int[lenM][lenN];
dp[0][0] = m.charAt(0)==n.charAt(0)?1:0;
for(int i=1;i<lenM;i++){
dp[i][0] = m.charAt(i)==n.charAt(0)?1:0;
dp[i][0] = Math.max(dp[i-1][0],dp[i][0]);
}
for(int j=1;j<lenN;j++){
dp[0][j] = m.charAt(0)==n.charAt(j)?1:0;
dp[0][j] = Math.max(dp[0][j-1],dp[0][j]);
}
for(int i=1;i<lenM;i++){
for(int j=1;j<lenN;j++){
if(m.charAt(i)==n.charAt(j)){
dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);
dp[i][j] = Math.max(dp[i][j],dp[i-1][j-1]+1);
}else{
dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);
}
}
}
System.out.println(dp[lenM-1][lenN-1]);
}
}
}