zoukankan      html  css  js  c++  java
  • 【2018.07.28】(字符串/回文串)学习Manacher算法小记

    主要是应用在回文串啦,原理也理解了老半天,如果没有图片的话,我也看不太懂它的原理

    学习的灵感来源来自于:https://segmentfault.com/a/1190000008484167

    /*     最长回文     */
    /*给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度. 
    回文就是正反读都是一样的字符串,如aba, abba等
    
    Input
    输入有多组case,不超过120组,每组输入为一行小写英文字符a,b,c...y,z组成的字符串S 
    两组case之间由空行隔开(该空行不用处理) 
    字符串长度len <= 110000
    
    Output
    每一行一个整数x,对应一组case,表示该组case的字符串中所包含的最长回文长度. 
    
    Sample Input
    aaaa
    abab
    
    Sample Output
    4
    3*/
    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cmath> 
    using namespace std;
    /*说实话我非常讨厌字符串的题目,对于我来说可能是会在输入出现问题,所以我一直都不
    太喜欢字符串,拿到这道题是没有什么思路的。但是简单看了解析就不得不佩服他们的想法
    他的想法是,在每个字符串之间加入特殊符号,他用的是#,这样子就可以算出奇数个的回
    文串了,这样奇数字符串就仍然以字母为中心,偶数字符串就会以#为中心展开,接下来的
    方法我还没看,但我可以猜测如果是检索到#的话就隔项去检索字母,如果是检索到字母就
    隔项去检索字母,试着去完成一下吧*/
    //果然还是以失败告终,我去看看网上的思路吧 
    
    char s[110050], ss[220100]; 
    int Count[220100];
    
    int judge( int len )
    {
        Count[0]=1;//最低限度是1,但这个点应该用不到的说= =,这句话应该可以删掉 
        int mx=0,id=0;
        //mx 代表以 id 为中心的最长回文的右边界
        for(int i=1 ; i<=len ; i++ ) //从第一个#开始 
        {
            if( mx>i )//如果这个点包含在右边界之中 
            {
                Count[i] = min( Count[2*id-i] , mx-i );
                /*这句话简直太精辟了,在id的右边的点i,会等于id左边点的对称点,如果
                这个i点到id的点的距离(左段)和i点到mx点的距离(右段)相比,如果右边
                比较小,那么就会继续向mx外部检索,如果对称点的Count[2*id-i]还不及边
                界,那么就不必继续向外检索了,下面的循环第一步就会停止了*/ 
            }
            else
            {
                Count[i] = 1;//如果这个点超出了右边界,那么这个点开始重新计算 
            }
            while( i+Count[i]<=len && ss[i-Count[i]]==ss[ i+Count[i] ] ) 
                Count[i]++;//如果旁边只要有一次相等便会+1,直到不相等为止 
            if( Count[i]+i > mx )//如果新检索的位置超出了最大边界 
            {
                mx=Count[i]+i;//Count存储的是半径,i是当前位置,相加得新的右边界 
                id=i;//id记录的是对称点所在位置 
            }
        }
        //数据验证 
        /*for (int i=1 ; i<=len ; i++ )
        {
            cout<<Count[i]<<' '; 
        }
        cout<<endl;*/
        int max=0;
        for(int i=1;i<=len;i++)
        {
            if( Count[i] > max )    max=Count[i];
        }
        return max-1;
    }
    
    
    int main(void)
    {
        int result;
        int j, len, i;
        ss[0]='$';
        ss[1]='#';
        while ( scanf("%s",s)!=EOF )
        {
            j=2;
            len=strlen(s);
            for ( i=0 ; i<len ; i++ )
            {
                ss[j++]=s[i];
                ss[j++]='#';//执行完语句j才会自增1 
            }
            //ss[j]='^';
            //printf("%s\n",ss);
            result = judge(j);
            printf("%d\n",result);
        }
        return 0;
    }
    //下面这里是自己实现的代码,貌似不太行23333 
    /*int judge( int len )
    {
        len=(len+1)*2+1;//比ss多一个数字,是小于
        int max=0, i=3 , count=1;
        while ( i<len )
        {
            if ( ss[i]=='#' )
            {
                while ( 1 )
                {
                    if ( (i-count*2+1)>=0 || (i+count*2-1)>=len ) break;
                    if ( ss[i-count*2+1] == ss[i+count*2-1] )
                    {
                        if ( count > max ) max=count; 
                        count++;
                    }
                    else
                    {
                        count=1;
                        break;
                    }
                }
            }
            else
            {
                while ( 1 )
                {
                    if ( ss[i+count*2] == ss[i-count*2])
                    {
                        if ( count > max ) max=count;
                        count++;
                    }
                    else
                    {
                        count=1;
                        break;
                    }
                    if ( (i-count*2)>=0 || (i+count*2)>=len ) break;
                }
            }
            i++;
        }
        return max;
    }*/

    吉哥系列故事——完美队形II

    吉哥又想出了一个新的完美队形游戏! 
      假设有n个人按顺序站在他的面前,他们的身高分别是h[1], h[2] ... h[n],吉哥希望从中挑出一些人,让这些人形成一个新的队形,新的队形若满足以下三点要求,则就是新的完美队形: 

      1、挑出的人保持原队形的相对顺序不变,且必须都是在原队形中连续的;
      2、左右对称,假设有m个人形成新的队形,则第1个人和第m个人身高相同,第2个人和第m-1个人身高相同,依此类推,当然如果m是奇数,中间那个人可以任意; 
      3、从左到中间那个人,身高需保证不下降,如果用H表示新队形的高度,则H[1] <= H[2] <= H[3] .... <= H[mid]。 

      现在吉哥想知道:最多能选出多少人组成新的完美队形呢?

    Input  输入数据第一行包含一个整数T,表示总共有T组测试数据(T <= 20); 
      每组数据首先是一个整数n(1 <= n <= 100000),表示原先队形的人数,接下来一行输入n个整数,表示原队形从左到右站的人的身高(50 <= h <= 250,不排除特别矮小和高大的)。Output  请输出能组成完美队形的最多人数,每组输出占一行。Sample Input

    2
    3
    51 52 51
    4
    51 52 52 51

    Sample Output

    3
    4
     1 #include <algorithm>
     2 #include <iostream>
     3 #include <cstring>
     4 #include <cstdio>
     5 #include <vector>
     6 #include <cmath>
     7 #include <stack>
     8 #include <queue>
     9 using namespace std;
    10 #define MAXN 100010*2
    11 /*这题我知道是运用马拉车算法*/
    12 /*在manacher算法上要加上对身高的判断,中间的人身高会比较高*/
    13 /*检查BUG检查了好久好久= =,最后发现只要在那个地方加入一条判断就可以了= =*/
    14 int a[MAXN], b[MAXN], p[MAXN];
    15 
    16 int manacher(int len)
    17 {
    18     int mx=0, id=0, i, j;
    19     for ( i=1 ; i<=len ; i++ )
    20     {
    21         if ( mx > i )
    22         {
    23             p[i]=min( p[2*id-i] , mx-i );
    24         }
    25         else p[i]=1;
    26         while ( i+p[i] <= len && b[ i-p[i] ] == b[ i+p[i] ] && b[i-p[i]]<=b[i-p[i]+2] )
    27         {//加入的条件就是上面最后一个条件 
    28             /*if ( i%1 )
    29             {
    30                 if ( b[i+1] < b[ i+1+p[i]*2 ] ) break;
    31             }
    32             else
    33             {
    34                 if ( b[i] < b[ i+p[i]*2 ] ) break; 
    35             }*/
    36             p[i]++;
    37         }
    38         if ( p[i]+i > mx )
    39         {
    40             mx=p[i]+i;
    41             id=i;
    42         }
    43     }
    44     int Max=0;
    45     for ( j=0 ; j<=len+2 ; j++ )
    46     {
    47         if ( Max < p[j] ) Max=p[j];
    48     }
    49     return Max-1;
    50 }
    51 
    52 int main(void)
    53 {
    54     int repeat, i, n, temp, j;
    55     scanf("%d", &repeat);
    56     while ( repeat-- )
    57     {
    58         memset( b , 0 , sizeof(b) );
    59         scanf("%d" ,&n);
    60         b[1]=-1;
    61         for ( i=0, j=2 ; i<n ; i++ )
    62         {
    63             scanf("%d", &a[i] );
    64             b[j++]=a[i];
    65             b[j++]=-1;
    66         }
    67         b[j]=-1;
    68         /*for ( i=0 ; i<=j ; i++ )
    69         {
    70             printf("%d ", b[i] );
    71         }*/
    72         cout<<manacher(j)<<endl;
    73     }
    74     return 0;
    75 }
  • 相关阅读:
    第 1 章 Java 设计模式介绍
    Java 随心笔记1
    在Editplus中配置java编译(javac)和运行(java)的方法
    RabbitMQ/JAVA 客户端连接测试
    CentOS上的RabbitMQ安装
    AMQP与RabbitMQ简介
    Mongodb学习教程汇总
    selenium+python之iframe学习笔记
    selenium 上传文件,非input标签,安装pyuserinput
    selenium+python之元素定位的八种方法
  • 原文地址:https://www.cnblogs.com/mokou/p/9381900.html
Copyright © 2011-2022 走看看