LCS最长公共子序列java实现
最长公共子序列:可以不连续
最长公共子串:必须连续
求最长公共子序列:
引进一个二维数组c[][],用c[i][j]记录X[i]与Y[j] 的LCS 的长度,b[i][j]记录c[i][j]是通过哪一个子问题的值求得的,以决定搜索的方向。
我们是自底向上进行递推计算,那么在计算c[i,j]之前,c[i-1][j-1],c[i-1][j]与c[i][j-1]均已计算出来。此时我们根据X[i] = Y[j]还是X[i] != Y[j],就可以计算出c[i][j]。
问题的递归式写成:
回溯输出最长公共子序列过程:
算法分析:
由于每次调用至少向上或向左(或向上向左同时)移动一步,故最多调用(m * n)次就会遇到i = 0或j = 0的情况,此时开始返回。返回时与递归调用时方向相反,步数相同,故算法时间复杂度为Θ(m * n)。
package kpp.base; /** * 获取两个字符串的最长公共子序列 * @author kpp * */ public class LCSTest { private static String lcs = ""; public static void main(String[] args) { // TODO Auto-generated method stub //保留空字符串是为了getLength()方法的完整性也可以不保留 //但是在getLength()方法里面必须额外的初始化c[][]第一个行第一列 String firstStr = "ABCBDAB"; String secondStr = "BDCABA"; /*String[] x = new String[firstStr.length()+1]; String[] y = new String[secondStr.length()+1];*/ String[] x = strToArray(firstStr); String[] y = strToArray(secondStr); /*String[] x = {"", "A", "B", "C", "B", "D", "A", "B"}; String[] y = {"", "B", "D", "C", "A", "B", "A"}; */ int[][] b = getSearchRoad(x, y); Display(b, x, x.length-1, y.length-1); System.out.println("lcs:"+lcs); } /** * 字符串转数组,并且数组的第0个元素为"" * @param str * @return */ private static String[] strToArray(String str){ String[] strArray = new String[str.length()+1]; strArray[0] = ""; for(int i = 1; i < strArray.length;i++){ strArray[i] = ""+str.charAt(i-1); } return strArray; } /** * 获得LCS矩阵的路径走向 * @param x 第一个数组 * @param y 第二个数组 * @return 返回一个记录决定搜索的方向的数组 */ public static int[][] getSearchRoad(String[] x, String[] y) { int[][] b = new int[x.length][y.length]; int[][] c = new int[x.length][y.length]; for(int j = 0;j < y.length;j++){ c[0][j] = 0; } for(int i = 0;i < x.length;i++){ c[i][0] = 0; } for(int i=1; i<x.length; i++) { for(int j=1; j<y.length; j++) { //对应第一个性质 //x[i].equals(y[j])是指x[i]与y[j]的值相同 if( x[i].equals(y[j])) { c[i][j] = c[i-1][j-1] + 1; b[i][j] = 1; } //x[i] == y[j]是指x[i]与y[j]的地址相同 /*if( x[i] == y[j]) { c[i][j] = c[i-1][j-1] + 1; b[i][j] = 1; }*/ //对应第二或者第三个性质 else if(c[i-1][j] >= c[i][j-1]) { c[i][j] = c[i-1][j]; b[i][j] = 0; } //对应第二或者第三个性质 else { c[i][j] = c[i][j-1]; b[i][j] = -1; } } } return b; } /** * 自矩阵右下至左上回溯,根据搜索路径获取LCS * @param b 搜索路径数组 * @param x 第一个数组 * @param i * @param j */ public static void Display(int[][] b, String[] x, int i, int j) { if(i == 0 || j == 0) return ; if(b[i][j] == 1) { Display(b, x, i-1, j-1); lcs += x[i]; } else if(b[i][j] == 0) { Display(b, x, i-1, j); } else if(b[i][j] == -1) { Display(b, x, i, j-1); } } }