LeetCode 5.最长回文子串

题目描述

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

示例 1:
输入: “babad”
输出: “bab”
注意: “aba” 也是一个有效答案。

示例 2:
输入: “cbbd”
输出: “bb”

解题思路

  • 暴力法:利用两个for循环,找出所有可能种回文子串,每次找出一个回文子串时与前一个进行比较选择回文子串长度大的作为返回的结果
  • 回文:翻转过后保持不变,例如回文数:121,1221,13231,回文子串:“abcba”,“bcb”

Cpp实现

class Solution {
public:
    string longestPalindrome(string s) {
        string res = "";//利用res存放结果
        string temp = "";//利用temp存放循环过程中的子串
        for(int i = 0; i < s.size();i++){
            for(int j = i; j < s.size();j++){
                temp = temp + s[j];
                string _temp = temp;
                std::reverse(_temp.begin(),_temp.end());
                if(_temp == temp)
                res = res.size() > temp.size() ? res : temp;
                //一个字符串中可能存在多个回文子串
                //我们需要找到最长的回文子串
            }
            temp = "";//循环完成一次后把temp转化成空字符串,再次进入循环去记录过程中给子串
        }
        return res;
    }
};

在这里插入图片描述

  • 当字符串长度很长时,提交会超出时间限制
  • 时间复杂度:O(n^3)

Python实现

  • 利用Python切片方法
class Solution:
    def longestPalindrome(self, s: str) -> str:
        if s == s[::-1]:
            return s
        max_len = 1
        res = s[0]
        for i in range(len(s) - 1):
            for j in range(i + 1,len(s)):
                if j - i + 1 > max_len and s[i:j + 1] == s[i:j + 1][::-1]:
                    max_len = j - i + 1
                    res = s[i:j + 1]
        return res

在这里插入图片描述

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

解题思路

  • 动态规划:定义一个二维数组bool dp[len-1][len-1]来记录遍历字符串所得的状态,dp[l][r]true表示从l到r的子串为回文串,false表示不是回文串
  • 初始化二维数组,单个字符为回文串,所以定义dp[i][i]=true
  • 找到状态转移方程:dp[l][r] = (s[r] == s[l]) && (r - l == 1 || dp[l+1][r-1]) ? true : false

Cpp实现

class Solution {
public:
    string longestPalindrome(string s) {
        int len = s.length();
        if (len == 0)
            return s;
        bool dp[len][len];
        int start = 0, end = 0;
        for (int i = 0; i <len; i++)
            dp[i][i] = true;
        for (int r = 1; r < len; r++)
            for (int l = 0; l < r; l++)
                if (s[r]==s[l] && (r-l==1 || dp[l+1][r-1])) {
                    dp[l][r] = true;
                    if (r-l > end-start) {
                        start = l; end = r;
                    }
                    continue;
                }else
                    dp[l][r] = false;
        return s.substr(start, end-start+1);
    }
};

在这里插入图片描述

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

Java实现

  • 状态:dp[i][j]:表示子串s[i,…,j]是否为回文子串
  • 状态转移方程:dp[i][j] = (s[i] == s[j]) and dp[i +1][j - 1]
  • 边界条件:(j - 1) - (i + 1) + 1 < 2,整理得:j - i < 3时,即无法构成区间,相当于s[i,....,j]长度为2或者3时,不用检查子串是否回文
  • 初始化:dp[i][i] = true ,即对角线上的为true(一个字符一定是回文串)
  • 输出:在得到一个状态的值为true的时候,记录起始位置和长度,填表完成后再截取
    在这里插入图片描述
