记个笔记 KMP 复杂难用 too big to fails

现在回过头来看觉得没什么难度,但是刚开始看的时候看那些直接套用公式的代码,完全没法理解(专家盲点(Curse of knowledge))(感谢这个博主七年前的帖子)把next[]数组讲明白,但是发现自己也很难给别人讲明白 。先记录下自己思考的笔记,看看能不能渡有缘人

但是,对比起Sunday等其他搜索算法,真的觉得KMP几个巧妙的步骤真的复杂而没有必要。。建议直接sunday

KMP

BBCXABCDABXBCDABCDABDE
ABCDABD

X处失败时,返回上一位,前缀后缀最长公共元素长度AB=2,即从后缀AB处再开始对比,直接从开始X与C对比

模式串 A B C D A B D
前缀后缀最长公共元素 0 0 0 0 1 2 0
next[] -1 0 0 0 0 1 2

next[] 便于查找时判断子串从前往后是否有重复项

KMP的关键也就是建next[]数组:

​ 往后遍历

​ 先判断j是否与第一个元素相同

​ 标记&next[j+1]=1

​ 判断第二个元素...

private void getNext(String p, int next[]) {
            int len = p.length();
            int i = 0;
            int j = -1;
            next[0] = -1;//这个默认的,

            while (i < len - 1) {
                if (j == -1 || p.charAt(i) == p.charAt(j)) {

                    i++;
                    j++;
                    next[i] = j;
                } else

                    j = next[j];//restart from head
            }
        }

例子

母串H [i]

子串N [j]

回退next[]

i,j 从头开始比较,当H[i]!=N[j],如例子中i=10,j=6

向右移动子串j-next[j]=4

BBCXABCDABXBCDABCDABDE
ABCDABD

并且继续从i处开始比较(j=next[j]=2),...右移...☞匹配

 public int strStr(String haystack, String needle) {
            if (needle.length() == 0)
                return 0;
            int i = 0;
            int j = 0;

            int[] next = new int[needle.length()];
            getNext(needle, next);
            while (i < haystack.length() && j < needle.length()) {

                if (j == -1 || haystack.charAt(i) == needle.charAt(j)) {
                    i++;
                    j++;
                } else {

                    j = next[j]; // j回到指定位置
                }
                if (j == needle.length())
                    return i - j;
            }
            return -1;
        }
原文地址:https://www.cnblogs.com/impw/p/15578890.html