题目描述
Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.
Example 1:
Input: “babad”
Output: “bab”
Note: “aba” is also a valid answer.
Example 2:
Input: “cbbd”
Output: “bb”
方法与实现
方法1
思路:
动态规划 Dynamic Programming 来解,根 Palindrome Partitioning II 的解法很类似,
我们维护一个二维数组 dp,其中 dp[i][j] 表示字符串区间 [i, j] 是否为回文串,
当 i = j 时,说明只有一个字符,肯定是回文串,
当 i - j = 1,说明是相邻字符,此时需要判断 s[i] 是否等于 s[j],
当 i - j >= 2,说明i和j不相邻,即,除了判断 s[i] 和 s[j] 相等之外,还要判断dp[i + 1][j - 1] ,若为真,就是回文串,
通过以上分析,可以写出递推式如下:
实现
class Solution {
public static String longestPalindrome(String s) {
if (s.isEmpty())
return "";
int len_s = s.length();
boolean dp[][] = new boolean[len_s][len_s];
int left = 0, right = 0;
int len = 0;//len记录回文串的最大长度
for (int i = 0; i < len_s; ++i) {
//当 i = j 时,说明只有一个字符,肯定是回文串,
dp[i][i] = true;
for (int j = 0; j < i; ++j) {
//当 i - j < 1,说明是相邻字符,此时需要判断 s[i] 是否等于 s[j]
//因为j<i 所以不存在i-j=0,i-j<2等价于i-j=1
if (i - j < 2)
dp[j][i] = s.charAt(i) == s.charAt(j);
//当 i - j >= 2,说明i和j不相邻,即,除了判断 s[i] 和 s[j] 相等之外,还要判断dp[i + 1][j - 1] ,若为真,就是回文串,
else
dp[j][i] = (s.charAt(i) == s.charAt(j)) && dp[j + 1][i - 1];
//如果是回文串且长度大于len,则更新len
if (dp[j][i] && len < i - j + 1) {
len = i - j + 1;//回文串长度
left = j;//回文串左边界
right = i;//回文串右边界
}
}
}
return s.substring(left, right + 1);
}
}
方法2
思路:
以每一个字符为中心,像两边扩散来寻找回文串。
注意奇偶情况,由于回文串的长度可奇可偶,比如 “bob” 是奇数形式的回文,“noon” 就是偶数形式的回文,两种形式的回文都要搜索,对于奇数形式的,我们就从遍历到的位置为中心,向两边进行扩散,对于偶数情况,我们就把当前位置和下一个位置当作偶数行回文的最中间两个字符,然后向两边进行搜索。
实现
class Solution {
private int start, maxLen;
public String longestPalindrome(String s) {
int len=s.length();
if(len<2)//长度为0或者1 肯定是回文序列
return s;
for (int i = 0; i < len-1; ++i){
extendPalindrome(s, i, i); //假设是基数长度
extendPalindrome(s, i, i+1); //假设是偶数长度
}
return s.substring(start,start+maxLen);
}
private void extendPalindrome(String s, int j, int k) {
while(j >= 0 && k<s.length()&& s.charAt(j)==s.charAt(k)){
j--;//起始位置向前
k++;//终止位置向后
}
if(maxLen<k-j+1-2){
//jxxxk j与k中间的为回文序列
start=j+1;//更新起始位置
maxLen=k-j+1-2;//更新长度
}
}
}