KMP

1.KMP简介

KMP是一个在字符串str中找一个子串pattern的匹配算法,在BF这种暴力匹配算法的基础上改进的。他是有三个人提出来的,所以用三个人的名字来命名这个算法

2.KMP解释

昨天和今天看了好几篇KMP的博客,有个人说的挺好的,坚持下去,就会有柳暗花明的感觉,下面是这位锅锅的博客地址,可以去看看他写的很详细

http://blog.csdn.net/v_july_v/article/details/7041827

我这里也说一下我的理解,做个记录

KMP和BF不同之处在于,i不用回溯到i - j - 1,而j也不用回溯到0这样就提高了算法的效率。

  (1)出现str[i]和pattern[j]不匹配值,i不动,j回溯到next[j](next[]存放的就是匹配失败时,j应该回溯到pattern中的位置)

  (2)str[i]与pattern[j]匹配时,i++,j++

这里我就不去讨论,为什么j直接跳转到next[j]的位置就okay了。我也不是很理解,这里面有什么前缀后缀,还有些什么之类的...感觉有点懂。其实这里感觉只要理解了怎么计算next[]数组的就okay了

3.next[]数组的计算

next[0] = -1这个是定义好的,不用计算

next[j] = ?呢这个就需要递推关系计算了,如果知道了前next[0,.....j - 1]那计算next[j]就可以看pattern[j] == pattern[k]了(k是pattern中前j个字符串的最大公共子串),
如果相等,则pattern[j] = k + 1;

如果不等,则继续寻找更小的k = next[k],在比较pattern[j] == pattern[k]

可以参考代码,以上解释只为做个记录

 1 package com.gxf.kmp;
 2 
 3 public class KmpSear {
 4     
 5     /**
 6      * 获取next[]的值
 7      * 这里用递推实现
 8      * @param pattern
 9      * @param next
10      */
11     public void getNext(String pattern, int next[]){
12         int k = -1;//最长公共前缀后缀
13         int j = 0;
14         next[0] = -1;//第一个字符的next[]值为-1
15         int length = pattern.length();
16         
17         while(j < length - 1){
18             if(-1 == k || pattern.charAt(j) == pattern.charAt(k)){//如果相同前缀和后缀长度+1
19                 k++;
20                 j++;
21                 if(pattern.charAt(j) == pattern.charAt(k)){//优化过后的,少一次递推
22                     next[j] = next[k];
23                 }
24                 else{
25                     next[j] = k;
26                 }
27             }
28             else{//如果相同前缀和后缀没有+1,递推找前面最小的相同前缀和后缀
29                 k = next[k];
30             }
31         }
32     }
33     
34     /**
35      * 匹配字符串
36      * @param str
37      * @param pattern
38      * @return
39      */
40     public int kmpSear(String str, String pattern){
41         int next[] = new int[pattern.length()];//next j的值
42         getNext(pattern, next);//获取next j的值
43         showNext(next);
44         int i = 0;//指向str
45         int j = 0;//指向pattern
46         
47         while(i < str.length() && j < pattern.length()){
48             if(j == -1 || str.charAt(i) == pattern.charAt(j)){
49                 j++;
50                 i++;//如果pattern移动到最开始的位置or两个字符刚好相等,同时移动i和j
51             }
52             else{
53                 j = next[j];//匹配失败,获取下一个j的位置
54             }
55         }
56         if(j == pattern.length()){
57             return i - pattern.length();
58         }
59         return -1;
60     }
61     
62     /**
63      * 输出next[]的内容
64      * @param next
65      */
66     public void showNext(int next[]){
67         for(int i = 0; i < next.length; i++){
68             System.out.print(next[i] + " ");
69         }
70         System.out.println();
71     }
72     
73     /**
74      * 测试程序
75      * @param args
76      */
77     public static void main(String args[]){
78         KmpSear kmpSear = new KmpSear();
79         String str = "substring searching algorithm";
80         String pattern = "search";
81         int index = kmpSear.kmpSear(str, pattern);
82         
83         System.out.println("index = " + index);
84     }
85 }
原文地址:https://www.cnblogs.com/luckygxf/p/4098406.html