Manacher演算法、KMP演算法

zxc123e發表於2015-12-18

一、Manancher演算法

Manacher演算法用於查詢子串中的迴文,演算法維持的三個變數十分重要pArr(下標所在位置字元迴文長度)、index(迴文中心)、pR(迴文半徑),這種演算法比其他演算法效率高的原因在於,它可以利用前面已計算過的迴文來判斷是否需要計算迴文。演算法在字串每個字元之間已經開始和末尾都插入特殊字元(可以是任意字元包括所查字串中字元),在計算迴文時就避免了奇迴文和偶迴文的問題。

演算法程式碼:

    public char[] manacherString(String str) {
        char[] charArr = str.toCharArray();
        char[] res = new char[str.length() * 2 + 1];
        int index = 0;
        for (int i = 0; i != res.length; i++) {
            res[i] = (i & 1) == 0 ? '#' : charArr[index++];
        }
        return res;
    }

    public int maxLcpsLength(String str) {
        if (str == null || str.length() == 0) {
            return 0;
        }
        char[] charArr = manacherString(str);
        int[] pArr = new int[charArr.length]; //下標所在位置字元迴文長度
        int index = -1; //迴文中心
        int pR = -1; //迴文半徑
        int max = Integer.MIN_VALUE;
        for (int i = 0; i != charArr.length; i++) {
            pArr[i] = pR > i ? Math.min(pArr[2 * index - i], pR - i) : 1;
            while (i + pArr[i] < charArr.length && i - pArr[i] > -1) {
                if (charArr[i + pArr[i]] == charArr[i - pArr[i]])
                    pArr[i]++;
                else {
                    break;
                }
            }
            if (i + pArr[i] > pR) {
                pR = i + pArr[i];
                index = i;
            }
            max = Math.max(max, pArr[i]);
        }
        return max - 1;
    }

二、KMP演算法

KMP演算法解決的是字串匹配問題,也是利用一個next陣列,利用前面的計算結果,為後面計算增加效率,next數字在KMP演算法中至關重要。
next陣列的定義:長度等於match字串長度
值為下標所在字元前面字串的標量(最長字首和最長字尾相等情況下的長度)

演算法程式碼

    public int getIndexOf(String s, String m) {
        if (s == null || m == null || m.length() < 1 || s.length() < m.length()) {
            return -1;
        }
        char[] ss = s.toCharArray();
        char[] ms = m.toCharArray();
        int si = 0;
        int mi = 0;
        int[] next = getNextArray(ms); //生成next陣列
        while (si < ss.length && mi < ms.length) {
            if (ss[si] == ms[mi]) {
                si++;
                mi++;
            } else if (next[mi] == -1) {
                si++;
            } else {
                mi = next[mi];
            }
        }
        return mi == ms.length ? si - mi : -1;
    }


    public int[] getNextArray(char[] ms) {
        if (ms.length == 1) {
            return new int[] { -1 };
        }
        int[] next = new int[ms.length];
        next[0] = -1;
        next[1] = 0;
        int pos = 2;
        int cn = 0;
        while (pos < next.length) {
            if (ms[pos - 1] == ms[cn]) {
                next[pos++] = ++cn;
            } else if (cn > 0) {
                cn = next[cn];
            } else {
                next[pos++] = 0;
            }
        }
        return next;
    }

相關文章