获取最长回文子串

惰性星云
• 阅读 796

以下是最长回文子串的Manacher‘s Algorithm相关代码,相关逻辑已在注释中注明:

public static String solution(String s) {
    if (s.length() == 0) {
        return "";
    }
    //我们原有的字符串可能存在两种回文子串,一种是具有基数个元素例如aba 一种是具有偶数个元素例如abba 这样的话分情况判断比较复杂
    //所以我们对原字符串进行扩充 在相邻元素中插入特殊值 插入后的原基数回文子串变成了#a#b#a# 原偶数回文子串变成了#a#b#b#a# 都变成了基数回文子串 便于后续的运算
    char[] chars = new char[s.length() * 2 + 1];
    for (int i = 0; i < s.length(); i++) {
        chars[2 * i] = '#';
        chars[2 * i + 1] = s.charAt(i);
    }
    chars[chars.length - 1] = '#';
    //初始化标识数组,此数组用来表示chars中某个元素的回文子串半径值
    int[] l = new int[chars.length];
    l[0] = 1;
    //其中max为已探明的回文子串中能扩展到最右的边界位置 id为前述回文子串的中心位置 resid为最终解的中心值
    int max = 1, id = 0, resid = 0;
    //循环获取最长回文子串
    for (int i = 1; i < l.length; i++) {
        // 当max>i时当前数组为如下结构:
        //  beg-------min----j-----id-----i----max-----end
        //其中beg和end分别为数组的边界位置 j=2*id-i 是i对于id的对称值 (当max>i时此对称值肯定会有并且肯定大于min,当max<i时此对称值可能已经越界) min是以id为中心的回文子串的最小值,所以min~max为一个对称的回文序列
        //l[j]记录了以j为中心的回文序列半径 因为min~max本来就是一个回文串 所以i存在如下几种情况
        // 1、如果以j为中心的回文序列在min~max之间的话 对称的以i为中心的回文序列也在min~max之间
        // 2、如果以j为中心的回文序列超出了min~max的范围的话,假设为jmin~jmax.可以保证min~jmax-(min-jmin)之间的回文串对称到i周围也是回文串
        //根据如上的方法 我们得到了以i为中心的一个回文子串,但这个回文子串不是最终的值 需要继续迭代扩充
        //当max<i时数组为如下结构
        //  beg------min-----id-----max----i-----end
        //此时无法根据min到max之间的回文对称来判断i的周围环境,只能给i的回文串长度赋值为1 然后进行迭代扩充
        l[i] = max > i ? Math.min(l[2 * id - i], max - i) : 1;
        //对获取的半径进行迭代扩充回文序列的长度
        while (i - l[i] >= 0 && i + l[i] <= chars.length - 1 && chars[i - l[i]] == chars[i + l[i]]) {
            l[i]++;
        }
        //如果当前的回文序列最右边界位置已经大于了max 则更新max和id为当前回文序列的相关值
        if (i + l[i] - 1 > max) {
            max = i + l[i] - 1;
            id = i;
        }
        //如果当前的回文序列长度为最长,则更新resid的值
        if (l[i] > l[resid]) {
            resid = i;
            //如果当前的回文序列长度和之前记录的最长回文序列的长度相同则存在如下情况:
            // 1、之前最长回文序列长度为1 但是此时中心为扩充值 比如a#b中 #为中心 长度为1 这样的序列并不能当作解来使用,如果发现了以原字符串中字符为中心的长度相同的串则要更新这个值
            // 2、之前最长回文序列中心值为扩充值,例如#a#a#长度为5对应原字符串中子串为aa,但是存在以原字符串的值为中心的序列比如a#b#a 长度为5,此时对应的原字符串为aba 可见长度相同但是最后的结果有差别
            // 所以此处进行判断来避免如上两种问题
        } else if (l[i] == l[resid] && resid % 2 == 0) {
            resid = i;
        }
    }
    StringBuilder sb = new StringBuilder();
    int resBeg = resid - l[resid] + 1;
    //根据得到的resid和其半径 获取最后的结果
    while (resBeg <= resid + l[resid] - 1) {
        if (resBeg % 2 == 1) {
            sb.append(chars[resBeg]);
        }
        resBeg++;
    }
    return sb.toString();
}
点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
美凌格栋栋酱 美凌格栋栋酱
7个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
一只编程熊 一只编程熊
4年前
【LeetCode每日一题 Day 5】5. 最长回文子串
大家好,我是编程熊,今天是LeetCode每日一题的第五天,一起学习LeetCode第五题《最长回文子串》。题意给你一个字符串s,找到s中最长的回文子串。示例txt输入:s"babad"输出:"bab"解释:"aba"同样是符合题意的答案。题解方法一采用简单暴力的方法,枚举每一个位置为单独回文中心(长度为奇数的子串,如aba)或者回文中心
Kubrnete Kubrnete
4年前
动态规划之马拉车算法
问题描述:给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。如"abc"有三个回文子串‘a','b','c'.示例1:输入:"abc"输出:3解释:三个回文子串:"a","b","c"示例2:输入:"aaa"输出
Wesley13 Wesley13
3年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Stella981 Stella981
3年前
HDU 2594(求最长公共前后缀 kmp)
题意是在所给的两个字符串中找最长的公共前后缀,即第一个字符串前缀和第二个字符串后缀的最长相等串。思路是将两个字符串拼接在一起,然后直接套用kmp算法即可。要注意用next会报编译错误,改成Next才过……但next确实不是c关键字。代码如下:!(https://oscimg.oschina.net/oscnet/5
Wesley13 Wesley13
3年前
DP
套路:最长, 最优,最大,最小,最长,计数先写出递归式stringsa"abcd";stringsb"becd";intf(inta,intb){if(a0||b0)return0;//最小规模为2个字符的比较if(
Wesley13 Wesley13
3年前
125. 验证回文串
\TOC\题目给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。说明:本题中,我们将空字符串定义为有效的回文串。示例1:输入:"Aman,aplan,acanal:Panama"输出:true示例2:输入:"raceacar"输出
Stella981 Stella981
3年前
JavaScript常用函数
1\.字符串长度截取functioncutstr(str,len){vartemp,icount0,patrn/^\x00\xff/,strre"";for(vari
Stella981 Stella981
3年前
LeetCode:(14. 最长公共前缀!!!!!)
题目:14\.最长公共前缀编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串“”。示例1:输入:\“flower”,“flow”,“flight”\输出:“fl”示例2:输入:\“dog”,“racecar”,“car”\输出:“”
小万哥 小万哥
1年前
Kotlin 字符串教程:深入理解与使用技巧
Kotlin中的字符串用于存储文本,定义时使用双引号包围字符序列,如vargreeting&quot;Hello&quot;。Kotlin能自动推断变量类型,但在未初始化时需显式指定类型,如varname:String。可通过索引访问字符串元素,如txt0获取首字符。字符串作为对象,拥有属性和方法,如length获取长度,toUpperCase()转大写。可使用compareTo()比较字符串,indexOf()查找子串位置。字符串中嵌入单引号表示文本内的引号,如&quot;It&39;salright&quot;。使用或plus()
惰性星云
惰性星云
Lv1
愿山野浓雾都有路灯,风雨漂泊都有归舟。
文章
4
粉丝
0
获赞
0