1 class Solution 2 { 3 public: 4 string longestPalindrome(string s) 5 { 6 int len=s.length(); 7 if(len<2) 8 return s; 9 int min_start=0,max_len=1; 10 for(int i=0;i<len;) 11 { 12 if(len-i<=max_len/2) 13 break; 14 int j=i,k=i; 15 while(k<len-1&&s[k]==s[k+1]) 16 k++; 17 i=k+1; 18 while(k<len-1&&j>0&&s[k+1]==s[j-1]) 19 { 20 ++k; 21 --j; 22 } 23 int newlen=k-j+1; 24 if(newlen>max_len) 25 { 26 min_start=j; 27 max_len=newlen; 28 } 29 } 30 return s.substr(min_start,max_len); 31 } 32 };
中心扩散法,以回文中间元素为扫描基准,扫描的时候判定回文并更新最大长度和开始值,值得注意的是一定要跳过中间相等的元素,从相等那一段的两端往两边走。
1 class Solution { 2 public: 3 string longestPalindrome(string s){ 4 // 进行填充,首末均有特殊字符,就不需要越界判定了 5 string ss="$#"; 6 for(char& c:s) 7 ss = ss + c + "#"; 8 int sz_ss=ss.size(); 9 vector<int> p(sz_ss, 0); 10 // center是当前最远回文串中心,right是当前最远距离 11 int center=0,right=0; 12 // 用来存放最大回文子串的位置和长度 13 int maxLen=0,maxPos=0; 14 15 for(int i=1;i<sz_ss;i++){ 16 // 如果当前扫描元素在最远回文距离以内,尝试使用历史信息初步判定回文长度 17 if(right>i) 18 p[i]=min(right-i, p[2*center-i]); 19 20 // 尝试继续向两边扩展 21 while(ss[i+p[i]+1]==ss[i-p[i]-1]) 22 ++p[i]; 23 24 // 更新最远距离和中心 25 if(right<i+p[i]){ 26 right=i+p[i]; 27 center=i; 28 } 29 30 // 更新最大长度和对应子串中心位置 31 if(p[i]>maxLen){ 32 maxLen=p[i]; 33 maxPos=i; 34 } 35 } 36 // 这个计算很巧妙,填充序列里,每个回文串必以填充字符开始和结束 37 // 所以真正回文开始位置就是最前方填充字符的下一个字符 38 // 下一个字符在原字符串中的下标,正好就是前面填充字符下标除以2 39 // 填充字符的下标是maxPos-maxLen 40 return s.substr((maxPos-maxLen)/2,maxLen); 41 } 42 };
马拉车算法,把回文串的特性利用了起来,减少了很多不必要的判定,O(n)复杂度,很强势。
浙公网安备 33010602011771号