Leetcode 5. Longest Palindromic Substring
https://leetcode.com/problems/longest-palindromic-substring/
class Solution {
public:
const int maxn=5000;
string longestPalindrome(string s) {
/*
回文串
马拉车算法
先隔着填充#,这样只需要考虑奇数长度的回文串就可以
P[k]:第k个字符为中心的回文串的一半长度(/2)
idx_M,用到最大坐标的回文串的中心位置.
最大坐标mx=idx_M+P[idx_M]
求P[k]时:
若k>mx,则k_r=k;
否则:
k相对idx_M的对偶坐标k_dual=2*idx_M-k,
k_r=min(k+P[k_dual],mx)
可以保证以k为中心,右边延伸到k_r时,仍为回文串
之后继续延伸即可
更新idx_M【实际只有k_r=mx时才更想idx_M】
*/
#include<algorithm>
if(s.empty()) return s;
//init
char str[maxn];
int L=2*s.size()+1;
for(int i=0;i<s.size();++i)
str[2*i]='#',str[2*i+1]=s[i];
str[L-1]='#';
int P[maxn],idx_M=0,mx=0,k_dual,k_r,ans=0;
P[0]=0;
//
for(int k=1;k<L;++k){
if(L-k<=P[ans]) break;
if(k>mx) k_r=k;
else{
k_dual=2*idx_M-k;
k_r=min(k+P[k_dual],mx);
}
while(2*k-(k_r+1)>=0 && (k_r+1)<L && str[k_r+1]==str[2*k-(k_r+1)]) ++k_r;
P[k]=k_r-k;
//更新
if(k_r>mx){
idx_M=k;
mx=k_r;
}
if(P[k]>P[ans]) ans=k;
}
string sans;
for(int i=ans-P[ans];i<=ans+P[ans];++i)
if(str[i]!='#') sans.push_back(str[i]);
return sans;
}
};
python版本
def get_palindrome_len(s,k,r):
while k-r>=0 and k+r<len(s) and s[k+r]==s[k-r]:
r+=1
return r-1
def argmax(_s,L):
return max(range(len(L)), key=lambda idx : (L[idx]+1)//2*2 if _s[idx]=='#' else L[idx]//2*2+1)
class Solution:
def longestPalindrome(self,s: str) -> str:
if len(s)==0:
return s
_s='#'.join(list(s))
L=[0 for i in range(len(_s))]
mx,mx_idx=0,0
for i in range(1,len(_s)):
if mx<i:
L[i]=get_palindrome_len(_s,i,1)
mx,mx_idx=i+L[i],i
else:
l_i=2*mx_idx-i
candidate_r=mx-i
if L[l_i]<candidate_r:
L[i]=L[l_i]
else:
L[i]=get_palindrome_len(_s,i,candidate_r)
mx,mx_idx=i+L[i],i
idx=argmax(_s,L)
return ''.join(_s[idx-L[idx]:idx+L[idx]+1].split('#'))