前缀函数(kmp)

原理
1.求前缀函数,普通写法
/**
     *
     * 时间复杂度: O(n^3)
     * @param s 字符串
     * @return  pai
     */
public int[] pf(String s) {
    char[] c = s.toCharArray();
    int n = c.length;
    int[] pi = new int[n];
    for(int i = 1;i < n;i++) {
        for(int j = 1;j <= i;j++) {
            int l = 0;
            int r = j;
            while(r < n && c[l] == c[r]) {
                l++;
                r++;
            }
            if(r > i) {
                pi[i] = i - j + 1;
                break;
            }
        }
    }

    return pi;
}
2.求前缀函数,第一个优化

观察相邻的pai[i]pai[i + 1],发现pai[i + 1] <= pai[i] + 1,那么对于每个pai[i]都能跳过i - pai[i + 1]个前缀,大大提高效率

/**
     *
     * 时间复杂度: O(n^2)
     * @param s 字符串
     * @return  pi
     */
public int[] pf(String s) {
    char[] c = s.toCharArray();
    int n = c.length;
    int[] pi = new int[n];
    for(int i = 1;i < n;i++) {
        if(c[i] == c[pi[i - 1]]) {
            pi[i] = pi[i - 1] + 1;
            continue;
        }
        for(int j = i - pi[i - 1] + 1;j <= i;j++) {
            int l = 0;
            int r = j;
            while(r < n && c[l] == c[r]) {
                l++;
                r++;
            }
            if(r > i) {
                pi[i] = i - j + 1;
                break;
            }
        }
    }

    return pi;
}
3.求前缀函数,第二个优化
/**
     *
     * 时间复杂度: O(n)
     * @param s 字符串
     * @return  pi
     */
public int[] pf(String s) {
    char[] c = s.toCharArray();
    int n = c.length;
    int[] pi = new int[n];
    for(int i = 1;i < n;i++) {
        int secondLen = pi[i - 1];
        while(secondLen > 0 && c[i] != c[secondLen]) {
            secondLen = pi[secondLen - 1];
        }
        if(c[i] == c[secondLen]) secondLen++;
        pi[i] = secondLen;
    }

    return pi;
}
转载请注明出处