题目:给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为1000。
- 示例 1:
输入: “babad”
输出: “bab”
注意: "aba"也是一个有效答案。 - 示例 2:
输入: “cbbd”
输出: “bb”
思路:可以从头到尾遍历每个字符串,然后从中间向外扩展,判断最大能扩展到的长度。即:例如“babad”这种串,通过遍历,b,a,b,a,d,的顺序,每次遍历到一个字符,将其作为字符串的最中间,向两端扩展,例如当遍历到第一个a时,向两端扩展,bab,判断扩展的两个字符是否相等。还有一种情况就是回文子串长度是偶数。例如示例二中的“bb”,因此,这里再遍历一次,这次的遍历方式跟上面一样,只是中间的变成了两个字符,且要判断两个字符是否相等。代码:
private static String longestPalindrome(String s) {
// 对输入进行判断
if (s == null) {
return null;
}
int left = 0, right = 0;
String oddString = "", evenString = "";
// 如果回文字串为奇数
for (int i = 0; i < s.length(); i++) {
left = i - 1;
right = i + 1;
// 进行左右扩展
while (check(left, right, s)) {
left--;
right++;
}
// 当没有办法扩展时,判断这时的字串长度与原最长奇字串进行比较
if (oddString.length() < (right - i - 1) * 2 + 1) {
oddString = s.substring(left + 1, right);
}
}
// 如果回文字串为偶数
for (int i = 0; i < s.length() - 1; i++) {
// 这里判断最中间的两个元素是否相等
if (!check(i, i + 1, s)) {
continue;
}
left = i - 1;
right = i + 2;
while (check(left, right, s)) {
left--;
right++;
}
if (evenString.length() < (right - i - 1) * 2) {
evenString = s.substring(left + 1, right);
}
}
// 最后判断 长度为奇数的最长字串 跟 长度为偶数的最长字串 两个的大小关系
return oddString.length() > evenString.length()? oddString: evenString;
}
private static boolean check(int i, int j, String s) {
if (i < 0 || j >= s.length()) {
return false;
}
return s.substring(i , i + 1).equals(s.substring(j, j + 1));
}
这个代码是可以通过的,但执行的速度比较慢,下图是在LeetCode中文网上提交的结果:
因此,这里提出一个改进的方案:就是当遍历到第i个节点,要遍历i + 1节点时,先判断以第i + 1节点为中点时,长度为当前最长字串长度的字串,是否是回文字符串,如果是,则继续扩展,不是则遍历下一个节点,代码:
private static String longestPalindrome_(String s) {
if (s == null) {
return null;
}
int left = 0, right = 0;
String oddString = "", evenString = "";
// 如果回文字串为奇数
for (int i = 0; i < s.length(); i++) {
// 先判断以当前节点为中心,能否获得当前已知的最长字串
left = i - oddString.length() / 2;
right = i + oddString.length() / 2;
if (!check_(left, right, s)) {
continue;
}
while (check(left, right, s)) {
left--;
right++;
}
if (oddString.length() < (right - i - 1) * 2 + 1) {
oddString = s.substring(left + 1, right);
}
}
// 如果回文字串为偶数
for (int i = 0; i < s.length() - 1; i++) {
if (!check(i, i + 1, s)) {
continue;
}
left = i - evenString.length() / 2;
right = i + evenString.length() / 2 + 1;
if (!check_(left, right, s)) {
continue;
}
while (check(left, right, s)) {
left--;
right++;
}
if (evenString.length() < (right - i - 1) * 2) {
evenString = s.substring(left + 1, right);
}
}
return oddString.length() > evenString.length()? oddString: evenString;
}
private static boolean check(int i, int j, String s) {
if (i < 0 || j >= s.length()) {
return false;
}
return s.substring(i , i + 1).equals(s.substring(j, j + 1));
}
private static boolean check_(int i, int j, String s) {
if (i < 0 || j >= s.length()) {
return false;
}
StringBuilder sb = new StringBuilder(s.substring(i, j + 1));
String temp = sb.reverse().toString();
return temp.equals(s.substring(i, j + 1));
}
速度提升了很多,但还有很大提升空间,博主暂时没有其他好的改进方案: