力扣5-最长回文子串-(Manacher算法)

题目:输出最长回文子串,原串最长1000

坑:特判s="";

复习一下马拉车算法,之前写的只求答案,没有要输出子串。

class Solution {
    public String longestPalindrome(String s) {
        //特判s=""
        if(s.length()==0)
            return s;


           char[] a=new char[20005];
           int [] p=new int[20005];//记录每个位置的半径
        a[0]='!';//首尾加上不相干字符
        int cnt=1;//a的下标计数
        for(int i=0;i<s.length();i++){
            a[cnt]='#';
            cnt++;
            a[cnt]=s.charAt(i);
            cnt++;    
        }
        a[cnt]='#';
        cnt++;
        a[cnt]='@';//首尾加上不相干字符
        
        /* 预处理结束,算法开始
        i:表示当前遍历到哪一个下标的字符
      p[idx]:表示下标为idx的字符的回文半径,包括自身
      id:目前遍历过程中能延展到最右的回文的中心点
      mx:目前遍历过程中能延展到最右的下标位置,姑且称之为探测的最远长度
      j:以id为中心的关于i对称的字符,在id的左边,已经遍历过了,p[j]已经确定了的 
        ans:最长回文子串的长度
        t:最长回文子串在原串的起始下标
        */
        int ans=2;
        int t=0;
        int id=1,mx=1;
        int len=2*s.length()+3;//插#加首尾后的长度
        for(int i=1;i<len;i++) {
            int j=2*id-i;
            if(mx>i) {
                if(mx-i>=p[j])
                    p[i]=p[j];//i和j以id对称,但以id为中心的字符串包括了以i或j为中心的的最长回文子串
                else 
                    p[i]=mx-i;
            }else 
                p[i]=1;
            
            //暂定了p[i],还是有可能更大,中心扩展
            while( a[ i+p[i] ]==a[ i-p[i] ] )
                p[i]++;
            
            if(i+p[i]>mx) {//更新最右点和对应的id
                id=i;
                mx=id+p[i];
            }
            
            if(p[i]>ans) {//更新答案
                ans=p[i];
                t=(id-p[id])/2;//记录最长回文子串在原串的起始下标
            }

            
        }
        ans--;//去掉#作为对称边缘带来的影响
        return s.substring(t,t+ans);
    }
}

 

猜你喜欢

转载自www.cnblogs.com/shoulinniao/p/12331147.html