KMP算法如果理解原理的话,其实很简单。
这里根据自己的理解简单介绍下。
KMP算法的名称由三位发明者(Knuth、Morris、Pratt)的首字母组成,又称字符串查找算法。
个人觉得可以理解为最小回溯算法,即匹配失效的时候,尽量少回溯,从而缩短时间复杂度。
KMP算法有两个关键的地方,1)求解next数组,2)利用next数组进行最小回溯。
| j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 
|---|---|---|---|---|---|---|---|---|---|
| p | a | b | a | a | b | c | a | b | a | 
| next[j] | -1 | -1 | 0 | 0 | 1 | -1 | 0 | 1 | 2 | 
下图表示了第一次不匹配,第二次匹配的过程,其它过程可以类推。其中 或 覆盖部分表示最长匹配串。 为待判定位置, 为已判定位置。
s ××××××××××××××××××××××××××××××××××××××××××××
p ××××××××××××××
在j处不失配时,前面的有部分匹配,这时需要利用next数组信息进行最小回溯。
s ××××××××××××××××××××××××××××××××××××××××××××
p ××××××××××××××
(这里 i 指向 s , j 指向 p。)
注意在 j = 0 的时候失配时,直接 i++ 即可。
当 j > 0 的时候,需要利用next数组最快找到 p[ j ] == s[ i ] 的位置。
如果 j 移动到了0还找不到,则 i++,然后继续匹配。
这里我们可以发现只有 j 回溯了,i没有回溯,但是由于普通版本的 KMP 算法 j 需要不停地回溯直到找到合适的回溯位置,因此速度不是特别快,还可以继续优化,感兴趣的读者可以想想如何事先求解好next数组从而不需要不停地回溯。
strStr返回的是首次匹配的地址,如果不能匹配则返回NULL。
class Solution {
public:
    vector<int> getNext(char* &s){
        vector<int> next(strlen(s), -1);
        for(int i=1; i<strlen(s); i++){
            int j = next[i-1]; /* 前一个字符的最长匹配长度 */
            
            while(s[j+1] != s[i] && j>=0) 
                j = next[j];
            if(s[j+1] == s[i]) 
                next[i] = j+1;
            // else 默认为-1
        }
        return next;
    }
    char *strStr(char *haystack, char *needle) {
        if(haystack==NULL || needle==NULL) return NULL;
        if(strlen(haystack) < strlen(needle)) return NULL;
        if(strlen(needle) == 0) return haystack;
        vector<int> next = getNext(needle);
        int i = 0;
        int j = 0;
        int haystackLen = strlen(haystack);
        int needleLen = strlen(needle);
        while(i<haystackLen && j<needleLen){
            if(haystack[i] == needle[j] ) {
                i++;
                j++;
                if(j == needleLen) return haystack + i - j;
            }else{
                if(j == 0) i++;
                else j = next[j-1]+1; /* 该步骤可以优化 */
            }
        }
        return NULL;
    }
};
由于有人问有没有java版本的,由于鄙人java比较挫,写java时部分还写成了scala的语法,不知道代码是否规范,有优化的地方还麻烦java方面的大神指点。
import java.util.*;
public class StrStrSolution {
    private List<Integer> getNext(String p){
        List<Integer> next = new ArrayList<Integer>();
        next.add(-1);
        for(int i=1; i<p.length(); i++){
            int j = next.get(i-1);
            while(p.charAt(j+1) != p.charAt(i) && j>=0) 
                j = next.get(j);
            if(p.charAt(j+1) == p.charAt(i)) 
                next.add( j + 1 );
            else
                next.add( -1 );            
        }
        return next;
    }
    public String strStr(String haystack, String needle) {
        if (haystack == null || needle == null) return null;
        if (needle.length() == 0) return haystack;
        if (needle.length() > haystack.length()) return null;
        
        List<Integer> next = getNext(needle);  
        int i = 0;  
        int j = 0;
        int haystackLen = haystack.length();
        int needleLen = needle.length();  
        while(i < haystackLen && j < needleLen){  
            if(haystack.charAt(i) == needle.charAt(j) ) {  
                i++;  
                j++;  
                if(j == needleLen) return haystack.substring(i - j);  
            }else{  
                if(j==0) i++;  
                else j = next.get(j-1)+1; 
            }  
        }  
        return null;
    }
    public static void main(String[] args) {
        String s = "babcabaabcacbac";
        String p = "abaabcac";
        StrStrSolution sol = new StrStrSolution();
        System.out.println(sol.strStr(s,p)); 
    }
}【数据结构&&算法系列】KMP算法介绍及实现(c++ && java),布布扣,bubuko.com
【数据结构&&算法系列】KMP算法介绍及实现(c++ && java)
原文:http://blog.csdn.net/piaoxuefengqi/article/details/27837847