掘金团队号上线,助你 Offer 临门! 点击查看详情
一、题目描述:
给你一个字符串 s,找到 s 中最长的回文子串。
二、思路分析:
首先,理解什么是回文串,回文串指的是一个字符串从头到尾和从尾到头是一致的。
(1)如果使用暴力解法,我们很容易使用两层循环的方式枚举出所有子串,再对这些子串的长度和是否是回文串进行判断,在对一个子串进行是否是回文的判断也是一个循环的过程,故整个的时间复杂度就成为了O(n^3).
(2)对于给定的一个字符串S,,则如果S是个回文字符串,那么如果在其头尾各加一个相同的字母,那么这个大字符串S'也是一个回文字符串,反之,如果S'是个回文串,那么两边各去掉一个字母,它的子串依然是回文字符串。如此,我们要求一个字符串的最大回文子串,可以先求出最大子串的最大长度的回文串,一个大的问题我们可以分解成N个重复的相同子问题,使用动态规划的方式:可得出状态转移方程为:
f(i,j) = f(i+1,j-1) && S[i]==S[j];
(其中函数f(i,j)表示字符串从下标i处到j处的子串是否为回文子串)
考虑到边界条件:如果子符串长度为1,则必定是回文字符串,如果子字符串长度为2,且两个字母相等,他也是回文字符串。
另外因为需要从最小的子串依次长度递增的方式寻找最终字符串的方式,故第一层循环是以子串长度为元素,第二层循环是以i和j为迭代元素,也就是子串的首尾下标,总的时间复杂度为O(n^2),空间复杂度为O(n^2)
二、AC代码:
public String longestPalindrome(String s) {
int n = s.length();
boolean[][] dp = new boolean[n][n]();
//返回的结果字符串
String result = "";
//子字符串长度
int length = 1;
//从最小长度开始,自底往上求出dp表的结果
for(;length <= n;length++){
for(int i = 0,int i+length-1 < n;i++){
int j = i+length-1;
if(length==1){
dp[i][j] = true;
}else if(length == 2 && s.charAt(i)==s.charAt(j)){
dp[i][j] = true;
}else{
dp[i][j] = (s.charAt(i)==s.charAt(j)) && dp[i+1][j-1];
}
//求该长度范围内的最大子串
if(dp[i][j] && length>result.length()){
result = s.subString(i,j+1);
}
}
}
return result;
}
四、总结
在问题可以归结为很多重复小问题的时候,或者说每个小问题的状态结果可以推导出大问题的状态结果的时候,可以考虑使用动态规划,或者递归。