1、先科普下最长公共子序列 & 最长公共子串的区别:
找两个字符串的最长公共子串,这个子串要求在原字符串中是连续的。而最长公共子序列则并不要求连续。
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
这样矩阵中的最大元素就是 最长公共子串的长度。
在构造这个二维矩阵的过程中由于得出矩阵的某一行后其上一行就没用了,所以实际上在程序中可以用一维数组来代替这个矩阵。
2.1 代码如下:
01 | public class LCString2 { |
03 | public static void getLCString( char [] str1, char [] str2) { |
08 | int maxLen = len1 > len2 ? len1 : len2; |
09 | int [] max = new int [maxLen]; |
10 | int [] maxIndex = new int [maxLen]; |
11 | int [] c = new int [maxLen]; |
13 | for (i = 0 ; i < len2; i++) { |
14 | for (j = len1 - 1 ; j >= 0 ; j--) { |
15 | if (str2[i] == str1[j]) { |
16 | if ((i == 0 ) || (j == 0 )) |
28 | for ( int k = 1 ; k < maxLen; k++) { |
32 | } else if (c[j] == max[ 0 ]) { |
33 | for ( int k = 1 ; k < maxLen; k++) { |
45 | for (j = 0 ; j < maxLen; j++) { |
47 | System.out.println( "第" + (j + 1 ) + "个公共子串:" ); |
48 | for (i = maxIndex[j] - max[j] + 1 ; i <= maxIndex[j]; i++) |
49 | System.out.print(str1[i]); |
50 | System.out.println( " " ); |
55 | public static void main(String[] args) { |
57 | String str1 = new String( "123456abcd567" ); |
58 | String str2 = new String( "234dddabc45678" ); |
61 | getLCString(str1.toCharArray(), str2.toCharArray()); |
ref:
LCS的java算法---考虑可能有多个相同的最长公共子串
http://blog.csdn.net/rabbitbug/article/details/1740557
最大子序列、最长递增子序列、最长公共子串、最长公共子序列、字符串编辑距离
http://www.cnblogs.com/zhangchaoyang/articles/2012070.html
2.2 其实 awk 写起来也很容易:
2 | 234dddabc45678 "|awk -vFS=" " 'NR==1{str=$0}NR==2{N=NF;for(n=0;n++<N;){s=" ";for(t=n;t<=N;t++){s=s" "$t; if (index(str,s)){a[n]=t-n;b[n]=s; if (m<=a[n])m=a[n]} else {t=N}}}}END{ for (n=0;n++<N;) if (a[n]==m)print b[n]}' |
ref:http://bbs.chinaunix.net/thread-4055834-2-1.html
2.3 perl的。。。真心没看懂。。。
05 | my $str1 = "123456abcd567" ; |
06 | my $str2 = "234dddabc45678" ; |
07 | my $str = $str1 . "\n" . $str2 ; |
10 | $str =~ /(.+)(?=.*\n.*\1)(*PRUNE)(?{ push @substr , $1 })(*F)/; |
11 | @substr = sort { length ( $b ) <=> length ( $a ) } @substr ; |
12 | @result = grep { length == length $substr [0] } @substr ; |
ref:
http://bbs.chinaunix.net/thread-1333575-7-1.html
3、最长公共子序列
01 | import java.util.Random; |
05 | public static void main(String[] args) { |
11 | String y = "1a1wbz2c123a1b2c123" ; |
13 | int substringLength1 = x.length(); |
14 | int substringLength2 = y.length(); |
17 | int [][] opt = new int [substringLength1 + 1 ][substringLength2 + 1 ]; |
20 | for ( int i = substringLength1 - 1 ; i >= 0 ; i--) { |
21 | for ( int j = substringLength2 - 1 ; j >= 0 ; j--) { |
22 | if (x.charAt(i) == y.charAt(j)) |
23 | opt[i][j] = opt[i + 1 ][j + 1 ] + 1 ; |
25 | opt[i][j] = Math.max(opt[i + 1 ][j], opt[i][j + 1 ]); |
28 | System.out.println( "substring1:" + x); |
29 | System.out.println( "substring2:" + y); |
30 | System.out.print( "LCS:" ); |
33 | while (i < substringLength1 && j < substringLength2) { |
34 | if (x.charAt(i) == y.charAt(j)) { |
35 | System.out.print(x.charAt(i)); |
38 | } else if (opt[i + 1 ][j] >= opt[i][j + 1 ]) |
46 | public static String GetRandomStrings( int length) { |
47 | StringBuffer buffer = new StringBuffer( "abcdefghijklmnopqrstuvwxyz" ); |
48 | StringBuffer sb = new StringBuffer(); |
49 | Random r = new Random(); |
50 | int range = buffer.length(); |
51 | for ( int i = 0 ; i < length; i++) { |
52 | sb.append(buffer.charAt(r.nextInt(range))); |
REF:
字符串最大公共子序列以及最大公共子串问题
http://gongqi.iteye.com/blog/1517447
动态规划算法解最长公共子序列LCS问题
http://blog.csdn.net/v_JULY_v/article/details/6110269