前面腾讯面试这题时,很多概念都搞混了,过来反省,好好研究了下KMP算法,把它实现。

大体过程数据结构上都说得很明白,

这里说说自己的感悟吧:

主要是next数组的作用:

现有一个主串s和模式串t,KMP算法会首先对模式串t求一个辅助数组next,有个这个next后我们每次匹配时主串的下标i就不用回溯,模式串的下标j回溯到next[j]的位置。

看似next值越大越好,其实不是这样,next值当然是为0,为-1时最好。这个next数值k的意思表示当si!=tj时,那么tj-ktj-k+1...tj-1和主串的s0s1..sk-1是匹配的,那么

其实需要回溯k位置,即主串回溯到i-k位置和t0比较。当然,由于这一串又相等了,我们可以认为i不需要回溯,j直接移到k位置来比较就好。这样宏观来看,就是模式串t滑动

了j-next[j]个位置,那么当时是next[j]越小时,滑动的距离就越多,效率就越高。

java实现如下:

View Code
private static int[] getNext(char[] s) {
        int len = s.length, j = 0, k = -1;
        int[] next = new int[len];
        next[0] = k;
        while (j < len - 1) {
            if (k == -1 || s[j] == s[k]) {
                j++;
                k++;
                next[j] = k;
            } else
                k = next[k];
        }
        return next;
    }

    private static int match(char[] oStr, char[] tStr) {
        int i = 0, j = -1;
        int[] next = getNext(tStr);
        for (int k : next) {
            System.out.print(k + ",");
        }

        while (i < oStr.length && j < tStr.length) {
            if (j == -1 || oStr[i] == tStr[j]) {
                i++;
                j++;
            } else
                j = next[j];
        }
        if (j >= tStr.length)
            return i - j;
        else
            return -1;
    }