《算法竞赛入门经典》3.3最长回文子串

Posted 你有多努力,就有多幸运!

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《算法竞赛入门经典》3.3最长回文子串相关的知识,希望对你有一定的参考价值。

  1     //例题3-4  
  2     /*  
  3     * 输入一个字符串,求出其中最长的回文子串。子串的含义是:在原串中连续出现的字符串片段。 
  4     *回文的含义是:正看着和倒看着相同,如abba和yyxyy。在判断时,应该忽略所有标点符号和空格 
  5     *且忽略大小写,但输出应保持原样(在回文串的首部和尾部不要输出多余字符)。输入字符长度不超过5000 
  6     *且占据单独的一行。应该输出最长回文串,如果有多个,输出起始位置最靠左的。 
  7     *样例输入:Confuciuss say:Madam,I‘m Adam. 
  8     *样例输出:Madam,I‘m Adam 
  9     */  
 10       
 11     //程序3-5 最长回文子串(1)  
 12     #include<stdio.h>  
 13     #include<string.h>  
 14     #include<ctype.h>     //用到isalpha、touuper等工具  
 15     #define MAXN 5000+10  
 16     char buf[MAXN],s[MAXN];  
 17     int main()  
 18     {  
 19         int n,m=0,max=0;  
 20         int i,j,k;  
 21         fgets(buf,sizeof(s),stdin);     //从标准输入流中读取sizeof(s)-1个字符并且把他们转储到buf中  
 22         n=strlen(buf);                  //获取buf的长度,包含文件结束符‘\0‘  
 23         for(i=0;i<n;i++)    
 24                                 //构造一个新的字符串,把标点符号过滤掉,随便把小写字母变为大写  
 25             if(isalpha(buf[i])) s[m++]=toupper(buf[i]);  
 26         for(i=0;i<m;i++)     //其中m是新字符串s的长度  
 27             for(j=i;j<m;j++)  
 28             {  
 29                 int ok=1;  
 30                 for(k=i;k<=j;k++)    //判断s[i..j]是否为回文串  
 31                     if(s[k]!=s[i+j-k]) ok=0;      
 32                 if(ok && j-i+1>max) max=j-i+1;   //保存当前发现的最长回文串  
 33             }  
 34             printf("max=%d\n",max);  
 35             return 0;  
 36     }  
 37       
 38       
 39     //程序3-5 最长回文子串(2)  
 40     #include<stdio.h>  
 41     #include<string.h>  
 42     #include<ctype.h>     //用到isalpha、touuper等工具  
 43     #define MAXN 5000+10  
 44     char buf[MAXN],s[MAXN];  
 45     int p[MAXN];            //增设数组p,用于保存s[i]在buf中的位置  
 46     int main()  
 47     {  
 48         int n,m=0,max=0,x,y;  
 49         int i,j,k;  
 50         fgets(buf,sizeof(s),stdin); //从标准输入流中读取sizeof(s)-1个字符并且把他们转储到buf中  
 51         n=strlen(buf);              //获取buf的长度,包含文件结束符‘\0‘  
 52         for(i=0;i<n;i++)  
 53             if(isalpha(buf[i]))     //构造一个新的字符串,把标点符号过滤掉,随便把小写字母变为大写  
 54                 {  
 55                     p[m]=i;         //保存s[m]在buf的位置  
 56                     s[m++]=toupper(buf[i]);   
 57             }  
 58             for(i=0;i<m;i++)     //遍历字符串s,以i为"中间"位置,然后根据j的值不断向两边扩展  
 59             {                       //这个for循环遍历的子串长度为奇数  
 60                 for(j=0;i-j>=0 && i+j<m; j++) //注意i和j的关系:i-j>=0表示i到j的距离不能上溢  
 61                                                 //i+j<m表示i再加j个位置没有超过字符串s的总长  
 62                 {  
 63                     if(s[i-j]!=s[i+j]) break;   //如果以i为中间点,左边i-j个点字符跟右边i+j个点不同,跳出循环  
 64                     if(j*2+1>max)                //因为子串的长度为奇数,所以子串的长度应该等于j*2+1(j为以i为中心,往两边的距离)  
 65                     { max=j*2+1; x=p[i-j];y=p[i+j]; } //保存当前最长回文子串长度,记录子串范围  
 66                 }  
 67                 for(j=0;i-j>=0 && i+j+1<m; j++)//这个for循环遍历的子串长度为偶数,  
 68                     //中间点i取子串长度的中点,导致两边长度不均,右边的距离应该再加1  
 69                 {  
 70                     if(s[i-j]!=s[i+j+1]) break;  
 71                     if(j*2+2>max)            
 72                     { max=j*2+2; x=p[i-j]; y=p[i+j+1]; }  
 73                 }  
 74             }  
 75             for(i=x;i<=y;i++)    //把最长回文子串输出  
 76                 printf("%c",buf[i]);  
 77             printf("\n");  
 78             return 0;  
 79     }  
 80       
 81       
 82     /*样例输入:Confuciuss say:Madam,I‘m Adam. 
 83     *样例输出:Madam,I‘m Adam 
 84     * 
 85     //分析得出最长回文子串的过程 
 86     *(1)    for(i=0;i<m;i++)     //遍历字符串s,以i为"中间"位置,然后根据j的值不断向两边扩展 
 87             {                       //这个for循环遍历的子串长度为奇数 
 88     *(2)        for(j=0;i-j>=0 && i+j<m; j++) //注意i和j的关系:i-j>=0表示i到j的距离不能上溢 
 89                                                 //i+j<m表示i再加j个位置没有超过字符串s的总长 
 90                 { 
 91                     if(s[i-j]!=s[i+j]) break;   //如果以i为中间点,左边i-j个点字符跟右边i+j个点不同,跳出循环 
 92                     if(j*2+1>max)                //因为子串的长度为奇数,所以子串的长度应该等于j*2+1(j为以i为中心,往两边的距离) 
 93                     { max=j*2+1; x=p[i-j];y=p[i+j]; } //保存当前最长回文子串长度,记录子串范围 
 94                 } 
 95     *(3)        for(j=0;i-j>=0 && i+j+1<m; j++)//这个for循环遍历的子串长度为偶数, 
 96                     //中间点i取子串长度的中点,导致两边长度不均,右边的距离应该再加1 
 97                 { 
 98                     if(s[i-j]!=s[i+j+1]) break; 
 99                     if(j*2+2>max)           
100                     { max=j*2+2; x=p[i-j]; y=p[i+j+1]; } 
101                 } 
102             } 
103     *字符串s="CONFUCIUSSSAYMADAMIMADAM" 
104     *字符串长度m=24 
105     *第一个for循环循环到i=18的时候 
106     *也就是遍历到s[18]位置上,这时s[18]=‘I‘ 
107     *接着进行内部循环,执行第二个循环体,开始以I为中心点,向两边扩展 
108     *i=18,j=0,满足条件,执行if语句,s[i-j]=I,s[i+j]=I,s[i-j]=s[i+j]不满足条件 
109     *执行下一条if语句,判断j*2+1是否大于max,0*2+1<max=5,不满足条件,因为之前第一个回文子串是MADAM,长度为5 
110     *j=1;s[i-j]=M,s[i+j]=M;不满足条件 
111     *j*2+1<max,max=5,p[i-j]=17,p[i+j]=19 
112     *j=2;s[i-j]=A;s[i+j]=A; 
113     *j*2+1=max,max=5,p[i-j]=16,p[i+j]=20 
114     *j=3;s[i-j]=D;s[i+j]=D; 
115     *j*2+1>max,max=7,p[i-j]=15,p[i+j]=21 
116     *j=4;s[i-j]=A;s[i+j]=A; 
117     *j*2+1>max,max=9,p[i-j]=14,p[i+j]=22 
118     *j=5;s[i-j]=M;s[i+j]=M; 
119     *j*2+1>max,max=11,p[i-j]=13,p[i+j]=23,x=13,y=23 
120     *j=6;i+j>m,结束本次循环 
121     *继续执行下一个for语句 
122     *i=18,j=0,满足循环条件,执行循环体 
123     *s[i-j]!=s[i+j+1];满足条件,break跳出循环 
124     *到此最长的回文子串已经得出来了,不过还要继续遍历字符串,直到结束为止 
125     *最后结果:Madam,I‘m Adam 
126     */  

 

以上是关于《算法竞赛入门经典》3.3最长回文子串的主要内容,如果未能解决你的问题,请参考以下文章

求最长回文子串,O(n)复杂度

求最长回文子串,O(n)复杂度

LeetCode-面试算法经典-Java实现05-Longest Palindromic Substring(最大回文字符串)

多思路深度剖析经典面试题最长回文子串

字符串最长回文子串 ( 动态规划算法 ) ★

字符串最长回文子串 ( 中心线枚举算法 )