• MANACHER---求最长回文串


    求最长回文串,如果是暴力的方法的话,会枚举每个字符为中心,然后向两边检测求出最长的回文串,时间复杂度在最坏的情况下就是0(n^2),为什么时间复杂度会这么高,因为对于每一个作为中心的字符的检测是独立的,没有充分利用前面比较过信息,这就类似暴力求字符串的匹配最糟糕的情况下是0(n*m),然后通过预处理的信息把时间复杂度降低也就是kmp算法;

    MANACHER算法:

    先假设所有回文串都是以某个字符为中心的,即回文串的长度都是奇数;

    lc[ i ]保存的是以位置i的字符为中心的最长回文串到最右边的距离

    先假设以知lc[i],(0<=i<x)求lc[x]

    设p=k+lc[k]-1,k是使p最大的i的取值,如下图

     

    如果x>p那么直接以x为中心进行检测,并更新k;

    如果x<=p那么对于以k为中心x的对称点就是j,并且lc[j]的值已经知道了,

    If (lc[j]<p-x+1) lc[x]=lc[j]

    因为s[j-1]!=s[j+1], s[j-1]=s[x-1],s[j+1]=s[x+1],所以s[x-1]!=s[x+1]如图:

     

    If (lc[j]>=p-x+1) 那么lc[x]至少是lc[j] 如图:

     

    但对于蓝色位置是不是还需要检测

    时间复杂度分析:因为对于每一位s[i]都只被检测了一次,所以是o(n);

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 

    现在回到最原先的问题,因为回文串有可能是“1221”这种长度是偶数的,MANACHER算法提供了一个构造的方法可以统一这两种情况:在两个字符之间插入一个没有出现过的字符,如‘#’,那么”1221”->”#1#2#2#1#”这样所有的回文串长度都是奇数的了,为了处理方便再在该字符串前面加一个‘$’字符,这样字符串就是$#1#2#2#1#

    求出lc[i]后,对于以s[i]为中心的字符串,如果s[i]==’#’,那么len=(lc[i]-1)/2*2,因为lc[i]-1肯定是偶数(因为该回文串的最左和最右肯定是’#’)所以len=lc[i]-1;

    如果s[i]!=’#’,那么len=(lc[i] - 1)/2*2+1;因为lc[i]-1肯定是奇数,所以len=lc[i]-2+1=lc[i]-1;

    所以最后的解就是最大lc[i]-1;

     1 void Manacher(char *s){
     2     s1[0]='$';
     3     int nn=strlen(s),c=1;
     4     for (int i=0;i<nn;i++){
     5         s1[c++]='#';
     6         s1[c++]=s[i];
     7     }s1[c++]='#';s1[c++]='';
     8   //  cout<<s<<endl<<s1<<endl;
     9   
    10     lc[0]=1;lc[1]=1;
    11     int k=1, p, j;
    12     for (int i=2;i<c;i++){
    13         p=k+lc[k]-1;
    14         if (p<i){
    15             int t=1;
    16             while (i-t>=0 && i+t<c && s1[i-t]==s1[i+t]) t++;
    17             lc[i]=t; k=i;
    18         }else {
    19             j=2*k-i;
    20             if (lc[j]<p-i+1) lc[i]=lc[j];
    21             else {
    22                 int t=p-i+1;
    23                 while (i-t>=0 && i+t<c && s1[i-t]==s1[i+t]) t++;
    24                 lc[i]=t; k=i;
    25             }
    26         }
    27     }
    28     int ret=0;
    29     for (int i=0;i<c;i++){
    30         //cout<<lc[i]<<" ";
    31         if (lc[i]-1>ret) ret=lc[i]-1;
    32     }//cout<<endl;
    33     printf("%d
    ",ret);
    34 
    35 }
  • 相关阅读:
    Beta冲刺(4/4)
    2019 SDN上机第7次作业
    Beta冲刺(3/4)
    Beta冲刺(2/4)
    机器学习第二次作业
    机器学习第一次作业
    软工实践个人总结
    第04组 Beta版本演示
    第04组 Beta冲刺(5/5)
    第04组 Beta冲刺(4/5)
  • 原文地址:https://www.cnblogs.com/Rlemon/p/3159533.html
Copyright © 2020-2023  润新知