KMP笔记

匹配字串 ABABCABAA

 


最长公共前后缀

0  A                        
0  AB                  
1  ABA                  // 前缀A,后缀A
2  ABAB                // 前缀AB,后缀AB
0  ABABC
1  ABABCA           // 前缀A,后缀A
2  ABABCAB         // 前缀AB,后缀AB
3  ABABCABA      // 前缀ABA,后缀ABA
1  ABABCABAA    // 前缀A,后缀A

 

下标 0 1 2 3 4 5 6 7 8
匹配字串 A B A B C A B A A
next数组 0 0 1 2 0 1 2 3 1

 

 

 

 

next里面的值可以看做是公共前后缀的长度,比如"ABAB",最后一个B对应的也就是是next[3] = 2,这个2就是表示了长度(前缀"AB",后缀"AB")。

但是如果想直接用next[3]访问前缀的最后的B呢?把数组的每个值减1就好了。

新next数组 -1 -1 0 1 -1 0 1 2 0

 

 

 void nextBuilder(char[] next, String needle) {
        int j = -1; //起始为-1
        next[0] = j; //赋初始值,这其实是动态规划问题

        //准确说j+1才是长度,但是为了方便后来不用-1,所以就用 j 啦。
//用next数组的话是 len = next[len-1] 这样回溯也很好理解了
for (int i = 1; i < needle.length(); i++) { //如果不相等,就到 当前前后缀长度减一的前后缀 的位置 while (j >= 0 && needle.charAt(j+1) != needle.charAt(i)) { j = next[j]; //回溯 } //如果相等,长度+1 if (needle.charAt(j+1)) == needle.charAt(i)) { j++; } next[i] = j; } }

这里构造的是每个值减一的next数组,如果不太明白,照着推一遍就好啦。

 

next数组是干什么用的呢?

A B A B A B A B C A B A A B
A B A B C                  
    A B A B C              
        A B A B C A B A A  

 

 

 

 

 

蓝色区域就是一路匹配的过程,有没有发现绿色(忽略的部分)和 上一层的蓝色区域有什么相似的地方?把与后缀相同的前缀给略过了。

这样时间复杂度大大降低。

 

KMP算法和next的构造很相似

 int kmpFind(String haystack, String needle) {
        int[] next = new int[needle.length()];
        nextBuilder(next, needle);
        int j = -1;
        for (int i = 0; i < haystack.length(); i++) {
            while (j >= 0 && needle.charAt(j+1) != haystack.charAt(i)) {
                j = next[j];
            }
            if (needle.charAt(j+1) == haystack.charAt(i)) {
                j++;
            } 
            if (j == needle.length() - 1) {
                return i - j;
            }
        }
        return -1;
    }

 

上一篇:idea使用技巧


下一篇:LeetCode 实现strStr()