求一个字符串中的最长回文字符串
1. 参考文章http://www.leetcode.com/2011/11/longest-palindromic-substring-part-i.html
2. 文章中阐述了五种方法
(1)将str反转然后得到rstr,然后求str和rstr的最长公共子串。每次得到一个最长公共子串候选,还需要对子串下标和反转子串的原始下标进行判断,看是否相等:相等则得到的是合理的回文串;否则不合理。如果求最长公共子串使用DP算法,则时间复杂度为O(N2),空间复杂度为O(N2);如果采用广义后缀树(GST),则时间复杂度为O(2N)(具体算法还没细看)。
(2)暴力搜索,时间复杂度为O(N3)(代码中的方法1)
(3)动态规划时间复杂度为O(N2),空间复杂度为O(N2)(代码中的方法2)
(4)从中间到两边扩展判断,时间复杂度为O(N2),空间复杂度为O(1)(代码中的方法3)
(5)线性算法,这个算法技巧性非常强,有些地方还不是很清楚。时间复杂度为O(N),空间复杂度为O(N)(代码中的方法5)
3. 重点掌握(2)(3)(4)
4. 感觉直接使用后缀树也可以得到线性时间的算法,具体算法有空实现。
5. 代码如下:
View Code
1 #include <iostream> 2 #include <cassert> 3 #include <string> 4 #include <algorithm> 5 using namespace std; 6 7 //方法一:暴力搜索 8 string IsPalindrome1(string str) 9 { 10 if (str=="") 11 { 12 return ""; 13 } 14 int n=str.length(); 15 int maxLength=-1; 16 int maxIndex; 17 for (int i=0;i<n;i++) 18 { 19 for (int j=i;j<n;j++) 20 { 21 int start=i; 22 int end=j; 23 bool flag=true; 24 while (start<=end) 25 { 26 if (str[start]!=str[end]) 27 { 28 flag=false; 29 break; 30 } 31 start++; 32 end--; 33 } 34 int tmpLength=j-i+1; 35 if (flag && tmpLength>maxLength) 36 { 37 maxLength=tmpLength; 38 maxIndex=i; 39 } 40 } 41 } 42 return str.substr(maxIndex,maxLength); 43 } 44 45 //方法2:动态规划 46 string IsPalindrome2(string str) 47 { 48 if (str=="") 49 { 50 return ""; 51 } 52 int n=str.length(); 53 int maxIndex=0; 54 int maxLength=1; 55 bool IsPal[1000][1000]={false}; 56 //bool **IsPal=new bool*[n]; 57 //for (int i=0;i<n;i++) 58 //{ 59 // IsPal[i]=new bool[n]; 60 //} 61 //for (int i=0;i<n;i++) 62 //{ 63 // for (int j=0;j<n;j++) 64 // { 65 // IsPal[i][j]=false; 66 // } 67 //} 68 for (int i=0;i<n;i++) 69 { 70 IsPal[i][i]=true; 71 } 72 for (int i=0;i<n-1;i++) 73 { 74 if (str[i]==str[i+1]) 75 { 76 IsPal[i][i+1]=true; 77 maxIndex=i; 78 maxLength=2; 79 } 80 } 81 for (int len=3;len<=n;len++) 82 { 83 for (int i=0;i<=n-len;i++) 84 { 85 int j=i+len-1; 86 if (IsPal[i+1][j-1] && str[i]==str[j]) 87 { 88 IsPal[i][j]=true; 89 maxIndex=i; 90 maxLength=len; 91 } 92 } 93 } 94 //for (int i=0;i<n;i++) 95 //{ 96 // delete[] IsPal[i]; 97 //} 98 //delete[] IsPal; 99 return str.substr(maxIndex,maxLength); 100 } 101 102 103 //从中心向两端扩展 104 string expandAroundCenter(string s,int c1,int c2) 105 { 106 int l=c1; 107 int r=c2; 108 int n=s.length(); 109 while (l>=0 && r<=n-1 && s[l]==s[r]) 110 { 111 l--; 112 r++; 113 } 114 return s.substr(l+1,r-l-1); 115 } 116 117 //方法3:从中心向两端扩展 118 string IsPalindrome3(string str) 119 { 120 int n=str.length(); 121 if (n==0) 122 { 123 return ""; 124 } 125 string longest=str.substr(0,1); 126 for (int i=0;i<n-1;i++) 127 { 128 string p1=expandAroundCenter(str,i,i); 129 if (p1.length()>longest.length()) 130 { 131 longest=p1; 132 } 133 string p2=expandAroundCenter(str,i,i+1); 134 if (p2.length()>longest.length()) 135 { 136 longest=p2; 137 } 138 } 139 return longest; 140 } 141 142 //方法5预处理 143 //若输入str="abba" 144 //则输出"^#a#b#b#a#$" 145 string preProcess(string str) 146 { 147 int n=str.length(); 148 if (n==0) 149 { 150 return "^$"; 151 } 152 string ret="^"; 153 for (int i=0;i<n;i++) 154 { 155 ret=ret+"#"+str.substr(i,1); 156 } 157 ret+="#$"; 158 return ret; 159 } 160 //方法5: 161 string IsPalindrome5(string str) 162 { 163 string T=preProcess(str); 164 int n=T.length(); 165 int *P=new int[n]; 166 int C=0; //对称中心 167 int R=0; //对此字符串的最右端边界 168 for (int i=1;i<n-1;i++) 169 { 170 int i_mirror=2*C-i; // 171 P[i]=(R>i)?min(R-i,P[i_mirror]):0; 172 //以i为中心向两端扩充 173 while (T[i+1+P[i]]==T[i-1-P[i]]) 174 { 175 P[i]++; 176 } 177 //如果以i为中心扩展的回文字符串右边界 178 //超过R则更新C和R 179 if (i+P[i]>R) 180 { 181 C=i; 182 R=i+P[i]; 183 } 184 } 185 int maxLen=0; 186 int currentIndex=0; 187 //搜索最大len和对应下标 188 for (int i=0;i<n-1;i++) 189 { 190 if (P[i]>maxLen) 191 { 192 maxLen=P[i]; 193 currentIndex=i; 194 } 195 } 196 delete[] P; 197 return str.substr((currentIndex-1-maxLen)/2,maxLen); 198 } 199 int main() 200 { 201 string str1="aaaaaaaa"; 202 string str2="abc"; 203 string str3="babcbabcbaccba"; 204 cout<<IsPalindrome1(str1)<<endl; 205 cout<<IsPalindrome1(str2)<<endl; 206 cout<<IsPalindrome1(str3)<<endl; 207 208 cout<<IsPalindrome2(str1)<<endl; 209 cout<<IsPalindrome2(str2)<<endl; 210 cout<<IsPalindrome2(str3)<<endl; 211 212 cout<<IsPalindrome3(str1)<<endl; 213 cout<<IsPalindrome3(str2)<<endl; 214 cout<<IsPalindrome3(str3)<<endl; 215 216 cout<<IsPalindrome5(str1)<<endl; 217 cout<<IsPalindrome5(str2)<<endl; 218 cout<<IsPalindrome5(str3)<<endl; 219 220 }