manacher

  manacher:是一个可以在O(n)的复杂度中返回字符串s中最长回文子串长度的算法。

  关于:

arr[i]=maxR>i?min(arr[2*id-i],maxR-i):1;

  其中arr[i]是以i为中心的最长回文半径,maxR是最右侧回文半径相当于上图中mx,min的作用是(用上图来解释):计算arr数组的值是从左向右计算的,在计算i的回文半径时,j的回文半径已经计算过,所以arr[2*id-i]其实就是arr[j],但是arr[j]与mx-i的大小关系未知,并且mx是我们已知的最右回文半径,mx左侧的情况未知,所以当arr[j]的值超过mx-i时,我们只能取到mx-i,以i为中心且mx右侧的情况只能一点一点向外扩。

class Solution {
public:
    string longestPalindrome(string s) {
        if(s.size()<0)
            return "";
        
        //解决奇偶回文
        string str("#");
        for(auto it=s.begin();it!=s.end();++it)
        {
            str+=(*it);
            str+="#";
        }
        
        //以i为中心的最右回文半径
        vector<int> arr(str.length(),0);
        int maxR=0,id=0;//最右回文半径(不包括此值)和回文中心
        int resId=0,resLen=0;//存储结果回文中心和回文半径
        for(int i=0;i<str.length();++i)
        {
            //在maxR内,i与id对应的j,对应的回文半径相等
            //i与maxR的关系:
            //  1>i在maxR内,直接根据j求得
            //  2>j>=maxR,要依次判断尝试 
            arr[i]=maxR>i?min(arr[2*id-i],maxR-i):1;//i在回文半径内,直接可根据回文特性计算得出
            while(i+arr[i]<str.length()&&i-arr[i]>=0)//i不在回文半径内需要依次向两边扩&&在回文半径内也需要判断回文半径外是否存在回文
                if(str[i+arr[i]]==str[i-arr[i]])
                    ++arr[i];
                else
                    break;
            
            if(maxR<i+arr[i])//更新回文半径和回文中心
            {
                id=i;
                maxR=i+arr[i];    
            }
            
            if(resLen<arr[i])
            {
                resId=i;
                resLen=arr[i];
            }
        }
        return s.substr((resId-resLen+1)/2,resLen-1);
    }
};

 

posted on 2019-03-16 22:49  tianzeng  阅读(148)  评论(0编辑  收藏  举报

导航