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)复杂度,很强势。

posted on 2018-07-03 14:26  高数考了59  阅读(137)  评论(0)    收藏  举报