动态规划
d p ( i , j ) = { t r u e , i = j s [ i ] = = s [ j ] ? t r u e : f a l s e , j − i < 2 d p ( i + 1 , j − 1 ) & & s [ i ] = = s [ j ] , j − i > = 2 dp(i,j)=\left\{ \begin{aligned} &true , \quad i = j\\ &s[i] == s[j]?true:false\quad, j-i<2\\ &dp(i+1,j-1)\&\&s[i] == s[j] ,\quad j - i>=2 \end{aligned} \right. dp(i,j)=⎩⎪⎨⎪⎧true,i=js[i]==s[j]?true:false,j−i<2dp(i+1,j−1)&&s[i]==s[j],j−i>=2
string longestPalindrome(string s) //动态规划
{
int size = s.size();
vector<vector<bool>> dp(size,vector<bool>(size,false));
int start = 0;
int maxLength = 1;
for (int i = 0; i < size; i++)
{
for (int j = 0; j <=i; j++)
{
if (i - j < 2)
{
dp[j][i] = (s[j]==s[i]);
}
else if (i - j >= 2)
{
dp[j][i] = (s[j] == s[i]) && (dp[j+1][i-1]);
}
if (dp[j][i] && maxLength < i - j + 1)
{
maxLength = i - j + 1;
start = j;
}
}
}
return s.substr(start,maxLength);//start表示开始的下标,maxlength表示返回字符串的长度
}
中心拓展算法
#include<bits/stdc++.h>
using namespace std;
int expandAroundCenter(string s, int left, int right) {
int L = left, R = right;
while (L >= 0 && R < s.length() && s[L] == s[R]) {
L--;
R++;
}
return R - L - 1;
}
string longestPalindrome(string s) {
if (s == "" || s.length() < 1) return "";
int start = 0, end = 0;
for (int i = 0; i < s.length(); i++) {
int len1 = expandAroundCenter(s, i, i); //从一个字符扩展
int len2 = expandAroundCenter(s, i, i + 1); //从两个字符之间扩展
int len = max(len1, len2);
//根据 i 和 len 求得字符串的相应下标
if (len > end - start) {
start = i - (len - 1) / 2;
end = i + len / 2;
}
}
return s.substr(start, end + 1);
}
int main(){
string s = "ababaabc";
string ss = longestPalindrome(s);
printf("%s",ss.c_str());
}
马拉车算法
马拉车算法是基于中心拓展算法的优化,首先预处理变成一个奇数串,然后利用回文串对称的性质进行优化。
需要注意:首先预处理的时候先加一个’$‘在按照顺序一个’#‘一个字符组成一个新的串,新串的最后一位会默认’/0’,所以还是个奇数串。
其中有好几个特殊的情况,下面的代表处理的非常好,如果想要详细了解,自行百度看看大佬的博客吧!
//返回源字符串S的最长回文子串
string Manacher(string s){
//预处理源串
string t = "$#";
for(int i=0; i<s.size(); i++){
t+=s[i];
t+="#";
}
//新建p数组,大小和t串一致,初始化为0 ,p[i]表示以t[i]为中心的回文串半径
vector<int> p(t.size() , 0);
//设定重要参数 mx(某回文串延伸到的最右边下标),id(mx所属回文串中心下标),
//reCenter(结果最大回文串中心下标),reLen(最大长回文长度)
int mx = 0, id = 0, reCenter = 0, reLen = 0;
//遍历t字符串
for(int i=1; i<t.size(); i++){
//核心算法
p[i] = mx > i ? min(mx - i , p[2*id - i]) : 1;
//上面的语句只能确定i~mx的回文情况,至于mx之后的部分是否对称,就只能老老实实去匹配了,匹配一个p[i]++
while(t[i + p[i]] == t[i - p[i]]) p[i]++;
//当t[i]匹配的 右边界超过mx时mx和id就更新
if(i+p[i] > mx){
mx = i+p[i];
id = i;
}
//更新结果数据
if(p[i] > reLen){
reLen = p[i];
reCenter = i;
}
}
return s.substr((reCenter - reLen) / 2 , reLen - 1) ;
}