LeetCode-5.最长回文子串 C++实现

一.问题描述

给你一个字符串 s,找到 s 中最长的回文子串(如果字符串向前和向后读都相同,则它满足 回文性。)。

示例 1:

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

示例 2:

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

提示:

  • 1 <= s.length <= 1000

  • s 仅由数字和英文字母组成

二.问题思路 

2.1暴力搜索(从两边向中间收缩)

 
比较容易想到的算法是暴力搜索算法,对于每个可能的子串长度,从最长到最短,检查是否存在这样的回文子串。一旦找到,立即返回。
具体步骤

1. 外层循环从字符串长度开始,逐渐减少到1。

2. 对于每个长度l,从0到n-l的位置开始,检查子串s[i..i+l-1]是否是回文。

3. 一旦找到第一个符合条件的回文子串,立即返回,因为它是最长的。

不过,这种方法的缺点是对于每个长度len,可能需要检查n-len+1个子串,每个子串需要O(len)的时间来判断是否是回文。总的时间复杂度是O(n³)。
代码实现

#include <string>
using namespace std;

class Solution {
public:
    string longestPalindrome(string s) {
        int n = s.size();
        if (n == 0) return "";
        
        // 从最长子串开始检查
        for (int len = n; len >= 1; len--) {
            for (int start = 0; start <= n - len; start++) {
                int end = start + len - 1;
                if (isPalindrome(s, start, end)) {
                    return s.substr(start, len);
                }
            }
        }
        return "";
    }

private:
    // 检查子串 s[left..right] 是否为回文
    bool isPalindrome(const string& s, int left, int right) {
        while (left < right) {
            if (s[left] != s[right]) return false;
            left++;
            right--;
        }
        return true;
    }
};

时间复杂度:O(n³),遍历所有子串并检查回文的开销较高。
缺点:不适用于长字符串,但实现简单。

2.2中心扩展法 

 更高效的算法是中心扩展法,以每个字符为中心,向两边扩展,寻找最长的回文子串。同时,还需要考虑回文的长度可能是奇数或偶数的情况,比如“aba”是奇数长度,中心是中间的“b”;而“abba”是偶数长度,中心在两个“b”之间。因此,对于每个字符,我们需要考虑这两种情况,分别进行扩展。

比如,对于示例1中的s = "babad",从每个字符开始扩展:

以第一个字符b为中心,向左无法扩展,向右到a,此时回文是"b";以第二个字符a为中心,向左是b,向右是b,形成"bab";继续向右扩展可能得到更长的吗?这里可能还需要考虑其他中心的情况。但是,这样可能需要遍历每个字符,并且每个字符最多扩展n次,所以总的时间复杂度是O(n²),这应该比之前的O(n³)好很多。

具体步骤

1. 遍历字符串中的每一个字符,作为可能的回文中心。

2. 对每个中心,分别处理奇数长度和偶数长度的回文情况。

3. 对于每种情况,向两边扩展,直到不再满足回文条件为止。

4. 记录每次扩展得到的回文子串的起始和结束位置,比较长度,更新最长回文的信息。

比如,对于s = "cbbd",当处理第二个b的时候,以它为中心的奇数长度回文是"b",而偶数长度的情况则是和后面的b组成"bb",此时需要扩展检查两边是否相同。
核心思想
以每个字符为中心,向两边扩展寻找回文子串,并同时处理奇数和偶数长度的回文。例如,对于字符 s[i],分别以 s[i] 为中心(奇数长度)和以 s[i] 与 s[i+1] 为中心(偶数长度)进行扩展。
代码实现

#include <string>
using namespace std;

class Solution {
public:
    string longestPalindrome(string s) {
        if (s.empty()) return "";
        int start = 0, max_len = 0;
        for (int i = 0; i < s.size(); ++i) {
            int len1 = expand(s, i, i);   // 奇数长度回文
            int len2 = expand(s, i, i+1); // 偶数长度回文
            int current_len = max(len1, len2);
            if (current_len > max_len) {
                max_len = current_len;
                start = i - (current_len - 1) / 2; // 计算起始位置
            }
        }
        return s.substr(start, max_len);
    }

private:
    int expand(const string& s, int left, int right) {
        while (left >= 0 && right < s.size() && s[left] == s[right]) {
            left--;
            right++;
        }
        return right - left - 1; // 返回回文长度
    }
};

时间复杂度:O(n²)
空间复杂度:O(1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值