Leetcode_0005_LongestPalindromicSubstring 最长回文子串

124 阅读1分钟
/**
 * i: 当前位置
 * i': i关于C的对称点
 * L: 回文最左边界
 * R: 回文最右边界
 * C: 回文中心
 * max: 回文最大半径
 * maxC: 当达到最大半径时的中心
 *
 * 分情况:
 *  i 在 R 外: 直接暴力往外扩
 *  i 在 R 内:
 *      1. parr[i][L,R] 内, parr[i] = parr[i']
 *      2. parr[i] 超出了 [L,R]的范围, 从R 开始往外扩
 *      3. parr[i] 刚好就是[L,R], parr[i] = R - i
 *
 *  所以最小不用往外扩的范围就是,一个字符它本身一定是回文的
 *      R > i ? Math.min((R - i), parr[C - (i - C)]) : 1;
 */
public class Leetcode_0005_LongestPalindromicSubstring {
    public static String longestPalindrome(String str) {
        if (str == null || str.length() == 0) {
            return "";
        }
        char[] charArr = str2ManacherStr(str);
        // 回文半径数组
        int[] pArr = new int[charArr.length];
        // 回文最右边界的下一个位置 [L,R)
        int R = -1;
        // 回文中心
        int C = -1;
        // 回文最大半径
        int max = -1;
        // 最大半径的中心
        int maxC = -1;
        for (int i = 0; i < charArr.length; i++) {
            // 找到最小不用往外扩的位置
            pArr[i] = R > i ? Math.min(pArr[2 * C - i], R - i) : 1;
            // 暴力扩
            while (i + pArr[i] < charArr.length && i - pArr[i] >= 0) {
                if (charArr[i + pArr[i]] == charArr[i - pArr[i]]) {
                    pArr[i]++;
                } else {
                    // 第一没找到就匹配失败
                    break;
                }
            }
            // 更新R C
            if (i + pArr[i] > R) {
                R = i + pArr[i];
                C = i;
            }
            // 更新max maxC
            if (pArr[i] > max) {
                max = pArr[i];
                maxC = i;
            }
        }
        StringBuilder builder = new StringBuilder();
        for (int i = maxC - max + 1; i < maxC + max; i++) {
            builder.append((i & 1) == 0 ? "" : charArr[i]);
        }
        return builder.toString();
    }

    private static char[] str2ManacherStr(String str) {
        char[] manStr = new char[str.length() * 2 + 1];
        int index = 0;
        for (int i = 0; i < manStr.length; i++) {
            manStr[i] = (i & 1) == 0 ? '#' : str.charAt(index++);
        }
        return manStr;
    }
}