📅  最后修改于: 2023-12-03 15:40:17.051000             🧑  作者: Mango
回文串是一种具有对称性质的字符串,即正反读都一样。最长回文子串就是一个字符串中最长的回文子串。在计算机领域中,字符串的问题是经常遇到的问题之一,最长回文子串也是常见的问题之一。
目前求解最长回文子串的方法较为多样,以下为常见的几种解法:
遍历每个字符,并以其为中心点,向两侧扩展,找到最长回文串。这样的时间复杂度为 $O(n^2)$。
public static int longestPalindrome(String s) {
if (s == null || s.length() == 0) {
return 0;
}
int max = 1;
for (int i = 0; i < s.length() - 1; i++) {
int len1 = expandCenter(s, i, i);
int len2 = expandCenter(s, i, i + 1);
max = Math.max(max, Math.max(len1, len2));
}
return max;
}
public static int expandCenter(String s, int left, int right) {
while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
left--;
right++;
}
return right - left - 1;
}
通过状态转移方程求解,时间复杂度为 $O(n^2)$ 。
public static int longestPalindrome(String s) {
if (s == null || s.length() == 0) {
return 0;
}
int n = s.length();
boolean[][] dp = new boolean[n][n];
int max = 1;
for (int i = 0; i < n; i++) {
dp[i][i] = true;
}
for (int j = 1; j < n; j++) {
for (int i = 0; i < j; i++) {
if (s.charAt(i) == s.charAt(j)) {
if (j - i < 3) {
dp[i][j] = true;
} else {
dp[i][j] = dp[i + 1][j - 1];
}
} else {
dp[i][j] = false;
}
if (dp[i][j]) {
max = Math.max(max, j - i + 1);
}
}
}
return max;
}
时间复杂度为 $O(n)$ 。
public static int longestPalindrome(String s) {
if (s == null || s.length() == 0) {
return 0;
}
char[] newStr = new char[(s.length() << 1) + 1];
int[] p = new int[newStr.length];
int max = 1;
for (int i = 0; i < s.length(); i++) {
newStr[i << 1] = '#';
newStr[(i << 1) + 1] = s.charAt(i);
}
newStr[newStr.length - 1] = '#';
int right = 0, center = 0;
for (int i = 0; i < newStr.length; i++) {
if (i < right) {
p[i] = Math.min(right - i, p[(center << 1) - i]);
} else {
p[i] = 1;
}
while (i >= p[i] && i + p[i] < newStr.length && newStr[i - p[i]] == newStr[i + p[i]]) {
p[i]++;
}
if (i + p[i] > right) {
right = i + p[i];
center = i;
}
max = Math.max(max, p[i]);
}
return max - 1;
}
以上三种方法都能较为高效地解决最长回文子串的问题。中心扩展法是最简单粗暴的方法,动态规划法通过递推求解,Manacher 算法则是从回文子串的对称性入手,优化时间复杂度。根据具体的场景可以选择不同的方法解决问题。