最长回文子串

题目

  • 给你一个字符串 s,找到 s 中最长的 回文 子串。

    示例 1:

    输入:s = "babad"
    输出:"bab"
    解释:"aba" 同样是符合题意的答案。
    

    示例 2:

    输入:s = "cbbd"
    输出:"bb"
    

    提示:

    • 1 <= s.length <= 1000
    • s 仅由数字和英文字母组成

分析

  • 预处理:将 "abc" 转换为 "#a#b#c#",这样奇偶长度回文都变成奇数长度

核心变量含义

int[] p = new int[t.length()];  // p[i] = 以位置i为中心的回文半径
int center = 0, right = 0;      // center = 当前覆盖最远的回文中心
                                // right = 该回文能到达的最右边界

算法的三种情况

假设我们正在处理位置 i

情况1:i 超出了已知范围

当 i >= right 时,无法利用之前信息,只能从头开始扩展
p[i] = 0,然后直接进入while循环扩展

情况2:i 在已知回文范围内

当 i < right 时,可以利用对称性:

     left    center    i    right
      |        |       |      |
   ...L........C.......i......R...
      |        |       |      |
     mi                       

mi = 2 * center - i  (i关于center的镜像位置)
if (i < right) {
    p[i] = Math.min(right - i, p[mi]);
}

为什么用Math.min?

  • p[mi]:镜像位置的回文半径
  • right - i:i到右边界的距离
  • 取最小值是因为i的回文不能超出已知的右边界

扩展阶段

while (i + p[i] + 1 < t.length() && i - p[i] - 1 >= 0
        && t.charAt(i + p[i] + 1) == t.charAt(i - p[i] - 1)) {
    p[i]++;
}

无论哪种情况,都要尝试继续扩展:

  • i + p[i] + 1i - p[i] - 1 是下一对要比较的字符
  • 如果相等,回文半径+1

更新center和right

if (i + p[i] > right) {
    right = i + p[i];
    center = i;
}

如果以i为中心的回文超出了当前的right,就更新center和right,为后续位置提供更多信息。

举例说明

对于字符串 "babad" → "#b#a#b#a#d#":

位置: 0 1 2 3 4 5 6 7 8 9 10
字符: # b # a # b # a # d #
p值: 0 1 0 3 0 1 0 1 0 1 0

当处理位置4('#')时:

  • center=3, right=6
  • mi = 2*3-4 = 2
  • p[4] = min(6-4, p[2]) = min(2, 0) = 0
  • 然后扩展发现s[3]='a', s[5]='b'不等,所以p[4]=0

这样通过利用已知信息,避免了大量重复计算,实现O(n)时间复杂度。

code

public class Main {
    public String longestPalindrome(String s) {
        if (s.length() == 0 || s.length() == 1)
            return s;

        String t = processString(s);
        int[] p = new int[t.length()];

        int center = 0, right = 0;
        int maxLen = 0, maxCenter = 0;

        for (int i = 0; i < t.length(); i++) {
            if (i < right)
                p[i] = Math.min(right - i, p[2 * center - i]);

            while (i + p[i] + 1 < t.length() && i - p[i] - 1 >= 0
                    && t.charAt(i + p[i] + 1) == t.charAt(i - p[i] - 1))
                p[i]++;

            if (i + p[i] > right) {
                right = i + p[i];
                center = i;
            }

            if (p[i] > maxLen) {
                maxLen = p[i];
                maxCenter = i;

            }
        }

        int st = (maxCenter - maxLen) / 2;
        return s.substring(st, st + maxLen);


    }

    public String processString(String s) {
        StringBuilder t = new StringBuilder();
        t.append('#');
        for (int i = 0; i < s.length(); i++) {
            t.append(s.charAt(i)).append('#');
        }
        return t.toString();
    }

}


posted @ 2025-07-21 09:32  TsumugiHane  阅读(34)  评论(0)    收藏  举报