字符串-马拉车算法-5. 最长回文子串
2020-03-19 11:44:44
问题描述:
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: "babad" 输出: "bab" 注意: "aba" 也是一个有效答案。
示例 2:
输入: "cbbd" 输出: "bb"
问题求解:
解法一:DFS
对于长度为n的字符串,回文子串的中心点的个数有2 * n - 1个,其中n个是字符表示回文为奇数的情况,n - 1个是字符之间的位置表示回文为偶数的情况。
可以使用dfs来枚举所有的中心点位置,记录最长的即可。
时间复杂度:O(n ^ 2)
String res = "";
public String longestPalindrome(String s) {
int n = s.length();
for (int i = 0; i < n; i++) {
extend(s, i, i);
extend(s, i, i + 1);
}
return res;
}
private void extend(String s, int i, int j) {
if (i < 0 || j >= s.length() || s.charAt(i) != s.charAt(j)) return;
if (j - i + 1 > res.length()) res = s.substring(i, j + 1);
extend(s, i - 1, j + 1);
}
解法二:马拉车算法
马拉车算法是解决最长回文子串的最优解,可以在线性时间复杂度内求解。上述的暴力算法有两个问题,一个是要分别讨论奇偶情况,一个是没有充分利用回文的特性。
马拉车算法在每个字符左右都插入一个不常用字符(例如'#',aaa -> #a#a#a#),这样就只有长度为奇数的情况了,因为任意两个连续的字符都不相等。
另外,还需要维护一个目前回文到达的right_most位置,如果当前index在其范围内,可以使用前面计算的结果减少遍历。
时间复杂度:O(n)
public String longestPalindrome(String s) {
StringBuffer res = new StringBuffer();
StringBuffer sb = new StringBuffer();
sb.append("#");
for (int i = 0; i < s.length(); i++) {
sb.append(s.charAt(i)).append("#");
}
int n = sb.length();
int[] dp = new int[n];
dp[0] = 1;
int right_most = 0;
int mid = 0;
for (int i = 1; i < n; i++) {
int len = right_most >= i ? Math.min(right_most - i + 1, dp[mid * 2 - i]) : 1;
while (i - len >= 0 && i + len <= n - 1 && sb.charAt(i - len) == sb.charAt(i + len)) len += 1;
if (i + len - 1 > right_most) {
right_most = i + len - 1;
mid = i;
}
dp[i] = len;
}
int max_len = dp[0];
for (int i = 0; i < n; i++) {
if (dp[i] > max_len) {
max_len = dp[i];
mid = i;
}
}
for (int i = mid - max_len + 1; i <= mid + max_len - 1; i++) {
char c = sb.charAt(i);
if (c == '#') continue;
res.append(c);
}
return res.toString();
}

浙公网安备 33010602011771号