leetcode 5 最长回文子串 三种解法

动态规划

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,ji<2dp(i+1,j1)&&s[i]==s[j],ji>=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)  ;
    
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值