- 最长回文子串
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: “babad”
输出: “bab”
注意: “aba” 也是一个有效答案。
示例 2:
输入: “cbbd”
输出: “bb”、
第一:暴力解法:看代码注释很容易理解
时间复杂度:因为主程序有2个for循环,掉用的函数还有一次n循环,总的时间复杂度是N的3方
class Solution {
/**
* 暴力解法:这个函数是判断当前传进来的子串是不是回文子串,就是从两边向中间依次判断
* @param charArray:当前字符串数组
* @param left:左边界
* @param right:右边界
* @return 当前边界条件下是否是回文子串
*/
public boolean validSym(char[] charArray, int left, int right){
while(left < right){
if (charArray[left] != charArray[right]) {
return false;
}
left++;
right--;
}
return true;
}
/**
*暴力解法:从第一个自负开始,依次向后判断当前的范围是不是回文子串,调用上面的函数
* @param s : 字符串
* @return: 返回最长的回文子串
*/
public String longestPalindrome(String s) {
char[] charArray = s.toCharArray();
int char_len = charArray.length;
if (char_len < 2) return s;
int max_len = 1;
int begin = 0;
for (int i = 0; i < char_len-1; i++) {
for (int j = i+1; j < char_len; j++) {
if (j-i+1>max_len && this.validSym(charArray, i, j )){
max_len = j-i+1;
begin = i;
}
}
}
return s.substring(begin, begin + max_len); // 注意这个子串函数是左闭右开,右边取不到
}
}
第二种方法:中心开花方法,从中心向两边扩散,分别寻找当前下标的最长回文子串
分为两种情况,有可能是偶数串,也有可能是奇数串
/**
* 从当前给定的左右两个下标开始,从中心向两边扩散,l 和 r可能相等活不相等
* @param charArray:原字符数组
* @param left:中心点下标
* @param right|:中心点下表
* @return 返回满足要求的左右边界下标
*/
public int[] expendFromCenter(char[] charArray, int left, int right){
int char_len = charArray.length;
while (left>=0 && right < char_len && charArray[left] == charArray[right]){
left--;
right++;
}
int[] a = new int[2];
a[0] = left + 1;
a[1] = right - 1;
return a;
}
/**
* 对于·每一个下标,分别求一下当前下标情况下的奇数回文子串 和 偶数回文淄川的长度分别是多少
* @param s:字符串
* @return 返回所有下标的最长回文子串
*/
public String longestPalindrome(String s){
char[] charArray= s.toCharArray();
int char_len = charArray.length;
if (char_len < 2) return s;
int max_len = 1;
int begin = 0;
for (int i = 0; i < char_len; i++) {
int[] oddCenter = this.expendFromCenter(charArray, i, i); // 把当前中心点作为奇数中心
int[] evenCenter = this.expendFromCenter(charArray, i, i+1); // 把当前中心点作为偶数中心
if (oddCenter[1]-oddCenter[0]+1 > max_len && oddCenter[1]-oddCenter[0]+1 > evenCenter[1]-evenCenter[0]+1){
begin = oddCenter[0];
max_len = oddCenter[1] - oddCenter[0] + 1;
}else if (evenCenter[1]-evenCenter[0]+1 > max_len && evenCenter[1]-evenCenter[0]+1 > oddCenter[1]-oddCenter[0]+1){
begin = evenCenter[0];
max_len = evenCenter[1] - evenCenter[0] + 1;
}
}
return s.substring(begin, begin + max_len);
}
方法三:动态规划的解法:
dp数组保存ij是否是回文子串的boolean值
长度小于2,化简之后就是坐标关系的小于3
class Solution {
public String longestPalindrome(String s){
char[] charArray = s.toCharArray();
int char_len = charArray.length;
if (char_len < 2) return s;
int max_lem = 1;
int begin = 0;
boolean[][] dp = new boolean[char_len][char_len]; // 初始化dp数组
for (int i = 0; i < char_len; i++) {
dp[i][i] = true;
}
// 构建dp数组:按照每一列构建
for (int j = 0; j < char_len; j++) { // 列在这里面是后移动项
for (int i = 0; i < j; i++) { // 行这里面是先移动项
if (charArray[i] != charArray[j]) {
dp[i][j] = false;
}else if (j - i < 3) {
dp[i][j] = true;
}else {
dp[i][j] = dp[i+1][j-1];
}
if (dp[i][j] == true && j - i + 1 > max_lem) {
max_lem = j - i + 1;
begin = i;
}
}
}
return s.substring(begin, begin + max_lem);
}
}