最长回文子串问题
字数 1904 2025-12-13 06:35:21
最长回文子串问题
最长回文子串(Longest Palindromic Substring)是字符串算法中的经典问题,要求在一个给定的字符串中,找到最长的回文子串(即正序和倒序相同的连续字符序列)。
例如,对于字符串 "babad",最长回文子串为 "bab" 或 "aba";对于 "cbbd",最长回文子串为 "bb"。
解题思路(循序渐进)
步骤1:理解回文特性
- 回文串的核心是对称性:
- 长度为奇数的回文:中心是单个字符,如
"aba",从中心向两边扩展时,左右字符相同。 - 长度为偶数的回文:中心是两个相同字符,如
"bb",从中心向两边扩展时,左右字符相同。
- 长度为奇数的回文:中心是单个字符,如
步骤2:暴力解法(Baseline)
- 最简单的方法是枚举所有子串(共
O(n²)个),检查每个子串是否为回文(检查需O(n)时间),总时间复杂度为O(n³)。- 不推荐,因为对长字符串效率极低。
步骤3:中心扩展法(核心解法)
- 核心思想是枚举所有可能的回文中心,向两边扩展直到不再满足回文条件。
- 对长度为
n的字符串,可能的回文中心有2n-1个:- 以单个字符为中心:共
n个(如s[i])。 - 以两个字符之间的空隙为中心:共
n-1个(如s[i]和s[i+1]之间)。
- 以单个字符为中心:共
- 对每个中心,向左右扩展并判断是否相等,记录最大长度和对应的起始位置。
- 时间复杂度:
O(n²)(每个中心最多扩展O(n)次)。 - 空间复杂度:
O(1)(只存储结果)。
实现细节:
- 初始化
start = 0和maxLen = 1(最小回文长度为1)。 - 遍历每个中心
i:- 对奇数中心:
left = i,right = i。 - 对偶数中心:
left = i,right = i+1。
- 对奇数中心:
- 扩展函数:当
left >= 0且right < n且s[left] == s[right]时,left--,right++。 - 更新最大长度:
len = right - left - 1,若len > maxLen,则更新maxLen和start(起始位置为left+1)。 - 返回子串
s[start:start+maxLen]。
步骤4:动态规划(优化记忆)
- 定义
dp[i][j]表示子串s[i..j]是否为回文。 - 状态转移方程:
- 如果
s[i] == s[j]且(j-i <= 2或dp[i+1][j-1] == true),则dp[i][j] = true。 - 否则
dp[i][j] = false。
- 如果
- 初始化:单个字符一定是回文(
dp[i][i] = true)。 - 从长度较短的子串向长度较长的子串递推,记录最长回文子串。
- 时间复杂度:
O(n²),空间复杂度:O(n²)。
步骤5:Manacher算法(进阶优化)
- 专门用于解决最长回文子串的线性时间算法。
- 核心步骤:
- 预处理:在原字符串每个字符间插入分隔符(如
#),使所有回文长度变为奇数。 - 维护一个数组
p[i]表示以i为中心的最长回文半径(包括中心)。 - 利用对称性避免重复计算:
- 维护当前已知的最右回文边界
right和对应的中心center。 - 若
i < right,则p[i]可从p[mirror]快速初始化,然后继续扩展。
- 维护当前已知的最右回文边界
- 遍历所有中心,更新
p[i]、right和center,并记录最大值。
- 预处理:在原字符串每个字符间插入分隔符(如
- 时间复杂度:
O(n),空间复杂度:O(n)。
示例演示
以字符串 "babad" 为例,用中心扩展法:
- 中心
i=0(字符'b'):- 奇数扩展:左右都是
'b',长度为1。 - 偶数扩展:
(b,a)不匹配,跳过。
- 奇数扩展:左右都是
- 中心
i=1(字符'a'):- 奇数扩展:
"bab"(左'b',右'b'匹配),长度3 → 更新最大长度。 - 偶数扩展:
(a,b)不匹配。
- 奇数扩展:
- 中心
i=2(字符'b'):- 奇数扩展:
"aba"(左'a',右'a'匹配),长度3 → 更新最大长度。
- 奇数扩展:
- 最终得到最长回文子串
"bab"或"aba"。
总结
- 中心扩展法:直观易懂,面试常用。
- 动态规划:适用于需要多次查询子串回文性的场景。
- Manacher算法:适合对性能要求极高的场景(如处理超长字符串)。