动态规划解最长回文子串:深入解析与优化问题
问题背景
在字符串处理中,寻找最长回文子串是一个经典问题。回文串是指正读反读都相同的字符串,例如 "aba"、"abba" 等。今天我们将通过一道 LeetCode 算法题(编号:5)来探讨如何高效解决这个问题。
动态规划解法思路
使用动态规划解决最长回文子串问题的核心思想是利用已计算的子问题结果来避免重复计算。我们定义二维数组 booleanArray[i][j]
表示子串 s[i..j]
是否为回文串:
基本情况:
- 单字符:booleanArray
[i][i] = true
- 双字符:booleanArray
[i][j] = (s[i] == s[j])
- 单字符:booleanArray
状态转移方程:
- 当
s[i] == s[j]
且 booleanArray[i+1][j-1] = true
时,booleanArray[i][j] = true
- 否则 booleanArray
[i][j] = false
- 当
参考力扣题解:
代码实现与解析
public class longestPalindrome {public String longestPalindrome(String s) {char[] charArray = s.toCharArray();int length = s.length();if(length==2){if(charArray[0]==charArray[1]){return s;}else{return s.substring(0,1);}}if(length==1){return s;}boolean[][] booleanArray=new boolean[length][length];int start=0;int maxLength =0;for(int i=0;i<length;i++){booleanArray[i][i]=true;}boolean result=false;for(int L=2;L<=length;L++){result=false;for(int i=0;i<length;i++){int j=i+L-1;if(j>length-1){break;}if(charArray[i]!=charArray[j]){booleanArray[i][j]=false;}else{if(j-i+1==2){booleanArray[i][j]=true;result=true;}else{booleanArray[i][j]=booleanArray[i+1][j-1];}if(j-i+1>maxLength&&booleanArray[i][j]){start=i;maxLength=L;result=true;}}}}String str=new String(charArray,start, maxLength);if(str==null){return new String(charArray,0,1);}else{return str;}}}
关键点解析
边界处理:
- 长度为0:直接返回空字符串
- 长度为1:本身就是回文
- 长度为2:相等时为回文,否则取任一字符
动态规划表初始化:
- 所有长度为1的子串自动成为回文串
子串长度遍历:
- 从最小的子串长度2开始,逐步扩展到整个字符串
- 内层循环检查所有可能的子串起始位置
回文判断优化:
- 首尾字符不等:直接标记为非回文
- 首尾字符相等:根据内部子串状态决定
最长子串追踪:
- 实时更新最长回文子串的起始位置和长度
复杂度分析
- 时间复杂度:O(n²)
- 双重循环遍历所有可能的子串
- 空间复杂度:O(n²)
- 需要二维数组存储动态规划状态
优化方向
空间优化:
- 使用滚动数组可将空间复杂度降至O(n)
中心扩展法:
- 空间复杂度可优化至O(1)
- 枚举所有可能的中心点并向两侧扩展
Manacher算法:
- 时间复杂度优化至O(n)
- 专门解决最长回文子串的高效算法
总结
动态规划是解决最长回文子串问题的高效方法之一。虽然它的空间复杂度较高,但思路清晰,代码易于实现。通过逐步构建子问题的解,我们能够有效地找到整个字符串中最长的回文子串。实际应用中,可以根据具体场景选择动态规划、中心扩展或Manacher算法等不同解决方案。
掌握这类字符串处理问题的核心在于理解状态转移方程的推导以及边界条件的处理,这也是解决许多动态规划问题的通用技巧。