版权声明:转载请标明出处「OneDeveloper」 https://blog.csdn.net/OneDeveloper/article/details/83540207
这一题可以参考:647. 回文子串
本质上是一样的,要判断出所有的回文字串,然后找到其中最长的那一个。
中心扩展法
中心扩展就是把给定的字符串的每一个字母当做中心,向两边扩展,这样来找最长的子回文串。算法复杂度为O(N^2)
public String longestPalindrome(String s) {
if (s == null || s.length() < 1) return "";
char[] strs = s.toCharArray();
int len = strs.length;
int[] arr1 = new int[2];
int[] arr2 = new int[2];
//记录起点与终点的位置
int start = 0, end = 0;
for (int i = 0; i < len; i++) {
//以 s(i) 为中心向两边扩散,得到最长的回文子串
get(arr1, strs, i - 1, i + 1);
//以 s(i) 与 s(i+1) 为中心向两边扩散,得到最长的回文子串
get(arr2, strs, i, i + 1);
int tmpStart, tmpEnd;
if (arr1[1] - arr1[0] > arr2[1] - arr2[0]) {
tmpStart = arr1[0];
tmpEnd = arr1[1];
} else {
tmpStart = arr2[0];
tmpEnd = arr2[1];
}
if ((tmpEnd - tmpStart) > (end - start)) {
start = tmpStart;
end = tmpEnd;
}
}
return s.substring(start, end + 1);
}
public void get(int[] arr, char[] strs, int left, int right) {
while (left >= 0 && right < strs.length && strs[left] == strs[right]) {
--left;
++right;
}
++left;
--right;
arr[0] = left;
arr[1] = right;
}
基于动态规划
public String longestPalindrome(String s) {
if (s == null || s.length() < 1) return "";
int len = s.length();
boolean dp[][] = new boolean[len][len];
char[] strs = s.toCharArray();
int start = 0, end = 0;
// 判断 dp[i][i+1] 是不是回文
for (int i = 0; i < len -1 ; i++) {
if(strs[i] == strs[i + 1]) {
dp[i][i + 1] = true;
start = i;
end = i + 1;
}
// dp[i][i] 即单个字母肯定是回文
dp[i][i] = true;
}
//因为上面的循环无法设置最后一个字母,所以要在这里设置
dp[len - 1][len - 1] = true;
// 按照 dp[i][j] = (dp[i + 1][j - 1] && (strs[i] == strs[j]))
// 的转移方程来判断 dp[i][j] 是不是回文
// 如果是的话还要与原有最长的比较是不是更长且记录
for (int i = len - 3; i >= 0; i--) {
for (int j = i+2; j < len; j++) {
dp[i][j] = (dp[i + 1][j - 1] && (strs[i] == strs[j]));
if (dp[i][j]) {
if (j - i > end - start) {
start = i;
end = j;
}
}
}
}
return s.substring(start, end + 1);
}
dp[i][j]
表示 s 的子串 s[i,j]
是不是回文。
需要注意的就是第二个循环遍历的顺序如下图所示(折线表示计算的顺序
):