LeetCode 5. 最长回文子串:从暴力匹配到中心扩展的思维演进

题目描述

题目来源 :LeetCode 第 5 题

标签:字符串、动态规划、中心扩展

题目要求 :

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

什么是回文串?

如果一个字符串正着读和反着读是一样的,那么它就是回文串。例如 "aba"、"abba" 都是回文串。

提示与约束条件:

  • 1 <= s.length <= 1000

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

方法一:字符串反转 + 最长公共子串

1. 初始思路

回文串的特性是"正读反读都一样"。一个直观的想法是:将原字符串 s 反转得到 ss,然后寻找 s 和 ss 的最长公共子串(LCS)。这个公共子串理论上就是最长回文子串。

2. 逻辑漏洞与修正

漏洞 :仅仅寻找公共子串是不够的。例如 s = "abacdfgdcaba",反转后 ss = "abacdfgdcaba",两者的最长公共子串是 "abacd",但它并不是回文。

修正 :必须验证找到的公共子串在原字符串中的索引与反转字符串中的索引是否满足对称关系。即:若 s 中起始索引为 i,ss 中起始索引为 j,匹配长度为 len,则必须满足 i + j + len == s.size(),才能保证它是真正的回文。

3. 代码实现

cpp 复制代码
class Solution {
public:
    string longestPalindrome(string s) {
        if (s.empty()) return "";
        string ss = s;
        reverse(ss.begin(), ss.end());
        string ans = "";
        
        for (int i = 0; i < s.size(); i++) {
            for (int j = 0; j < ss.size(); j++) {
                int len = 0;
                while (i + len < s.size() && j + len < ss.size() && s[i + len] == ss[j + len]) {
                    len++;
                }
                // 核心修正:验证索引对称性
                if (len > ans.size() && i + j + len == s.size()) {
                    ans = s.substr(i, len);
                }
            }
        }
        return ans;
    }
};

复杂度分析

  • 时间复杂度 :O(n3)。双层循环枚举起点为 O(n2),内部 while 匹配最坏情况为 O(n)。

  • 空间复杂度 :O(n)。需要存储反转字符串 s。

方法二:中心扩展法(最优解法)

1. 思路转变

放弃"反转匹配"的间接思路,回归回文的本质:对称性 。回文串一定有一个"中心",从这个中心向两边扩展,两边的字符必定相等。

中心可能有两种情况:

  • 奇数长度 :中心是一个字符(如 "aba",中心是 'b')。

  • 偶数长度 :中心是两个字符之间的空隙(如 "abba",中心在两个 'b' 之间)。

我们只需遍历字符串的每一个位置,将其作为中心向两边扩展,记录最长的回文即可。

2. 代码实现

cpp 复制代码
class Solution {
public:
    string longestPalindrome(string s) {
        if (s.empty()) return "";
        int start = 0, maxLen = 1;
        
        for (int i = 0; i < s.size(); i++) {
            // 奇数长度回文扩展
            int len1 = expandAroundCenter(s, i, i);
            // 偶数长度回文扩展
            int len2 = expandAroundCenter(s, i, i + 1);
            
            int len = max(len1, len2);
            if (len > maxLen) {
                maxLen = len;
                start = i - (len - 1) / 2;
            }
        }
        return s.substr(start, maxLen);
    }

private:
    int expandAroundCenter(const string& s, int left, int right) {
        while (left >= 0 && right < s.size() && s[left] == s[right]) {
            left--;
            right++;
        }
        return right - left - 1;
    }
};

复杂度分析

  • 时间复杂度:O(n2)。共有 2n−1个中心,每个中心最多扩展 O(n) 次。

  • 空间复杂度:O(1)。只需常数级别的额外空间,无需存储反转字符串。

总结与对比

方法 核心关键词 时间复杂度 空间复杂度
反转匹配法 反转、公共子串、索引验证 O(n3) O(n)
中心扩展法 对称性、奇偶中心、双指针扩展 O(n2) O(1)
相关推荐
码客-ygluu7 小时前
X3 LUA 异步分布式微服务集群框架
c++·架构·lua
forest_099 小时前
多 Agent 协作第二课:交叉验证≠独立验证
人工智能·python·算法·机器学习·prompt·agi
九英里路9 小时前
protobuf快速上手
网络·c++·中间件·json·谷歌·序列化·protobuf
纪念 22910 小时前
C++ 算法基础 (差分)
开发语言·c++·算法
文丑颜不良啊13 小时前
LeetCode2761~2780题目解析
java·leetcode
jyOverQ13 小时前
从零学 JVM(六):垃圾回收算法详解——标记清除、标记复制与标记整理
jvm·算法
ShineWinsu15 小时前
对于Qt:QTreeWidget常见属性以及QTreeWidgetItem类的解析
开发语言·c++·qt·gui·客户端·多叉树·qtreewidget
严肃小白兔15 小时前
第 06/24 期:神经网络的反向传播算法:从链式法则到梯度计算
人工智能·神经网络·算法
落羽的落羽15 小时前
【C++】C++17的主要特性
linux·服务器·开发语言·c++·算法·机器学习