Manacher算法

整理自左程云算法课

暴力法:
以每个字符串为中心,判断其左右两边的相等的最长字符串
往字符串中间添加特殊字符,可以满足字符串长度为奇数和偶数的情况
eg.
m:  1 2 2 1 3 3 1 2 2 1
n: #1#2#2#1#3#3#1#2#2#1#
maxLength: 在最中间的位置,找到最长的回文半径 21/2 = 10
时间复杂度: O(n^2)

Manacher算法:
1. 回文半径c: 包含字符x在内的,回文半径
eg.
a#1#2#x#2#1#b
x的回文半径c为6, #1#2#x 或者 x#2#1#

2. 回文半径数组: 保存字符串m中每个字符的回文半径

3. 整体最右回文右边界: 
eg.
n   :    #  1  #  2  #  3  #  2  #  1   #
i   :    0  1  2  3  4  5  6  7  8  9  10
R   :-1  1  2  2  4  4 10 10 10 10 10  10

算法流程
- i处于R外面,使用暴力扩展
- i处于R里面,c一定位于i左边,那么肯定有i的对称点i'
	- i'的回文半径位于c的回文半径内
	- i'的回文半径超出c的回文半径,那么i的回文半径只有R-i
	- i'的回文半径,刚好与L重合·,那么需要验证以i为半径,验证R+1的位置

时间复杂度: O(n)

eg. 考虑i在R里面
n :     [          o          ]
                   c          R-1    回文半径:
p1:      [ i']           [ i ]     radius[2*c-i], i'的回文半径
p2:    [   i'  ]       [   i   ]       R-i, 去除不符合大于R边界的
p3:     [  i' ]         [  i  ]      需要验证
public class Manacher {
    public static int maxLengthOfPalindrome(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }

        char []chars  = toManacherString(s);
        int  []radius = new int[chars.length];
        int R = -1; // 整体最右回文右边界的下一个位置   L[...C...]R
        int C = -1; // 整体最右回文时的回文半径中心
        int max = Integer.MIN_VALUE;

        /*
         *  以i作为作为回文中点, 找最长的回文串
         *  三目运算符和while循环实现四种情况的判断
         *      - i >= R: 表示i在R外部, 暴力扩展, 此时回文半径至少为1
         *      - i <  R: 表示i在R里面, i的回文半径可能在以C为回文半径的圈内, 也可能不是
         *      - 在while内: 可以进行上面的暴力扩展, 也可以是i在R内, 作为扩不动的情况直接break
         */
        for (int i = 0; i < chars.length; ++i) {
            radius[i] = i >= R ? 1 : Math.min(radius[2*C-i], R-i);
            while (i + radius[i] < chars.length && i - radius[i] > -1) {
                if (chars[i+radius[i]] == chars[i-radius[i]]) {
                    ++radius[i];
                }
                else {
                    break;
                }
            }

            if (i + radius[i] > R) {
                R = i + radius[i];
                C = i;
            }
            max = Math.max(max, radius[i]);
        }

        /*
         * 返回值s字符串的最大回文长度 等于最大回文半径 - 1
         * eg.
         *    1221  ==> #1#2#2#1#   返回值为 5-1 = 4
         *    12321 ==> #1#2#3#2#1# 返回值为 6-1 = 5
         */
        return max - 1;
    }

    public static char []toManacherString(String s) {
        char []chars = new char[s.length() * 2 + 1];
        int index = 0;
        for (int i = 0; i < chars.length; ++i) {
            chars[i] = i % 2 == 0 ? '#' : s.charAt(index++);
        }

        return chars;
    }

    public static void main(String []args) {
        String s1 = "123";
        String s2 = "ab43534c1234321ab";

        System.out.println("s1: " + maxLengthOfPalindrome(s1));
        System.out.println("s2: " + maxLengthOfPalindrome(s2));
    }
}

你可能感兴趣的:(Algorithm)