class Solution {
    public static String longestPalindrome(String s) {
        int len = s.length();
        if (len < 2) {
            return s;
        }
        int maxLen = 1;
        int begin = 0;
        //初始化二维表
        //dp[i][j]表示s[i...j]是否为回文串
        boolean[][] dp = new boolean[len][len];
        for (int i = 0; i < len; i++) {
            dp[i][i] = true;
        }
        char[] charArray = s.toCharArray();
        //注意:左下角先填,因为 每一个dp[i][j] 需要参考dp[i + 1] [j - 1] 即为左下角
        //一列一列的填,只需要填上三角,且对角线已经赋值,只需要填对角线上方的值即可
        for (int j = 1; j < len; j++) {
            for (int i = 0; i < j; i++) {
                if (charArray[i] != charArray[j]) {
                    dp[i][j] = false;
                }else{
                    //头尾去掉没有字符或剩下一个字符的时候
                    if (j - i < 3) {
                        dp[i][j] = true;
                    } else {
                        //参考中间部分的答案
                        dp[i][j] = dp[i + 1][j - 1];
                    }
                }

                //只要dp[i][j] = true成立,就表示子串s[i...j]是回文,记录回文长度和起始位置
                if (dp[i][j] && j - i + 1 > maxLen) {
                    maxLen = j - i + 1;
                    begin = i;
                }
            }
        }
        return s.substring(begin, begin + maxLen);
    }
}

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

解题思路

  • 马拉车算法:如果字符串是奇数个,我们通过遍历所有字符串,再对所有字符串进行左右匹配,然后得到长度最大的字符串,如果字符串是偶数个,我们重新构造新的字符串即可
  • 学习一下马拉车算法并进行优化,学习一下别人写的代码,实在是太厉害了

Cpp实现

class Solution {
public:
    string longestPalindrome(string s) {
        //插入"#"
        string t="$#";
        for(auto c:s){
            t+=c;
            t+='#';
        }
        
        vector<int> p(t.size(),0);
        
        //mx表示某个回文串延伸在最右端半径的下标,id表示这个回文子串最中间位置下标
     //resLen表示对应在s中的最大子回文串的半径,resCenter表示最大子回文串的中间位置
        int mx=0,id=0,resLen=0,resCenter=0;
        
        //建立p数组
        for(int i=1;i<t.size();++i)
        {
         //更新p[i]的值
            p[i]=mx>i?min(p[2*id-i],mx-i):1;
            
            //遇到三种特殊的情况,需要利用中心扩展法
            while(t[i+p[i]]==t[i-p[i]])p[i]++;
            
            //半径下标i+p[i]超过边界mx,需要更新
            if(mx<i+p[i]){
                mx=i+p[i];
                id=i;
            }
            
            //更新最大回文子串的信息
            if(resLen<p[i]){
                resLen=p[i];
                resCenter=i;
            }
        }
        
        //最长回文子串长度为半径-1,起始位置为中间位置减去半径再除以2
        return s.substr((resCenter-resLen)/2,resLen-1);
    }
};

在这里插入图片描述

  • 时间复杂度:O(n)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: 最长回文子串可以通过两种方法来实现。第一种是使用心扩展法,代码如下: ```python class Solution: def check(self, s, l, r): while l >= 0 and r < len(s) and s[l == s[r]: l -= 1 r += 1 return l + 1, r - 1 def longestPalindrome(self, s: str) -> str: start, end = 0, 0 for x in range(len(s)): l1, r1 = self.check(s, x, x) l2, r2 = self.check(s, x, x + 1) if r1 - l1 > end - start: start, end = l1, r1 if r2 - l2 > end - start: start, end = l2, r2 return s[start:end+1] ``` 第二种方法是使用动态规划,代码如下: ```python class Solution: def longestPalindrome(self, s: str) -> str: res = '' for i in range(len(s)): start = max(0, i - len(res) - 1) temp = s[start:i+1] if temp == temp[::-1]: res = temp else: temp = temp<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [5. 最长回文子串(Python 实现)](https://blog.csdn.net/d_l_w_d_l_w/article/details/118861851)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [LeetCode(Python3)5.最长回文子串](https://blog.csdn.net/weixin_52593484/article/details/124718655)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [力扣 (LeetCode)刷题笔记5.最长回文子串 python](https://blog.csdn.net/qq_44672855/article/details/115339324)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值