LeetCode热题100:5.最长回文子串

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

示例 1:

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

示例 2:

复制代码
输入:s = "cbbd"
输出:"bb"

提示:

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

直接上代码,不懂请留言或私信我

java 复制代码
class Solution {

    public String longestPalindrome(String s) {
        //s的最小长度为1,如果只有长度1,直接返回自己
        if(s.length() == 1) {
            return s;
        }    
        //转换为字符数组进行操作
        char[] sArr = s.toCharArray();
        //转换为Manacer字符数组
        char[] manacerArr = getManacerArr(sArr);
        /**定义两个变量mostRight表示以某个位置为圆心的回文圆所能扩到的最右位置,maxCenter表示扩到mostRight
        的圆的直径,当前我们还没有遍历任何位置,这两个都设置为-1*/
        int mostRight = -1;
        int maxCenter = -1;
        //maxRadiusIndex表示最大半径出现的位置,现在可以设置为0
        int maxRadiusIndex = 0;
        /**maxRadiusArr表示以每个点为圆心的最大的回文直径,这里的半径和圆心所依赖的都是manacer这个数组的位置*/
        int[] maxRadiusArr = new int[manacerArr.length];
        /**curIndex表示当前到了哪个位置,当然我们从0开始遍历 */
        int curIndex = 0;
        /**最长的回文半径 */
        int maxRadius = 0;
        /**从0开始遍历一直到最后的位置*/
        while(curIndex < manacerArr.length) {
            //如果当前的位置在mostRight外就暴力扩(mostRight是以前面某个点为圆心的最右边的位置,在他前面有)
            if(curIndex > mostRight) {
                //目前暂定他的半径为0,如果能找到更长的就更新
                int r = 0;
                //持续比较他的左右对称位置看是否相等,这里需要判断是否越界
                //左边是
                while(curIndex - r - 1>= 0 && curIndex + r + 1 < manacerArr.length 
                && manacerArr[curIndex - r -1] == manacerArr[curIndex + r + 1]) {
                    r ++;
                }
                //以当前位置为圆心的回文半径最大到了r,记录到maxRadiusArr,并尝试更新max
                maxRadiusArr[curIndex] = r;
                //本来他就在mostRight的外面,必定能把mostRight右扩
                mostRight = curIndex + r;
                maxCenter = curIndex;
                if(r > maxRadius) {
                    maxRadius = r;
                    maxRadiusIndex = curIndex;
                }
            } else {
                /**如果i在mostRight的左边,就需要考虑i关于maxCenter的对称位置iMirror,分为三种情况
                1.如果iMirror为圆心的回文最左位置在maxCenter的回文左边界的右边,那i和它的半径一样
                2.如果iMirror为圆心的回文最左位置在maxCenter的回文左边界的左边,那i得回文右边界就是mostRight
                3.如果iMirror为圆心的回文最左位置和maxCenter的回文左边界的左边重合,则i的回文右边界至少在mostRight,可以尝试去扩展 */
                int iMirror = 2 * maxCenter - curIndex;
                int iMirrorLeftBound = iMirror - maxRadiusArr[iMirror];
                int maxCenterLeftBound = 2 * maxCenter - mostRight;
                if(iMirrorLeftBound > maxCenterLeftBound) {
                    maxRadiusArr[curIndex] = maxRadiusArr[iMirror];
                } else if(iMirrorLeftBound < maxCenterLeftBound) {
                    maxRadiusArr[curIndex] = mostRight - curIndex;
                } else {
                    /**最小半径是到mostRight,还可能更大,尝试扩展一下 */
                    int r = mostRight - curIndex;
                    while(curIndex - r - 1>= 0 && curIndex + r + 1 < manacerArr.length 
                        && manacerArr[curIndex - r - 1] == manacerArr[curIndex + r + 1]) {
                        r ++;
                    }
                    mostRight = curIndex + r;
                    maxCenter = curIndex;
                    if(r > maxRadius) {
                        maxRadius = r;
                        maxRadiusIndex = curIndex;
                    }
                    maxRadiusArr[curIndex] = r;
                }
            }
            curIndex ++;
        }
        /**最大回文子串在manacer中的是以maxCenter为圆心,maxRadius为直径的字符串
        回到原字符串中都除以2即可,但是记得subString的特性,后面不包含,所以要+1*/
        if(maxRadiusIndex % 2 == 1) {
            //在实轴上的时候
            return s.substring(maxRadiusIndex/2 - maxRadius/2, maxRadiusIndex/2 + maxRadius/2 + 1);
        } else {
            //在虚轴("#")上的时候
            return s.substring((maxRadiusIndex + 1)/2 - maxRadius/2, (maxRadiusIndex + 1)/2 + maxRadius/2 );
        }
        
    }

    public char[] getManacerArr(char[] arr) {
        //manacer就是把所有字符的间隔位置以及开头结尾加上#
        char[] manacerArr = new char[2*arr.length + 1];
        for(int i = 0; i < manacerArr.length; i++) {
            if(i % 2 == 0) {
                manacerArr[i] = '#';
            } else {
                manacerArr[i] = arr[i / 2];
            }
        }
        return manacerArr;
    }
    public void print(char[] arr) {
        for(int i = 0; i < arr.length; i++) {
            System.out.print(arr[i]);
        }
    }
    public void print(int[] arr) {
        for(int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
    }
}

运行结果:

相关推荐
琹箐13 分钟前
最大堆和最小堆 实现思路
java·开发语言·算法
renhongxia142 分钟前
如何基于知识图谱进行故障原因、事故原因推理,需要用到哪些算法
人工智能·深度学习·算法·机器学习·自然语言处理·transformer·知识图谱
坚持就完事了43 分钟前
数据结构之树(Java实现)
java·算法
算法备案代理1 小时前
大模型备案与算法备案,企业该如何选择?
人工智能·算法·大模型·算法备案
赛姐在努力.1 小时前
【拓扑排序】-- 算法原理讲解,及实现拓扑排序,附赠热门例题
java·算法·图论
我能坚持多久2 小时前
【初阶数据结构01】——顺序表专题
数据结构
野犬寒鸦2 小时前
从零起步学习并发编程 || 第六章:ReentrantLock与synchronized 的辨析及运用
java·服务器·数据库·后端·学习·算法
霖霖总总2 小时前
[小技巧66]当自增主键耗尽:MySQL 主键溢出问题深度解析与雪花算法替代方案
mysql·算法
rainbow68892 小时前
深入解析C++STL:map与set底层奥秘
java·数据结构·算法
wangjialelele3 小时前
平衡二叉搜索树:AVL树和红黑树
java·c语言·开发语言·数据结构·c++·算法·深度优先