给定一个字符串 s
,找到 s
中最长的回文子串。你可以假设 s
的最大长度为 1000。
示例 1:
输入: "babad" 输出: "bab" 注意: "aba" 也是一个有效答案。
示例 2:
输入: "cbbd" 输出: "bb"
分析:
暴力解法:
选出所有子字符串可能的开始和结束位置,并检验它是不是回文。复杂度O(n*n*n)
中心扩展算法:
我们观察到回文中心的两侧互为镜像。因此,回文可以从它的中心展开,并且只有 2n - 12n−1 个这样的中心。你可能会问,为什么会是 2n - 1 个,而不是 n 个中心?原因在于所含字母数为偶数的回文的中心可以处于两字母之间(例如 {“abba”} 的中心在两个 ‘b’ 之间)。时间复杂度O(n*n)
动态规划:
暴力解法计算了很多重复的子问题:例如 “asdfdsa”,暴力解法在计算完 “asdfdsa”是回文串后还会继续计算“sdfds”等子串。我们不妨先记忆化假设dp[i][j]为从S字符串从i到j是否为回文子串。接下来我们可以推导出状态转换方程:
dp[i][j] = dp[i+1][j-1] -- s[i]==s[j]
dp[i][j] = 0 --s[i]!=s[j]
可以写出代码:
import java.util.Scanner;
/**
* @author: Mr.Hu
* @create: 2019-03-01 21:10
*/
public class Main{
public static void main(String[] args) {
Scanner sc =new Scanner(System.in);
while (sc.hasNext()){
System.out.println( longestPalindrome(sc.next()));
}
}
public static String longestPalindrome(String s) {
if (s.length()==0) return "" ; //题目中含有空字符串的可能
int dp[][]=new int[s.length()][s.length()];
int length=1,start=0;
for (int i = 0; i < s.length(); i++) {
dp[i][i]=1;
if (i<s.length()-1 && s.charAt(i)==s.charAt(i+1)) { //别忘了更新start和length
dp[i][i+1]=1;
start=i;
length=2;
}
}
for (int l = 3; l <= s.length(); l++) {
for (int i = 0; i+l-1 < s.length(); i++) {
int j=i+l-1;
if (s.charAt(i)==s.charAt(j)&&dp[i+1][j-1]==1) { //因为i+1 和j-1 所以长度得从3开始。
dp[i][j]=1;
length=l;
start=i;
}
else dp[i][j]=0;
}
}
return s.substring(start,start+length);
}
}