前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >5. 最长回文子串

5. 最长回文子串

作者头像
张伦聪zhangluncong
发布2022-10-26 18:19:23
7900
发布2022-10-26 18:19:23
举报

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为1000。

示例 1:

代码语言:javascript
复制
输入: "babad"
输出: "bab"
注意: "aba"也是一个有效答案。

示例 2:

代码语言:javascript
复制
输入: "cbbd"
输出: "bb"

解:这题很经典,我们使用Manacher算法(中文名:马拉车算法)来解决。

1.回文分为奇回文(aa)和偶回文(aba),在代码中解决起来比较麻烦所以我们可以进行填充#使得所有回文变成奇数,如#a#a#和#a#b#a#,为了代码处理方便不越界,我们再在前面填充最终变成#a#a#和

2.这里我们设s_new[i]为我们的填充后新字符串,如下图;再引入一个辅助数组p[i]表示对应i索引字符为中心的最长回文子串半径。

  • 如p[1]表示s_new[1]也就是#为中心对应最长回文子串半径为1,就是最长回文子串为#,半径为1即#
  • p[2]表示s_new[2]也就是a为中心对应最长回文子串半径为2,就是最长回文子串为#a#,半径为#a
  • p[5]表示s_new[5]也就是#为中心对应最长回文子串半径为5,就是最长回文子串#a#b#b#a#,半径为#a#b#

3.设当前已知的最长回文子串中心为id,mx为最长右边界,i是我们要求的值p[i]的中心,我们可以求得i关于id的对称点j=2*id-i,如下图。当mx>i的时候有p[i]=Math.min(p[2 * id - i], mx - i),具体解释看代码里面注释;但mx<=i的时候我们直接设p[i]=1,然后不断探索最长回文子串的左右边界,然后更新mx和id的值。

代码语言:javascript
复制
class Solution {
    public String longestPalindrome(String s) {
        if (s.length() <= 1) {
            return s;
        }
        // 预处理字符串,避免奇偶问题
        String str = preProcess(s);
        int id = 0;
        //mx 代表以 id 为中心的最长回文的右边界
        int mx = 0;
        //用来保存最长回文子串的中心
        int maxId = 0;
        //用来保存最长回文子串的半径
        int maxSpan = 0;
        //辅助数组p[i]代表对应字符串str中下标为i为中心的最长子串的半径
        int[] p = new int[str.length()];
        //跳过$符从#开始
        for (int i = 1; i < str.length(); i++) {
            //可能很多人不明白2 * id - i表示的是以id为中心最长子串i对应的另一个对标点,也就是
            //上图的j;如上图因为i,j是关于id的对称点,并且还是当前以id为中心最长子串的子集,所以
            //p[2 * id - i]的值也就是p[i]的值,但是因为mx > i,所以mx-i也是一个以i为中心的子串半径
            //i子串半径不能大于mx-i所以用一个min函数比较。
            p[i] = mx > i ? Math.min(p[2 * id - i], mx - i) : 1;
            //探索当前p[i]半径的边界
            while ((i + p[i]) < str.length() && str.charAt(i + p[i]) == str.charAt(i - p[i])) {
                p[i]++;
            }
            //如果右边界值大于mx,那要更新mx的值和id值
            if (i + p[i] > mx) {
                mx = p[i] + i;
                id = i;
            }
            //保存最新的最长子串半径和中点
            if (p[i] > maxSpan) {
                maxSpan = p[i];
                maxId = i;
            }
        }
        //去除占位符所以要除以2
        return s.substring((maxId - maxSpan) / 2, (maxSpan + maxId) / 2 - 1);
    }

    private String preProcess(String s) {
        // 如ABC,变为$#A#B#C#
        StringBuilder sb = new StringBuilder();
        sb.append("$");
        for (int i = 0; i < s.length(); i++) {
            sb.append("#");
            sb.append(s.charAt(i));
        }
        sb.append("#");
        return sb.toString();
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-08-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档