leetCode.005 Longest Palindromic Substring

(转载)LeetCode上一道求回文字符串的问题,通常容易想到的是暴力和动态规划的方法,时间复杂度为O(n^2),后来看到有一种更巧妙的算法,Manacher’s algorithm,时间复杂度为O(n)。参考大神的博客,记下来自己的理解,方便日后查阅。

1.预处理

首先,由于通常情况下,对于奇数长度和偶数长度的不同字符串,我们需要分别处理。这里,通过巧妙的预处理,在每一个字符两边增加一个特殊字符,例如:#a#b#a#a#b#a#a#b#,这样就可以枚举到每一个中心了,就是说把两种情况都统一起来。算法的思想是利用前面已经求得的回文子串的信息,来求以当前字符中心的回文子串。

2.空间换时间

然后,我们需要用一个数组 P[i] 来记录以字符S[i]为中心的最长回文子串向左/右扩张的长度(包括S[i]),比如S和P的对应关系:

[plain] view plaincopy
  1. S  #  1  #  2  #  2  #  1  #  2  #  3  #  2  #  1  #  
  2. P  1  2  1  2  5  2  1  4  1  2  1  6  1  2  1  2  1  
  3. (p.s. 可以看出,P[i]-1正好是原字符串中回文串的总长度)  

那么怎么计算P[i]呢?该算法增加两个辅助变量(其实一个就够了,两个更清晰)id和mx,
其中id表示最大回文子串中心的位置,mx则为id+P[id],也就是最大回文子串的边界。
注意:在算法中,id和mx是一直更新的,其表示,以id为起点,半径为mx势力范围内能够罩住的区间,即[id - mx,id + mx]。

 


3.算法逻辑分析

假设现在我们要求P[i],i关于id的对称点j是否有信息可以利用呢?主要看id为中心的回文串半径与P[j]的关系

总的来说,有三种情况

a.完全覆盖,不包括边界

此时可以完全利用i的对称点j的已有信息,即P[i]=P[j];此时,不会更新id和mx值,即可以直接处理下一个字符。

b.恰好覆盖,到达边界

此时,就需要就在边界的下一个开始继续比较下去

c.未能覆盖

此时,p[i] = mx - i 且 不会更新id和mx值,即可以直接处理下一个字符。

那么P[i]=j+P[j]-i ;因为如下图,1、13不在pj里面,就是说s[1]!=s[13],而在p4里面有s[1]=s[7],所以s[13]!=s[7],所以不能形成更长的回文串。

 1 char* s_Trans_t(char* s)
 2 {
 3     char* t;
 4     t=(char*)malloc(sizeof(char)*2500);
 5     t[0]='#';
 6     for(int i=0;s[i]!='\0';i++)
 7     {
 8         t[2*i+1]=s[i];
 9         t[2*i+2]='#';
10     }
11     return t;
12 }
13 char* longestPalindrome(char* s) {
14     char *t;
15     char* ans;
16     t=(char*)malloc(sizeof(char)*2500);
17     ans=(char*)malloc(sizeof(char)*2500);
18     t=s_Trans_t(s);
19     size_t lens;
20     lens=strlen(t);
21     int p[2500],mx=0,id=0,max_id=0,min;
22     memset(p,0,sizeof(p));
23     for(int i=0;t[i]!='\0';i++)
24     {
25         min=p[2*id-i]>mx-i?mx-i:p[2*id-i];
26         p[i]=mx>i?min:1;
27         while(t[i-p[i]] == t[i+p[i]] &&(i-p[i]>=0)&&(i+p[i]<lens))
28             p[i]++;
29         if(i+p[i]>mx)
30         {
31             mx=i+p[i];
32             id=i;
33         }
34         if(p[i]>p[max_id])
35             max_id=i;
36     }
37     int j=0;
38     for(int i=max_id-p[max_id]+1;i<max_id+p[max_id]-1;i++)
39     {
40         if(t[i]!='#')
41             ans[j++]=t[i];
42     }
43     ans[j]='\0';
44     return ans;
45 }
View Code

 

posted @ 2015-07-19 12:13  Mad.King  阅读(245)  评论(0)    收藏  举报