题目
5. Longest Palindromic Substring
思路一:暴力(O(n²))
把当字符当做最中心的一个或两个字符,向两侧枚举
class Solution {
public:
string longestPalindrome(string s) {
int n=s.size();
int l,r,cnt,max_length=0,max_l,max_r;
for(int i=0;i<n;i++){
l=i-1,r=i+1,cnt=1;
while(l>=0&&r<n&&s[l]==s[r])cnt+=2,l--,r++;
if(cnt>max_length){
max_length=cnt;
max_l = l+1;
max_r = r-1;
}
}
for(int i=0;i<n;i++){
l=i,r=i+1,cnt=0;
while(l>=0&&r<n&&s[l]==s[r])cnt+=2,l--,r++;
if(cnt>max_length){
max_length=cnt;
max_l = l+1;
max_r = r-1;
}
}
return s.substr(max_l,max_length);
}
};
或者用动态规划,思路都是一样的
思路二:二分(O(nlogn))
在思路一的基础上,我们还是把当前位置的抑或两个字符当做中心,接下来我们可以二分回文串(一半)的长度,那么问题来了,我们需要一种算法来实现下面两个事情:
- 在O(1)的时间里比较子串是否相等
- 为了可以使用二分,这个算法还必须满足可加性(也就是在不一样的字符出现之前,保证一样,出现之后,保证不一样)
这个算法就是hash
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
//最长回文子串
typedef unsigned long long ull;
ull h1[1010],h2[1010],p[1010];
int base = 131;
ull get_hash(ull hash[],int l,int r){
return hash[r]-hash[l-1]*p[r-l+1];
}
int main(){
string s;
cin>>s;
int n=s.size();
p[0]=1;h1[0]=0;h2[0]=0;
for(int i=1;i<=n;i++){
h1[i]=h1[i-1]*base + s[i-1]-'0';
h2[i]=h2[i-1]*base + s[n-i]-'0';
p[i]=p[i-1]*base;
}
int max_length=0,max_l;
for(int i=0;i<n;i++){
int l=1,r=min(i,n-i-1);
int mid=(l+r)/2;
while(l>=0&&r<=n/2&&l<=r){
if(get_hash(h1,i-mid+1,i)==get_hash(h2,n-i-mid,n-i-1))l=mid+1;
else r=mid-1;
mid=(l+r)/2;
}
if(2*(l-1)+1>max_length){
max_length=2*(l-1)+1;
max_l=i-(l-1);
}
}
for(int i=0;i<n;i++){
int l=1,r=min(i+1,n-i-1);
int mid=(l+r)/2;
while(l>=0&&r<=n/2&&l<=r){
if(get_hash(h1,i-mid+2,i+1)==get_hash(h2,n-i-mid,n-i-1))l=mid+1;
else r=mid-1;
mid=(l+r)/2;
}
if(2*(l-1)>max_length){
max_length=2*(l-1);
max_l=i-(l-1)+1;
}
}
cout<<max_length<<" "<<s.substr(max_l,max_length);
return 0;
}
思路三:Manacher (O(n))
思路参考:Manacher
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
//最长回文子串
int main(){
string s;
cin>>s;
if(s.length()==0)return 0;
int n = s.size();
n=2*n+1;
char a[n];
int p[n];
int index=0;
for(int i=0;i<n;i++)a[i]=(i%2==0)?'#':s[index++];
int R=-1,C=-1,max_r=0,max_C;
for(int i=0;i<n;i++){
if(i<R)p[i]=min(R-i,p[2*C-i]);
else p[i]=1;
while(i+p[i]<n&& i-p[i]>-1){
if(a[i+p[i]]==a[i-p[i]])p[i]++;
else break;
}
if(i+p[i]>R){
R=i+p[i];
C=i;
}
if(p[i]>max_r){
max_r=p[i];
max_C=C;
}
}
max_C=(max_C+1)/2;
cout<<s.substr(max_C-max_r/2,max_r-1);
}