力扣刷题第4天——最长回文子串

一、题目概要

来源:力扣(LeetCode)
链接:
力扣

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

示例1:

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

示例2:

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

二、初始思路及代码

1、初始思路

使用类似第二题的滑动窗口解决->通过改变不同的启示位置依次尝试不同的字符串,与其逆转后的字符串对比,若二者相等则更新最大长度和最长回文,否则继续进行查找。

2、未通过的代码

class Solution {
public:
    string longestPalindrome(string s) { 
        int maxLength=0;
        string ans="";     
        for(int i=0;i<s.length();i++){
            string tempStr="";
            string str="";
            for(int j=i;j<s.length();j++){
                str+=s[j];
                tempStr=str;
                reverse(str.begin(),str.end());
                if(tempStr==str){
                    if(str.length()>maxLength){
                        maxLength=str.length();
                        ans=tempStr;
                    }
                }
                str=tempStr;
            }
        }
        return ans;
    }
};

3、错误分析

通过双重循环+逆转判断等操作增大了时间复杂度,导致运行超时未能通过。

三、正确答案

1、动态规划

1.1思路

设P(i,j)为存放是s[i]~s[j]是否为回文的判断结果的bool型变量,则会出现一个规律:当s[i:j](从s[i]到s[j])为回文时,s[i+1:j-1]也必定是回文,根据此规律可发现该问题存在递推关系。

此时有两个特殊情况:

①当s[i:j]的长度为1时,则该字符串必定是回文

②当s[i:j]的长度为2时,只要满足s[i]==s[i+1]则该字符串必定为回文

因此可以用情况②作为递推的底层,进而判断出所需结果。

1.2代码

class Solution {
public:
    string longestPalindrome(string s) { 
        int n=s.size();
        if(n<2){
            return s;
        }

        int maxLen=1,begin=0;
        vector<vector<int>>dp(n,vector<int>(n));//用dp[i,j]存放从i到j的字符串是否为回文的判断结果
        for(int i=0;i<n;i++){
            dp[i][i]=true;
        }
        //枚举可能的回文长度
        for(int len=2;len<=n;len++){
            for(int i=0;i<n;i++){//左边界
                int j=len+i-1;//右边界
                if(j>=n){
                    break;//右边界越界
                }

                if(s[i]!=s[j]){
                    dp[i][j]=false;
                }
                else{
                    if(j-i<3){
                        dp[i][j]=true;
                    }
                    else{
                        dp[i][j]=dp[i+1][j-1];//递推
                    } 
                }
                if(dp[i][j]&&j-i+1>maxLen){
                    maxLen=j-i+1;
                    begin=i;
                }
            }
        }
        return s.substr(begin,maxLen);
    }
};

1.3代码分析

时间复杂度O(n^2)

空间复杂度O(n^2)

2中心扩展算法

2.1思路

核心思想与递推类似,依次选定字符串不同位置的s[i]作为中心点,依次向外扩展。根据上一解法可知,如果s[i:j]是回文,则s[i+1:j-1]必然是回文。因此该算法利用该特点向外扩展,直到扩展到的两个字符s[i]和s[j]不再相等后,返回两个下标i和j。

此外,扩展是会遇到两个不同情况:

①以奇数字符为中心,如bab的中心字符为a,是奇数字符,此时只需要从下标为1的位置直接向外扩展即可

②以偶数字符为中心,如baab的中心字符为aa,是偶数字符,此时则需要从i和i+1两个位置分别向外扩展

因此在书写外接函数时直接确定两个下标变量,若是情况①则传入i和i,若是情况②则传入i和i+1。

2.2代码

class Solution {
public:
    pair<int,int>expandAroundCenter(const string& s,int left,int right){
        while(left>=0&&right<s.size()&&s[left]==s[right]){
        //向外扩展->感觉类似递推
            left--;
            right++;
        }
        return {left+1,right-1};
    }

    string longestPalindrome(string s) { 
        int begin=0,end=0;
        for(int i=0;i<s.size();i++){
            auto [left1,right1]=expandAroundCenter(s,i,i);//长度为1的情况
            auto [left2,right2]=expandAroundCenter(s,i,i+1);//长度为2的情况
            if(right1-left1>end-begin){
                begin=left1;
                end=right1;
            }
            if(right2-left2>end-begin){
                begin=left2;
                end=right2;
            }
        }
        return s.substr(begin,end-begin+1);
    }
};

2.3代码分析

时间复杂度:O(n^2)

空间复杂度:O(1)

3、Manacher 算法(等后期有兴趣再补充)

四、每日打卡(滴滴!!)

2022.4.15 打卡完成!!!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值