字符串a,长度为m:a[1].a[2].a[3].a[4]....a[m]
字符串b,长度为n:b[1].b[2].b[3].b[4]....b[n]
比如字符串a:BDCABA;字符串b:ABCBDAB则这两个字符串的最长公共子序列长度为4,最长公共子序列是:BCBA或者BDAB,可以不用连续
1.求字符串a:0~m和b:0~n的最长公共子序列,如果a[m]等于b[n],问题是不是转化为求a:0~m-1和b:0~n-1的最长公共子序列(再加上a[m]或者b[n]的这个字符),最长公共子序列的长度用dp[m-1][n-1]+1表示;同样的,如果a[m-1]等于b[n-1],问题转化为求a:0~m-2和b:0~n-2的最长公共子序列+2,用dp[m-2][n-2]+2表示;
2.如果a[m]不等于b[n],说明最后一个元素不可能是最长公共子序列中的元素(都不相等了,怎么公共嘛),那对于最长公共子序列来说,可能是a[m-1]和b[n]的最长公共子序列或者a[m]和b[n-1]的最长公共子序列;同理要判断a[m-1]和b[n],如果a[m-1]和b[n]不相等,那继续递推a[m-1]和b[n-1]和a[m-2]和b[n];a[m]和b[n-1]是不是相等,如果a[m]和b[n-1]不相等,那继续递推a[m-1]和b[n-1]和a[m]和b[n-2];
.......
3.如果m=0,也即字符串a的长度是0,不管b字符串的情况怎样,那最长公共子序列肯定是0,记d[0][n]=0;同理,b字符串的长度为0时,d[m][0]=0;
即 if(a[m]==b[n]) dp[m][n] = dp[m-1][n-1]+1;
if(a[m]!=b[n]) dp[m][n] = max{dp[m-1][n], dp[m][n-1]};
if(m==0||n==0) dp[m][n]=0;
4.构建二维数组,dp[m][n]的值就是要求的最长公共子序列长度,如下图中的dp[6][7]=4

5.同样,根据上图,找到最长公共子序列BCBA或者BDAB
BCBA或者BDAB
6.代码部分
1 public static void lcs(String x, String y) { 2 if(x==null||"".equals(x)||y==null||"".equals(y)){ 3 return; 4 } 5 //记录通过哪个子问题解决的,也就是递推的路径 6 int[][] pos = new int[x.length()+1][y.length()+1]; 7 int[][] dp = new int[x.length() + 1][y.length() + 1]; 8 int maxLength = 0; 9 for (int i = 1; i < x.length() + 1; i++) { 10 for (int j = 1; j < y.length() + 1; j++) { 11 if (x.charAt(i - 1) == y.charAt(j - 1)) { 12 dp[i][j] = dp[i - 1][j - 1] + 1; 13 } else { 14 if(dp[i-1][j] >= dp[i][j-1]){ 15 dp[i][j] = dp[i-1][j]; 16 pos[i][j] = 1; 17 }else{ 18 dp[i][j] = dp[i][j-1]; 19 pos[i][j] = -1; 20 } 21 } 22 maxLength = Math.max(dp[i][j], maxLength); 23 } 24 } 25 System.out.println("公共子序列长度:"+maxLength); 26 System.out.println("公共子序列:"); 27 printLCS(pos, x, x.length(), y.length()); 28 System.out.println(); 29 } 30 31 public static void printLCS(int[][]b,String x,int i,int j){ 32 if(i == 0 || j == 0){ 33 return; 34 } 35 if(b[i][j] == 0){ 36 printLCS(b,x,i-1,j-1); 37 System.out.print(x.charAt(i-1)); 38 }else if(b[i][j] == 1){ 39 printLCS(b,x,i-1,j); 40 }else{ 41 printLCS(b,x,i,j-1); 42 } 43 }