Loading

【学习笔记】字符串回文算法

Page Views Count

Manacher

非线性的求回文算法

  • \(O(n^2)\):枚举每个位置作为中心,不断向两侧扩展。

  • \(O(n\log n)\):二分+哈希。

线性的求回文算法

维护一个回文串 \([l,r]\) 为当前右端点最靠右的回文串,设当前枚举位置 \(i\)\(i\)\([l,r]\) 回文中心对称的位置 \(j=l+r-i\)

由于 \(j\) 的最长回文半径已经处理过,因此当 \(i\le r\) 时,分别以 \(i\)\(j\) 为中心的回文串中的部分(在 \([l,r]\) 中的部分)同样对称;剩余情况则从 \(1\) 开始。

按照暴力的方法扩展,更新 \([l,r]\),这里由于 \(r\) 只增不减,所以总扩展次数是 \(O(n)\) 的。

回文分奇数偶数两种,统一处理一般插入分隔符。

然而事实上求回文串的的线性算法不会优化算法瓶颈。(对数复杂度中二分与数据结构中的修改是并列的)

点击查看代码
int n;
char s[maxn<<1];
int d[maxn<<1];
int ans;
inline void Manacher(){
    for(int i=1,l=0,r=-1;i<=2*n+1;++i){
        int j=l+r-i,k;
        if(i>r) k=1;
        else k=min(d[j],r-i+1);
        while(i-k>=1&&i+k<=2*n+1&&s[i-k]==s[i+k]) ++k;
        d[i]=k;
        ans=max(ans,(d[i]*2-1)/2);
        if(i+k-1>r) l=i-k+1,r=i+k-1;
    }
}
int main(){
    scanf("%s",s+1);
    n=strlen(s+1);
    for(int i=n;i>=1;--i) s[i*2]=s[i];
    for(int i=0;i<=n;++i) s[i*2+1]='#';
    Manacher();
    printf("%d\n",ans);
    return 0;
}

回文自动机 Palindrome Automaton

构建

与回文有关且同样存在后缀指针的一种自动机。

由于回文串分奇数偶数,自动机存在两个根:奇根 \(1\) 和偶跟 \(0\),需要维护回文串长 \(\mathrm{len}(u)\) 和最长回文真后缀指针 \(\mathrm{fail}(u)\)

构建的实际过程比较好理解,在上一个节点的基础上增量,一直跳 \(\mathrm{fail}\) 指针直到可以前后各扩展一个位置(为了方便计算奇根的长度设为 \(-1\)),如果已经有对应的转移,无需再修改;如果需要新建节点,就要再处理一下两个指针,按照同样方法就可以。设刚刚找到可以扩展的位置 \(u\),那么再寻找到的 \(\mathrm{fail}\) 指针位置关于 \(u\) 的最长回文串回文中心对称之后,显然是已经出现过的,也就是不需要再新建节点。

将上述过程扩展,也就是在一个字符串结尾增加一个字符,之后最长的回文后缀可能是新增加的,换言之,一个字符串的本质不同回文子串只有不超过 \(|s|\) 个。

点击查看代码
char s[maxn];
struct PalindromeAutomaton{
    int tot,last;
    int ch[maxn][26];
    int len[maxn],fail[maxn];
    PalindromeAutomaton(){
        tot=1,last=1;
        len[0]=0,fail[0]=1;
        len[1]=-1,fail[1]=1;
    }
    int get_fail(int u,int pos){
        while(s[pos-len[u]-1]!=s[pos]) u=fail[u];
        return u;
    }
    void extend(int pos){
        int c=s[pos]-'a';
        int u=get_fail(last,pos);
        if(!ch[u][c]){
            int f=get_fail(fail[u],pos);
            ++tot;
            len[tot]=len[u]+2,fail[tot]=ch[f][c];
            ch[u][c]=tot;
        }
        last=ch[u][c];
    }
}PAM;

参考资料

Manacher

回文自动机 Palindrome Automaton

  • OI Wiki
posted @ 2023-01-12 09:20  SoyTony  阅读(82)  评论(1编辑  收藏  举报