求两个字符串的最长公共子串,如“abcde”和“bceegf”的最长公共子串为“bc”(子串必须是连续的)
1,暴力法
求字符串的所有子串,进行比较
//暴力法 public static String longestCommonStrings(String s1 , String s2){ int len1 = s1.length(); int len2 = s2.length(); if(len1 == 0 || len2 == 0){ return "0"; } int start = -1; int max = -1; for (int i = 0; i < len1; i++) { for (int j = 0; j < len2; j++) { int m = i,n = j; int len = 0; while(m<len1 && n<len2){ if(s1.charAt(m)!=s2.charAt(n)){ break; } m++; n++; len++; } if(len>max){ max = len; start = i; } } } return s1.substring(start,start+max); }
2,动态规划
找两个字符串的最长公共子串,这个子串要求在原字符串中是连续的。其实这又是一个序贯决策问题,可以用动态规划来求解。我们采用一个二维矩阵来记录中间的结果。这个二维矩阵怎么构造呢?直接举个例子吧:"bab"和"caba"(当然我们现在一眼就可以看出来最长公共子串是"ba"或"ab")
b a b
c 0 0 0
a 0 1 0
b 1 0 1
a 0 1 0
我们看矩阵的斜对角线最长的那个就能找出最长公共子串。
不过在二维矩阵上找最长的由1组成的斜对角线也是件麻烦费时的事,下面改进:当要在矩阵是填1时让它等于其左上角元素加1。
b a b
c 0 0 0
a 0 1 0
b 1 0 2
a 0 2 0
这样矩阵中的最大元素就是 最长公共子串的长度。
在构造这个二维矩阵的过程中由于得出矩阵的某一行后其上一行就没用了,所以实际上在程序中可以用一维数组来代替这个矩阵。
状态转移方程:
代码如下:
//动态规划 public static String longestCommonStrings(String s1 , String s2){ int len1 = s1.length(); int len2 = s2.length(); if(len1 == 0 || len2 == 0){ return "0"; } int[][] arr = new int[len1+1][len2+1]; for (int i = 1; i <= len1; i++) { for (int j = 1; j <= len2; j++) { if(s1.charAt(i-1)!=s2.charAt(j-1)){ arr[i][j] = 0; }else{ arr[i][j] = arr[i-1][j-1]+1; } } } int max = -1; int indexE = -1; for (int i = 1; i < len1+1; i++) { for (int j = 1; j < len2+1; j++) { if(arr[i][j] > max){ max = arr[i][j]; indexE = j; } } } return s2.substring(indexE-max,indexE); }