最大回文子串
题目:输入一个字符串,输出该字符串中对称的子字符串的最大长度。
比如输入字符串“google”,由于该字符串里最长的对称子字符串是“goog”,因此输出4。
主要是参考了一下两篇文章:
http://blog.csdn.net/qitian0008/article/details/8042558
http://www.cnblogs.com/eric-blog/archive/2012/05/03/2481510.html
其中常规的方法,就是用一个i从左到右进行遍历,当i指向某个值的时候,以i为中心,逐个比较左右两个的字符是否相等。
这样就可以找到一个回文,以及他的长度。
但是,这样做的时候,是有重复计算的过程的。比如你找到一个回文,这个回文是左右对称的,那么你在计算右边范围内的某个字符,计算这个字符为中心的回文长度的时候,就可以利用他对称的左边的字符的回文长度,这样就可以实现简化,也就那个O(n)算法的思想。
但是计算回文的时候,有一个小问题,就是回文是奇数还是偶数,有个避免这种判断的方法就是在每个字幕中间插入#号,这样所有的都是奇数了。
好了,所有的问题都解决了,看代码吧。
#include <iostream> using namespace std; int getMaxHuiWenChar1(char *p,int len) { int nLen=2*len+3; char *str =new char[nLen]; int i=0; int max=0; int j=0,x,y; str[0]='$'; str[1]='#'; for(;i<len;i++) { str[i*2+2]=p[i]; str[i*2+3]='#'; } str[nLen-1]=0; for(i=0;i<nLen;i++) { cout<<str[i]; } cout<<endl; for(i=1;i<nLen;i++) { for(int j=0; i-j>0&&i+j<nLen; j++) { if(str[i-j]!=str[i+j]) break; else { if(max<j) { max=j; x=i-j; y=i+j; } } } } for(int k=x+1;k<=y-1;k+=2)//打印出回文 { cout<<str[k]; } return max; } int min(int a, int b) { return a<b?a:b; } int getMaxHuiWenChar2(char *s,int len) { int nLen=2*len+3; char *str =new char[nLen]; int i=0; int max=0; str[0]='$'; str[1]='#'; for(;i<len;i++) { str[i*2+2]=s[i]; str[i*2+3]='#'; } str[nLen-1]=0; int *p=new int[nLen];//定义一个用于标记的int数组 for(i=1;i<nLen;i++) { cout<<str[i]; p[i]=0; } cout<<endl; int id=0; for(i=1; i<nLen; i++) { if( max > i ) p[i] = min( p[2*id-i], p[id]+id-i ); else p[i] = 1; for(; str[i+p[i]] == str[i-p[i]]; p[i]++) NULL; if( p[i] + i > max ) { max = p[i] + i; id = i; } } int mx=0; for(i=1;i<nLen;i++) { if(mx<p[i]-1) mx=p[i]-1; } return mx; } int main(int argc, char* argv[]) { char *p="abcgooglrcabac"; int len=strlen(p); int max=getMaxHuiWenChar2(p,len); cout<<endl; cout<<max<<endl; return 0; }