题意:给一个字符串,求最长回文子串的长度。
思路:
(1)暴力穷举。O(n^3) -----绝对不行。
穷举所有可能的出现子串O(n^2),再判断是否回文O(n)。就是O(n*n*n)了。
(2)记录位置。O(n^3) -----绝对不行。
先扫一遍,记录每个字符在上一次出现的位置pos。每次考虑第i个字符,如果回文子串包括 i 的话,那么肯定在i的前面有一个跟第i个字符是一样的,利用之前记录的位置pos[i]可以找到与第i个相同的字符,如果i-pos[i]比之前发现的最长的子串max还短,那么不用比较了。如果更前面还有和第i个字符一样的,那么可以找到第pos[pos[i]]个,一定要找到区间比max还大的,才有比较的意义,除非前面已经没有相同字符的了。那么略过第i个,直奔下一个。记录位置需要O(n),考虑每个字符需要O(n),对其前面出现过的每个字符考虑O(n),一旦考虑就需要比较是否回文O(n),总的来说,后面3个是乘的关系O(n^3)。
1 #include <iostream> 2 #include <cstring> 3 #include <vector> 4 #include <stdio.h> 5 6 using namespace std; 7 const int N=1000010; 8 9 char str[N]; 10 char has[256]; 11 char pos[N]; 12 13 14 bool isP(int j,int i) 15 { 16 while( j!=i && j!=--i) 17 { 18 if( str[j]!=str[i] ) 19 return false; 20 j++; 21 } 22 return true; 23 } 24 25 int fin_ex(int max, int i) 26 { 27 int j=pos[i]; 28 while( i-j<=max && j>-1 ) //找到一个区间范围大于max的,开始算 29 j=pos[j]; 30 return j; 31 } 32 33 int cal(int len) 34 { 35 int max=1, j; 36 for(int i=0; i<len; i++) 37 { 38 j=fin_ex(max, i); //找相同的,且大于max的 39 while( j!=-1 && i-j>max ) //有相同 40 { 41 if(isP(j,i+1)==true) 42 max=i-j+1; 43 else 44 j=fin_ex(max, j); //不是回文,继续找 45 } 46 } 47 return max; 48 } 49 50 51 int main() 52 { 53 //freopen("input.txt", "r", stdin); 54 int t; 55 cin>>t; 56 getchar(); 57 while(t--) 58 { 59 gets(str); 60 int len=strlen(str); 61 for(int i=0; i<256; i++) has[i]=-1; //初始化 62 for(int i=0; i<len; i++) //记录上一次出现的位置 63 { 64 pos[i]=has[str[i]]; 65 has[str[i]]=i; 66 } 67 68 cout<<cal(len)<<endl; 69 } 70 return 0; 71 }