最长回文子串算法(leetcode第5题)

题目描述:

给你一个字符串 s,找到 s 中最长的回文子串。

如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。

示例 1:

输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。

示例 2:

输入:s = "cbbd"
输出:"bb"

算法一:

思路:

回文串两边去掉还是回文串,并使用动态规划dp[i][j]来判断s[i...j]是否是回文串

代码实现:
//对于一个子串而言,如果它是回文串,并且长度大于 222
//那么将它首尾的两个字母去除之后,它仍然是个回文串
class Solution
{
public:
    string longestPalindrome(string s){
        int n=s.size();
        if(n<2){
            return s;
        }
        int left,right,len;
        int begin=0,max=1;//返回字串的头尾
        // dp[i][j] 表示 s[i..j] 是否是回文串
        vector<vector<int>> dp(n,vector<int>(n));
        for(int i=0;i<n;i++) dp[i][i]=1;
        //枚举字串的长度len
        for(len=2;len<=n;len++){
            for(left=0;left<len;left++){
                //right-left+1=len
                right=len+left-1;
                //right越界
                if(right>=n) break;
                //不为回文子串
                if(s[left]!=s[right]) dp[left][right]=0;
                //是回文子串
                else{
                    //长度小于4(1,2,3)
                    //如 aba,aa,a
                    if(len<4) dp[left][right]=1;
                    //
                    else{
                        //只有s[i+1:j−1]是回文串,并且s的第i和j个字母相同时
                        //s[i:j]才会是回文串。
                        //所以不能写成dp[left][right]=1
                        //因为这只满足了第i和j个字母相同
                        dp[left][right]=dp[left+1][right-1];
                    }
                }
                //更新头尾
                if(dp[left][right]==1&&max<len){
                    max=len;//从头开始需要遍历的长度
                    begin=left;//头
                }
            }
        }
        return s.substr(begin,max);
    }
};

算法二:

思路:

从中心开始向两边扩展,并考虑中心是奇数还是偶数

代码实现:
class Solution
{
public:
    pair<int,int> expandSubstr(const string &s,int left,int right){
        //向中心两边扩展
        while(left>=0 && right<s.size() && s[left]==s[right]){
            --left;
            ++right;
        }
        //返回不符合情况的字串的前一个字串,故要left加回1,right减回1
        return {left+1,right-1};
    }
    string longestPalindrome(string s){
        int start=0,end=0;
        for(int i=0;i<s.size();i++){
            auto [left1,right1] = expandSubstr(s,i,i);//中心为奇数的字串
            auto [left2,right2] = expandSubstr(s,i,i+1);//中心为偶数的字串
            //分类
            if(right1-left1>end-start){
                end = right1;
                start = left1;
            }
            if(right2-left2>end-start){
                end = right2;
                start = left2;
            }

        }
        return s.substr(start,end-start+1);
        
    }
};

算法三:Manacher算法

还在学习中,之后补充代码

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值