经典算法-最长公共子序列(LCS)与最长公共子串(DP)
public static int lcs(String str1, String str2) { int len1 = str1.length(); int len2 = str2.length(); int c[][] = new int[len1+1][len2+1]; for (int i = 0; i <= len1; i++) { for( int j = 0; j <= len2; j++) { if(i == 0 || j == 0) { c[i][j] = 0; } else if (str1.charAt(i-1) == str2.charAt(j-1)) { c[i][j] = c[i-1][j-1] + 1; } else { c[i][j] = max(c[i - 1][j], c[i][j - 1]); } } } return c[len1][len2]; }
public class LCSProblem { public static void main(String[] args) { //保留空字符串是为了getLength()方法的完整性也可以不保留 //但是在getLength()方法里面必须额外的初始化c[][]第一个行第一列 String[] x = {"", "A", "B", "C", "B", "D", "A", "B"}; String[] y = {"", "B", "D", "C", "A", "B", "A"}; int[][] b = getLength(x, y); Display(b, x, x.length-1, y.length-1); } /** * @param x * @param y * @return 返回一个记录决定搜索的方向的数组 */ public static int[][] getLength(String[] x, String[] y) { int[][] b = new int[x.length][y.length]; int[][] c = new int[x.length][y.length]; for(int i=1; i<x.length; i++) { for(int j=1; j<y.length; 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; } //回溯的基本实现,采取递归的方式 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); System.out.print(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); } } }
public static int lcs(String str1, String str2) { int len1 = str1.length(); int len2 = str2.length(); int result = 0; //记录最长公共子串长度 int c[][] = new int[len1+1][len2+1]; for (int i = 0; i <= len1; i++) { for( int j = 0; j <= len2; j++) { if(i == 0 || j == 0) { c[i][j] = 0; } else if (str1.charAt(i-1) == str2.charAt(j-1)) { c[i][j] = c[i-1][j-1] + 1; result = max(c[i][j], result); } else { c[i][j] = 0; } } } return result; }
public class stringCompare { //在动态规划矩阵生成方式当中,每生成一行,前面的那一行就已经没有用了,因此这里只需使用一维数组,而不是常用的二位数组 public static void getLCString(char[] str1, char[] str2) { int len1, len2; len1 = str1.length; len2 = str2.length; int maxLen = len1 > len2 ? len1 : len2; int[] max = new int[maxLen];// 保存最长子串长度的数组 int[] maxIndex = new int[maxLen];// 保存最长子串长度最大索引的数组 int[] c = new int[maxLen]; int i, j; for (i = 0; i < len2; i++) { for (j = len1 - 1; j >= 0; j--) { if (str2[i] == str1[j]) { if ((i == 0) || (j == 0)) c[j] = 1; else c[j] = c[j - 1] + 1;//此时C[j-1]还是上次循环中的值,因为还没被重新赋值 } else { c[j] = 0; } // 如果是大于那暂时只有一个是最长的,而且要把后面的清0; if (c[j] > max[0]) { max[0] = c[j]; maxIndex[0] = j; for (int k = 1; k < maxLen; k++) { max[k] = 0; maxIndex[k] = 0; } } // 有多个是相同长度的子串 else if (c[j] == max[0]) { for (int k = 1; k < maxLen; k++) { if (max[k] == 0) { max[k] = c[j]; maxIndex[k] = j; break; // 在后面加一个就要退出循环了 } } } } for (int temp : c) { System.out.print(temp); } System.out.println(); } //打印最长子字符串 for (j = 0; j < maxLen; j++) { if (max[j] > 0) { System.out.println("第" + (j + 1) + "个公共子串:"); for (i = maxIndex[j] - max[j] + 1; i <= maxIndex[j]; i++) System.out.print(str1[i]); System.out.println(" "); } } } public static void main(String[] args) { String str1 = new String("binghaven"); String str2 = new String("jingseven"); getLCString(str1.toCharArray(), str2.toCharArray()); } }
/*
000000000
010000000
002000001
000300000
000000000
000000010
000000100
000000020
001000003
第1个公共子串:
ing
第2个公共子串:
ven
*/