详细问题解说请看http://tianyunpu2008.blog.163.com/blog/static/6559379920089162236915/
这里是java代码实现
package edu.cumt.jnotnull; public class Lcs { public static void main(String[] args) { char[] left = "21232523311324".toCharArray(); char[] right = "312123223445".toCharArray(); char [] result = delLGS(left, right); String strResult=""; for(int index = 0;index<result.length;index++){ strResult = strResult+ result[index]+""; } System.out.println(strResult); } public static char[] delLGS(char[] left, char[] right) { int lenLeft = left.length; int lenRight = right.length; int c[][] = new int[lenLeft][lenRight]; char[] p; int start, end, len, i, j = 0; end = len = 0; for (i = 0; i < lenLeft; i++) { for (j = lenRight - 1; j >= 0; j--) { if (left[i] == right[j])// 元素相等时 { if (i == 0 || j == 0) c[i][j] = 1; else { c[i][j] = c[i - 1][j - 1] + 1; } } else c[i][j] = 0; if (c[i][j] > len) { len = c[i][j]; end = j; } } } start = end - len + 1; p = new char[len]; for (i = start; i <= end; i++) { p[i - start] = right[i]; } return p; } }
衍生阅读:Rabin-Karp算法
Rabin-Karp算法在字符串匹配中其实也不算是很常用,但它的实用性还是不错的,除非你的运气特别差,最坏情况下可能会需要O((n-m)*m)的运行时间(关于n,m的意义请看上篇)。平均情况下,还是比较好的。
朴素的字符串匹配算法为什么慢? 因为它太健忘了,前一次匹配的信息其实可以有部分可以应用到后一次匹配中的,而朴素的字符串匹配算法只是简单的把这个信息扔掉,从头再来,因此,浪费了时间。好好的利用这些信息,自然可以提高运行速度。
这个算法不是那么容易说清楚,我举一个例子说下(看算法导论看到的例子)。
我们用E来表示字母表的字母个数,这个例子字母表如下:{0,1,2,3,4,5,6,7,8,9},那么E就是10,如果采用小写英文字母来做字母表,那么E就是26,类此。
由于完成两个字符串的比较需要对其中包含的字符进行检验,所需的时间较长,而数值比较则一次就可以完成,那么我们首先把模式(匹配的字串)转化成数值(转化成数值的好处不仅仅在此)。在这个例子里我们可以把字符0~9映射到数字0~9。比如,”423″,我们可以转化成3+E*(2+E*4)),这样一个数值,如果这个值太大了,我们可以选一个较大的质数对其取模,模后的值作为串的值。
这边处理好了,那么接下来转换被匹配的字符串,取前m个字符,如上述操作对其取值,然后对该值进行比较即可。
若不匹配,则继续向下寻找,这时候该如何做呢?比如模式是”423″,而父串是”324232″;第一步比较423跟324的值,不相等,下一步应该比较423跟242了,那么我们这步如何利用前一步的信息呢?首先我们把324前去300,然后在乘以E(这里是10),在加上2不就成了242了么?用个式子表示就是新的值a(i+1)=(E(a(i)-S[i])*h-S[S+M])) MOD p,p是我们选取的大质数,S[i]表示父串的第i个字符,而a(i)表示当前值,本例中就是324,h表示当前值最高位的权值,比如,324,则h=100,就是3这个位的权值,形式化的表示就是h=(E^m-1)MOD p。当然拉,由于采用了取模操作,当两者相等时,未必是真正的相等,我们需要进行细致的检查(进行一次朴素的字符串匹配操作)。若不相等,则直接可以排除掉。继续下一步。