最长回文子串
1、参考资料
https://leetcode-cn.com/problems/longest-palindromic-substring/
https://blog.csdn.net/u013309870/article/details/70742315
https://zhuanlan.zhihu.com/p/38251499
https://labuladong.gitbook.io/algo/gao-pin-mian-shi-xi-lie/zui-chang-hui-wen-zi-chuan
2、题目要求
题目描述
给定一个字符串 s
,找到 s
中最长的回文子串。你可以假设 s
的最大长度为 1000。
示例 1:
输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。
示例 2:
输入: "cbbd"
输出: "bb"
3、代码思路
方法一:中心扩散法
-
我们遍历字符串
str
中的每一个字符,以该字符为中心,向两边扩散求最长回文字符串 -
对于
"xabay"
这种字符串,存在中心对称点,左指针left
和右指针right
同时指向字符'b'
,然后向两侧扩展 -
对于
"xabbay"
这种字符串,不存在中心对称点,左指针left
指向左侧的字符b
,右指针right
指向右侧的字符b
,然后向两侧扩展 -
我们在遍历字符串
str
中的每一个字符,存在中心对称点和不存在中心对称点的情况都要考虑到,expandFromCenter()
方法以left
,right
为中心起点,向两侧扩展,寻找回文字符串 -
考虑到程序性能,我们在
expandFromCenter()
方法中,选择返回回文字符串的长度,并不是返回左右边界的索引int[] {left, right}
,就是将链表长度再转换左右边界索引的时候,逻辑有点绕,举一些例子就明白了
方法二:动态规划法
4、代码实现
中心扩散法:时间复杂度 O(n2),空间复杂度 O(1)
/**
* @ClassName LongestPalindromeDemo
* @Description TODO
* @Author Heygo
* @Date 2020/9/3 14:22
* @Version 1.0
*/
public class LongestPalindromeDemo {
public static void main(String[] args) {
Solution solution = new Solution();
String longestPalindrome = solution.longestPalindrome("babad");
System.out.println(longestPalindrome);
}
}
class Solution {
/**
* 求 str 的最长回文字符串
*
* @param str 输入的字符串
* @return str 的最长回文字符串
*/
public String longestPalindrome(String str) {
// Gurad safe
if (str == null || str.length() < 1) {
return "";
}
int start = 0;
int end = 0;
// 遍历字符串中每一个字符
for (int i = 0; i < str.length(); i++) {
// 以当前字符为中心对称点,以 i 为中心向两边扩散
int len1 = expandFromCenter(str, i, i);
// 无中心对称点,,以 i 为左指针,i+1 为右指针,向两边扩散
int len2 = expandFromCenter(str, i, i + 1);
// 求得最大的回文串长度
int len = Math.max(len1, len2);
// 如果当前回文串长度大于之前的回文串长度
if (len > end - start) {
// 对于 "xabay" 这种字符串,len = 3 为奇数
// 对于 "xabbay" 这种字符串,len = 4 为偶数
start = i - (len - 1) / 2;
end = i + len / 2;
}
}
// 返回最长回文字符串
return str.substring(start, end + 1);
}
/**
* 中心扩展法求 str 的最长回文字符串
* 如果匹配像 "aba" 这样有中心对称点的字符串,left == right
* 但如果匹配像 "abba" 这样没有中心对称点的字符串,right = left + 1
*
* @param str 源字符串
* @param left left 起点
* @param right right 起点
* @return 回文字符串的长度
*/
public int expandFromCenter(String str, int left, int right) {
while (left >= 0 && right < str.length() && str.charAt(left) == str.charAt(right)) {
left--;
right++;
}
// 回文字符串的长度
// 对于 "xabay" 这种字符串,执行完成后 left 指向 x,right 指向 y,right - left - 1 = 3,为回文字符串的长度
// 对于 "xabbay" 这种字符串,执行完成后 left 指向 x,right 指向 y,right - left - 1 = 4,为回文字符串的长度
return right - left - 1;
}
}