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)
相关推荐
拓恒技术6 小时前
无人机巡检AI算法的工程化落地:从需求到交付的5个核心环节
人工智能·算法·无人机
晨曦中的暮雨6 小时前
限流算法——固定窗口、滑动窗口、漏桶、令牌桶
java·开发语言·算法
怕浪猫6 小时前
Claude Code vs Codex:Computer Use 实现原理深度拆解
算法·面试·github
文丑颜不良啊7 小时前
LeetCode876~900题目解析
java·leetcode
罗西的思考8 小时前
AI 时代的 “房谋杜断”:如何培养能力、品味与判断力
人工智能·算法·机器学习
淡海水8 小时前
07-02-源码-.NET Core GC分配路径
算法·unity·c#·.netcore·gc·1024程序员节
choumin9 小时前
C++中万能引用与std::forward的作用和用法
c++·万能引用·std forward
下一站春风里10 小时前
位运算完整学习笔记:按位与(&)+ 异或(^)
开发语言·c++·算法
DRobot10 小时前
【机械制图与CAD实战(二十五)】螺纹的表示方法
算法·机械制图
用户老李10 小时前
卡尔曼滤波自学教程 10:无迹卡尔曼滤波(UKF)
算法