题目:给一个字符串s,找出其中最长的回文子串。
提示:s仅由数字和英文字母组成
1 <= s.length <= 1000
示例:
输入:s="babad"
输出:"bab"
解释:"aba"同样是符合题意的答案
首先要清楚什么是回文串。回文串是一个正读和反读都一样的字符串,比如“level”或者“noon”等等都是回文串。那我们可以想一下,在一个回文串的两端分别加上一个相同的字符得到的是不是依然是回文串呢?答案是肯定的。由此,我们可以利用这一点,来完成这道题目。
假设有这样一个长度为length的字符串s。
如果它有从下标为i的位置到下标为j位置的子串,那么这个子串是否为回文子串就取决于:
- 下标i位置的字符和j位置的字符相同,并且i == j,则一定为回文子串
- 下标i位置的字符和j位置的字符相同,并且j - i == 1(也就是i和j相邻),则一定为回文子串
- 下标i位置的字符和j位置的字符相同,并且j - i == 2(也就是i和j之间仅隔一个字符),则一定为回文子串
- 下标i位置的字符和j位置的字符相同,并且j - i > 2,则是否为回文子串取决于i+1位置到j-1位置字符串是否为回文子串
有了基本的思路,我们可以用一个二维数组来解决这个问题。
定义一个二维数组boolean[][] dp = new boolean[length][length]. dp[i][j]表示从i下标到j下标到子串是否为回文串。因为i一定小于j,那么可能存在的位置为图中的灰色部分。
如果i到j是回文串,则将dp[i][j]赋值为true,否则为false。
将上面的思想用代码实现:
public static String longestPalindrome(String s){
if (s == null || s.length() <= 1){
return s;
}
int length = s.length();
boolean[][] dp = new boolean[length][length];
int maxLength = 1;
int start = 0;
for (int j = 0;j < length;j ++){
for (int i = 0;i <= j;i ++){
if (s.charAt(i) == s.charAt(j)){
if (j - i < 3){
dp[i][j] = true;
} else {
dp[i][j] = dp[i+1][j-1];
}
} else {
dp[i][j] = false;
}
if (dp[i][j] && maxLength < (j-i+1)){
maxLength = j-i+1;
start = i;
}
}
}
return s.substring(start,start+maxLength);
}