动态规划解决最长回文子串问题(Longest Palindromic Substring)
字数 1431 2025-11-23 00:32:42
动态规划解决最长回文子串问题(Longest Palindromic Substring)
问题描述
最长回文子串问题要求在一个给定的字符串中,找到最长的连续子串,使得该子串正序和反序读完全相同(即回文)。例如,字符串 "babad" 的最长回文子串为 "bab" 或 "aba";字符串 "cbbd" 的最长回文子串为 "bb"。该问题需要高效地确定子串的起始和结束位置,并返回最长回文子串本身。
解题思路
动态规划(DP)通过存储中间结果来避免重复计算。对于最长回文子串问题,我们可以定义状态数组 dp[i][j] 表示子串 s[i:j+1] 是否为回文。通过填充这个二维表,逐步扩展子串长度,最终找到最长的回文子串。
步骤详解
-
状态定义
- 设
dp[i][j]是一个布尔值,表示字符串s从索引i到j的子串是否为回文。 - 初始条件:所有长度为 1 的子串都是回文(即
dp[i][i] = true)。
- 设
-
状态转移方程
- 对于长度大于 1 的子串,
s[i:j+1]是回文的条件是:- 首尾字符相等:
s[i] == s[j]。 - 去掉首尾后的子串是回文或子串长度不超过 2:
- 若
j - i <= 2(即子串长度为 2 或 3),只需首尾字符相等即可(例如 "aa" 或 "aba")。 - 若
j - i > 2,则需要dp[i+1][j-1]为true。
- 若
- 首尾字符相等:
- 综合得到转移方程:
dp[i][j] = true, 当 s[i] == s[j] 且 (j - i <= 2 或 dp[i+1][j-1] == true)
- 对于长度大于 1 的子串,
-
填充顺序
- 由于
dp[i][j]依赖于dp[i+1][j-1](即左下方的值),需要按子串长度从小到大填充。 - 外层循环遍历子串长度
L(从 2 到n),内层循环遍历起始索引i,计算结束索引j = i + L - 1。
- 由于
-
记录结果
- 在填充过程中,记录最长回文子串的起始位置
start和长度max_len。 - 当
dp[i][j]为true且当前子串长度L > max_len时,更新max_len = L和start = i。
- 在填充过程中,记录最长回文子串的起始位置
-
复杂度分析
- 时间复杂度:O(n²),需要填充 n² 大小的 DP 表。
- 空间复杂度:O(n²),用于存储 DP 表。
示例演示
以字符串 "babad" 为例:
- 初始化:所有长度为 1 的子串为回文(如
dp[0][0] = true)。 - 长度 L=2:
- "ba":
s[0]≠s[1]→dp[0][1]=false。 - "ab":
s[1]≠s[2]→dp[1][2]=false。 - "ba":
s[2]≠s[3]→dp[2][3]=false。 - "ad":
s[3]≠s[4]→dp[3][4]=false。
- "ba":
- 长度 L=3:
- "bab":
s[0]==s[2]且j-i=2→dp[0][2]=true,更新start=0, max_len=3。 - "aba":
s[1]==s[3]且dp[2][2]=true→dp[1][3]=true,但长度未超过 3。
- "bab":
- 继续处理更长子串,最终最长回文子串为 "bab" 或 "aba"。
优化提示
- 实际应用中,Manacher 算法可在 O(n) 时间内解决该问题,但动态规划解法更直观易懂,适合面试中展示基础思路。
- 可优化空间复杂度至 O(n),仅存储当前和前一行的 DP 状态。