给定一个字符串s,找到s中最长的回文子串。你可以假设s的最大长度为1000.
这题是很经典的题目,找到最长回文子串,回文就是bab,cabac这样的。
题解
解法一
暴力法,列举所有的子串,判断是否为回文串,很明显时间复杂度为O(n^2)。
解法二
将原字符串s倒置s',然后寻找最长回文串就变成寻找字符串s和s'的最长公共子串,需要注意的一点,找到最长公共子串后,还需要判断子串是否是回文。
解法三,动态规划
很多时候关于字符串的判断,需要用到动态规划的思想。
我们判断i到j的子串为回文串时,等价于i+1到j-1时回文串&&Si=Sj。时间复杂度仍为O(n^2),空间复杂度也是。
代码
public String longestPalindrome(String s) {
int length = s.length();
boolean[][] P = new boolean[length][length];
int maxLen = 0;
String maxPal = "";
for (int len = 1; len <= length; len++) //遍历所有的长度
for (int start = 0; start < length; start++) {
int end = start + len - 1;
if (end >= length) //下标已经越界,结束本次循环
break;
P[start][end] = (len == 1 || len == 2 || P[start + 1][end - 1]) && s.charAt(start) == s.charAt(end); //长度为 1 和 2 的单独判断下
if (P[start][end] && len > maxLen) {
maxPal = s.substring(start, end + 1);
}
}
return maxPal;
}
解法四,扩展中心
每次循环选择一个中心,进行左右扩展,判断左右字符是否相等即可。
因为存在奇数和偶数的字符串,所有共有n+n-1个中心.
public String longestPalindrome(String s) {
if (s == null || s.length() < 1) return "";
int start = 0, end = 0;
for (int i = 0; i < s.length(); i++) {
int len1 = expandAroundCenter(s, i, i);
int len2 = expandAroundCenter(s, i, i + 1);
int len = Math.max(len1, len2);
if (len > end - start) {
start = i - (len - 1) / 2;
end = i + len / 2;
}
}
return s.substring(start, end + 1);
}
private int expandAroundCenter(String s, int left, int right) {
int L = left, R = right;
while (L >= 0 && R < s.length() && s.charAt(L) == s.charAt(R)) {
L--;
R++;
}
return R - L - 1;
}
我的解法代码
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class leetcode {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String s = scan.nextLine();
String str = longestPalindrome(s);
System.out.println(str);
}
public static String longestPalindrome(String s) {
int length = s.length();
//p[i][j]代表ij是否是回文串
boolean[][] p = new boolean[length][length];
int maxLen = 0;//记录最长长度
String maxPal = "";//记录最长回文串
for(int len = 1; len <= length; len++) {
for(int start = 0; start < length; start++) {
//len代表回文串长度,start起始位,end终止位
int end = start + len - 1;
if(end >= length) break;
//核心思想的代码,判断是否回文串
p[start][end] = (len == 1 || len == 2 || p[start + 1][end - 1]) && s.charAt(start) == s.charAt(end);
/*
可以理解为
if((len == 1 || len == 2 || p[start + 1][end - 1]) && s.charAt(start) == s.charAt(end))
p[][] = true;
*/
if(p[start][end] && len > maxLen) {
maxPal = s.substring(start, end+1);
maxLen = len;
}
}
}
return maxPal;
}
}