这个算法也看了大半天了,仔细看过两个人的博客,一个是传说中的Matrix67,另一个是阮一峰,个人感觉阮一峰的非常好理解,但是和百度其他人的做法有些出入,不过仍然是首选。Matrix67大神的也还可以,就是P[]的解释太复杂了,一整段文字带符号看得人欲仙欲死。
下面是两人的链接:
http://kb.cnblogs.com/page/176818/
http://www.matrix67.com/blog/archives/115
进入正题,这个算法不好理解的地方只有一个,就是预处理的next[]。看过阮一峰的博客之后,我感觉可以把next[]中存放的东西叫做循环的跳跃量,就是对长字符串的遍历不再以i++作为条件,而是以i+=next[j]作为条件。 这只是一种好理解的方法,真实意义还是要靠原博客去理解,而且这样写出来的预处理方法我总感觉不是O(m)的,还需要继续学习。
看了这么久,感觉头脑都不清醒了,有什么问题或细节上的错误欢迎指正。
import java.util.ArrayList;
import java.util.List;
public class General {
public static void KMP(String a,String b){
List<Integer> next = next_k(b);
for(int i=0;i<a.length();){
String result="";
for(int j=0;j<b.length();j++){
if(a.charAt(i+j)!=b.charAt(j)&&j!=0){
if(j==0){
i++;
break;
}
int offlen=j-next.get(j-1);
i+=offlen;
break;
} else result+=b.charAt(j);
}
if(result.length()==b.length()){
System.out.println(result+" "+i);
break;
}
}
}
public static List<Integer> next_k(String b){
List<Integer> next = new ArrayList<Integer>();
for(int i=0;i<b.length();i++){
next.add(i, 0);
}
int k=2;
while(k<b.length()){
for(int j=k;j>0;j--){
if(b.substring(0,j).equals(b.substring(k-j+1, k+1))){
next.set(k, b.substring(0,j).length());
break;
}
}
k++;
}
return next;
}
public static void main(String[] args) {
String s = "asdfwqwqgweafasdf";
String t = "dfw";
KMP(s,t);
}
}
两小时后改动。。。我认怂,标准的算法巧妙的多,但是原理也是一样,就是控制短字符串指针的偏移量。当然这种算出的next[]就是带-1的那种方法,需要去随便百度一个博客看一下生成规则。代码如下:
这里写代码片
static int KMP2( char[] str, char[] ptr )
{
int[] next = next(ptr);
int s_i = 0, p_i = 0;
while( s_i < str.length && p_i < ptr.length )
{
if( str[ s_i ] == ptr[ p_i ] ){
s_i++;
p_i++;
}else{
if( p_i == 0 ){
s_i++;
}
else{
p_i = next[ p_i - 1 ] + 1;
}
}
}
return ( p_i == ptr.length ) ? ( s_i - ptr.length ) : -1;
}
public static int[] next(char[] str){
int[] next=new int[str.length];
int i=0,j=1;
next[0] = -1;
for( i = 1; i < str.length; i++ )
{
j = next[ i - 1 ];
while( str[ j + 1 ] != str[ i ] && ( j >= 0 ) )
{
j = next[ j ];
}
if( str[ i ] == str[ j + 1 ] )
{
next[ i ] = j + 1;
}
else
{
next[ i ] = -1;
}
}
return next;
}