最長迴文子串 manacher

求最長迴文子串。
字面意思
這麼求??

暴力:

枚舉某個點爲迴文中心,向兩邊擴展。(在每個字符中間再插一個沒出現過的字符以保證迴文子串長度爲偶數的情況)
時間複雜度:O(N2)

然而可以線性時間:

Fi 表示以i 點爲中心時的迴文子串半徑最大:cabac以b爲中心的迴文串的半徑r 爲2
根據迴文串的性質:左右對稱
我們可以得出在某一個迴文串中,以它迴文中心右邊的某個點爲迴文中心的最長迴文子串長度不小於以它左邊對稱點爲中心的最長迴文子串的長度

於是:

i>PiP+r 時(P 爲當前的中心)
FiFPr
在這基礎上再向左右擴展

當然,還有一些特殊情況:出界,右邊的迴文串長一些(cccbcc中b爲中心,最右邊)等。。。

F[i]=max( 0,min( F[2*p-i],p+F[p]-i ) );

理解一下這條語句2pi 原型是p(ip)

在此基礎上再向左右擴展下去

while(s[i-F[i]]==s[i+F[i]]) F[i]++;

當以新的i 點爲中心的最長迴文子串的邊界超過原中心的邊界時,這個i 就升級爲新的中心。

裸題:HDU3068

貼代碼:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<math.h>
#include<string.h>
//#include<>
using namespace std;

char str[120000],s[240000];
int ans,F[240000];

void pre()
{
    s[0]='@';
    int l=strlen(str);
    for(int i=0;i<l;i++)
    {
        s[i*2+1]='#';
        s[i*2+2]=str[i];
    }
    s[(l-1)*2+3]='#';
    s[(l-1)*2+4]='%';
}
void manacher()
{
    int n=(strlen(str)-1)*2+4;
    F[0]=F[1]=ans=0;
    int p=1;
    for(int i=2;i<=n;i++)
    {
        F[i]=max( 0,min( F[2*p-i],p+F[p]-i ) );
        while(s[i-F[i]]==s[i+F[i]]) F[i]++;
        if(i+F[i]>p+F[p]) p=i;
        ans=max(ans,F[i]);
    }
}
int main()
{
    while(scanf("%s",&str)!=EOF)
    {
        pre();
        manacher();
        printf("%d\n",ans-1);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章