求解字符串的最长回文子串的Manacher’s Algorithm
2017-10-04 10:34
351 查看
Manacher’s Algorithm
用Manacher’s Algorithm求解字符串的最长回文子串:这种算法的好处是将处理的时间复杂度降低到了O(n),是一种线性方法;
算法分析:
假设字符串为:GDGFGHJKKJHGFSFFSJFHS;
在任意的两个字符的开头结尾都插入相同字符如:#;结果如下:#G#D#G#F#G#H#J#K#K#J#H#G#F#S#F#F#S#J#F#H#S#;
然后我们可以把全新的字符串的下标表示出来从0开始;
最后以全新字符串的下标创建一个数组P[];P
的值为相对应字符串所对应回文值,比如:P[1]=1、P[2]=0、P[3]=3、P[4]=0;
我们就可以看出数组P中的最大值为最长回文子串的长度,且最大值对应的字符为全新字符串的最长回文串的中心;所以算法的最核心就是求解全新字符串对应的回文数组P[]。(全新字符串长度为n)
求解P[i]分析:如下图所示;
求P[i]: 已知P[i]之前的值,C为回文串的中心,R为以C为中心的回文串的最外沿,其回文半径为R-C;从L到R以C为对称中心,i的对称点为i’。
1、当P[i]<R-i时,P[i] = P[i’];
2、当P[i]>=R-i时,P[i] = R-i ;然后接着遍历R+1和其以i为对称中心的对称点,如果还是满足对称则P[i]加1,然后一直往下遍历直到找到i的最大回文半径即P[i],然后修改对称中心把C移到i处即C = i ;同时把R= P[i]+i;接下来求解P[i+1],然后一直求解到P[n-1];
这样就可以求出来全新字符串对应的回文数组的最大值,也就求出最长回文串的长度。同时也知道最大回文串的对称中心i。
C++ 代码如下:
class Solution {
public:
string longestPalindrome(string s) {
string l;
l = s;
int r=0,i,n,j=0,i_mirror=0,centre=0; //对称中心、镜像对称点、回文半径都是0;
for(i=0;i<=s.size();i++){
l.insert(l.begin()+2*i,1,'#'); //在每个字符的开头和结尾插入#;
}
l.insert(l.begin(),1,'$'); //在全新字符串开头插入$;
n = l.size();
int p
;
for(i
4000
=0;i<n-1;i++){ //遍历全新字符串;
i_mirror = 2*centre-i; //镜像对称点与对称中心的关系
p[i] = (r>i) ?min(r-i,p[i_mirror]) : 0; //遍历是否超出当前回文串;
while(l[i+p[i]+1]==l[i-p[i]-1]){ //遍历P[i]+1和其以i为对称中心的镜像对称点;
p[i]++; //符合条件加一;
}
if(p[i]+i>r){ //符合条件交换对称中心和回文半径;
centre = i;
r = i + p[i];
}
}
int max = 0,centre_index = 0;
for(i = 1;i<n-1;i++){ //求回文数组的最大值和其对称中心;
if(p[i]>max){
max = p[i];
centre_index = i;
}
}
return s.substr((centre_index-max-1)/2,max);
}
};
代码细节:这里为了便于代码的编写对于全新字符串做一下修改,在字符串的最前面加了一个字符$。
用Manacher’s Algorithm求解字符串的最长回文子串:这种算法的好处是将处理的时间复杂度降低到了O(n),是一种线性方法;
算法分析:
假设字符串为:GDGFGHJKKJHGFSFFSJFHS;
在任意的两个字符的开头结尾都插入相同字符如:#;结果如下:#G#D#G#F#G#H#J#K#K#J#H#G#F#S#F#F#S#J#F#H#S#;
然后我们可以把全新的字符串的下标表示出来从0开始;
#G #D #G# F#G # H # J # K # K # J # H # G # F # S # F #F#S#J#F#H#S# 0 1 2 3 4 5 6 7 8 9 10 …………….. |
的值为相对应字符串所对应回文值,比如:P[1]=1、P[2]=0、P[3]=3、P[4]=0;
我们就可以看出数组P中的最大值为最长回文子串的长度,且最大值对应的字符为全新字符串的最长回文串的中心;所以算法的最核心就是求解全新字符串对应的回文数组P[]。(全新字符串长度为n)
求解P[i]分析:如下图所示;
求P[i]: 已知P[i]之前的值,C为回文串的中心,R为以C为中心的回文串的最外沿,其回文半径为R-C;从L到R以C为对称中心,i的对称点为i’。
1、当P[i]<R-i时,P[i] = P[i’];
2、当P[i]>=R-i时,P[i] = R-i ;然后接着遍历R+1和其以i为对称中心的对称点,如果还是满足对称则P[i]加1,然后一直往下遍历直到找到i的最大回文半径即P[i],然后修改对称中心把C移到i处即C = i ;同时把R= P[i]+i;接下来求解P[i+1],然后一直求解到P[n-1];
这样就可以求出来全新字符串对应的回文数组的最大值,也就求出最长回文串的长度。同时也知道最大回文串的对称中心i。
C++ 代码如下:
class Solution {
public:
string longestPalindrome(string s) {
string l;
l = s;
int r=0,i,n,j=0,i_mirror=0,centre=0; //对称中心、镜像对称点、回文半径都是0;
for(i=0;i<=s.size();i++){
l.insert(l.begin()+2*i,1,'#'); //在每个字符的开头和结尾插入#;
}
l.insert(l.begin(),1,'$'); //在全新字符串开头插入$;
n = l.size();
int p
;
for(i
4000
=0;i<n-1;i++){ //遍历全新字符串;
i_mirror = 2*centre-i; //镜像对称点与对称中心的关系
p[i] = (r>i) ?min(r-i,p[i_mirror]) : 0; //遍历是否超出当前回文串;
while(l[i+p[i]+1]==l[i-p[i]-1]){ //遍历P[i]+1和其以i为对称中心的镜像对称点;
p[i]++; //符合条件加一;
}
if(p[i]+i>r){ //符合条件交换对称中心和回文半径;
centre = i;
r = i + p[i];
}
}
int max = 0,centre_index = 0;
for(i = 1;i<n-1;i++){ //求回文数组的最大值和其对称中心;
if(p[i]>max){
max = p[i];
centre_index = i;
}
}
return s.substr((centre_index-max-1)/2,max);
}
};
代码细节:这里为了便于代码的编写对于全新字符串做一下修改,在字符串的最前面加了一个字符$。
相关文章推荐
- Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串
- Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串
- Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串
- Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串
- Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串
- Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串
- Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串
- Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串
- Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串
- Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串
- Manacher 算法讲解 O(N)复杂度的 最长回文子串求解
- Manacher算法求字符串的最长回文子串
- Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串
- Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串
- Manacher's Algorithm 求解字符串的最长回文串
- 串子串Manacher算法: O(n)时间求字符串的最长回文子串
- [算法] Manacher算法线性复杂度内求解最长回文子串
- 字符串 manacher 最长回文子串
- Manacher's ALGORITHM: O(n)时间求字符串的最长回文子串
- Manacher算法:求解最长回文字符串,时间复杂度为O(N)