[算法]死磕最长回文子串
题目
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。
示例 2:
输入: "cbbd"
输出: "bb"
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-palindromic-substring
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
思路1
基于中心点枚举的算法,时间复杂度是O(n^2)。
先确定中间的点,这里包括两种,中间只有一个元素,或者中间有两个元素。
思路2
基于动态规划的算法,时间复杂度 O(n^2),会耗费额外的 O(n^2) 的空间复杂度。
dp[i][j],i <= j,表示从i到j是否是回文串,
状态转移方程是dp[i][j] = dp[i + 1][j - 1] && s[i] = s[j]。
思路3
使用 Manancher's Algorithm,可以在 O(n) 的时间内解决问题。
参考资料:https://www.felix021.com/blog/read.php?2040。
这个方法虽然最优,感觉一般人很难想到。
代码
方法1
class Solution { public String longestPalindrome(String s) { if(s == null || s.length() == 0){ return ""; } int start = 0, len = 0, longest = 1; for (int i = 0; i < s.length(); i++) { len = longestPalindromeLength(s, i, i); if (len > longest) { longest = len; start = i - len / 2; } len = longestPalindromeLength(s, i, i + 1); if (len > longest) { longest = len; start = i - len / 2 + 1; } } return s.substring(start, start + longest); } public int longestPalindromeLength(String s, int left, int right) { int len = 0; while (left >= 0 && right < s.length()) { if (s.charAt(left) != s.charAt(right)) { break; } len += left == right ? 1 : 2; left--; right++; } return len; } }
方法2
class Solution { public String longestPalindrome(String s) { if (s == null || s.length() == 0) { return ""; } int start = 0, longest = 1; int n = s.length(); boolean dp[][] = new boolean[n][n]; for (int i = 0; i < n; i++) { dp[i][i] = true; } for (int i = 0; i < n - 1; i++) { dp[i][i + 1] = s.charAt(i) == s.charAt(i + 1); if(dp[i][i + 1]){ start = i; longest = 2; } } for (int i = n - 3; i >= 0; i--) { for (int j = i + 2; j < n; j++) { dp[i][j] = dp[i + 1][j - 1] && s.charAt(i) == s.charAt(j); if(dp[i][j] && longest < j - i + 1){ start = i; longest = j - i + 1; } } } return s.substring(start, start + longest); } }