【LeetCode】Manacher算法+Longest Palindromic Substring(最长回文子串)

来源:互联网 发布:sam smith 知乎 编辑:程序博客网 时间:2024/06/07 20:43

【PS:结合上篇相关的转载文章。。。】

Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring.
【Manacher 算法】
分析:将传入的原始字符串s升级为S(开头加$、中间加#)
现在算长度为(2N+1)的String的LPS(下标:[0,2N])。
P[x]的下标的值 = 升级后的S[x]下标处从左/右起的最长回文串的长度。(由于加了#,故P[x] 等于 以原始s[x]为中心,当前下标x处的最长子串长度。)
假设当前从[0,i-1]的P[]已经算完,正在计算的是P[i] ,后面的P[i+1]~P[2N]暂不管。

设k:P[k]为从左or右起, 最远可到达的回文子串的长度
求出以下标k为起点,最远的回文子串能控制到下标为k+P[k]处,计为mx点
将k从0~i-1遍历,求k+P[k]的最大值(即距离k下标最远的位置,计作mx)
设符合要求的下标为id,即id+k[id]最大。

若当前遍历的下标i落在了当前势力范围(0~mx)内【即mx下标>当前的i下标】,则P[i]可以参照前面的值做计算(无需再遍历一遍,增加时间复杂度):
以id为中心,i的对称点计作j,又易知(i+j)/2 = id, 故下标j = 2*id - i。
①若my(以id为中心,mx的对称点)下标在j的左侧,即j在[my,mx]以内,则P[i]无需计算,P[i] == P[j]一定成立。(原因再分析——因为以id为中心,最远的回文子串下标为[my,mx],在此范围之内&&以id为中心的P[i]、P[j]的值一定是对称相等的)②若j在my左侧,即下标j超过了当前以id为中心的最长子串长度,P[j]的值无法起到帮助作用,故P[i] = mx - i ;

对应代码段:
if(mx > i) P[i] = min(P[mx],P[j]);【其中,j 以 ( 2*id - i ) 替换】

void Manacher1(char* s, int* P){    int size = strlen(s);    P[0] = 1;    int ans = 0;    int id = 0;    int mx = 0;//mx即为当前计算回文串最右边字符的最大值    for(int i = 1; i <size; i++)    {        if(mx > i){            P[i] = min(P[2*id - i],mx);        }else{//如果i>=mx,要从头开始匹配            P[i] = 1;        }        for(;s[i+P[i]] == s[i-P[i]];P[i]++);        if(mx < i+P[i]){//若新计算的回文串右端点位置(i+P[i])大于mx,要更新id和mx的值            mx = i+P[i];            id = i;        }        ans=max(ans,P[i]);    }}②void Manacher2(char* s, int* P){    int size = strlen(s);    P[0] = 1;    int ans = 0;    int id = 0;    int mx = 0;//mx即为当前计算回文串最右边字符的最大值    for(int i = 1; i <size; i++)    {        if(mx > i){            if(P[2*id-i] != mx - i){                P[i] = min(P[2*id - i],mx);            }else{//如果i>=mx,要从头开始匹配                P[i] = P[2*id-i];//将P[j]赋给P[i]                for(;s[i+P[i]] == s[i-P[i]];P[i]++);            }        } else{            P[i] = 1;            for(;s[i+P[i]] == s[i-P[i]];P[i]++);        }        if(mx < i+P[i]){//若新计算的回文串右端点位置(i+P[i])大于mx,要更新id和mx的值            mx = i+P[i];            id = i;        }        ans=max(ans,P[i]);    }}
阅读全文
2 0