题目选自力扣当中的一道中等难度题
题目描述:
给定一个字符串s,求其中s的子字符串中最长的回文字符串
例如ababac求出为ababa
注:一个字符串的反序与原字符串相等称作回文字符串
题目很简洁,但是到动手的时候就不知道从哪里下手了. 我们先一步步分析
1.字符串怎么去遍历所有的子字符串?
2.字符串怎么去判断是回文字符串?
3.怎么去记录一个字符串被判断不行?
如果我们知道这些问题答案,那就可以去想想,整体的框架是怎么样的?
针对这些问题,我们进行回答
1.遍历所有的子字符串,首先我们要知道是从s中的哪个位置开始找
可以用一个起始索引,和一个子字符串的长度去起手.两层循环就可以遍历每一个子字符串了
那么问题来了,怎么去用起始索引和字符串差长度?答案当然是字符数组啦.通过tochararray的方法去实现
将原字符串的所有字符装进数组中通过索引去获取它们/
2.第一问中我们用数组去对字符串操作,那么判断回文数我们可以通过起始索引指向的元素和右边界的元素进行对比.右边界的索引=起始索引+长度-1;而如何去边界移动又是个问题,而在之前讲到了我们会用数组遍历所有的子字符串,当我们遍历过程将所有长度为二的字符串判断完成后,再去判断长度为四的(长度为三和二一样) 先是判断边界是否为回文字符串,再去判断内部相邻的两个字符,!!!相邻???,这不就是长度为二的子字符串吗? 将之前的结果直接拿去用就好
将到这是不是有点要递归的意思了
3.上面我们讲直接用,怎么用?可以用一个二维数组去记录一个子字符串是否是回文字符串. 其中数组两个索引为字符串的起始索引和结束索引,而怎么去继承判断过的就可以用动态规划的方法实现了
状态转移方程为dp[i][j]=dp[i+1][j-1]
接下来我们代码实现
public class text4 {
public static void main(String[] args) {
String s="ababadc";
System.out.println(longestPalindrome(s));
}
//动态规划--最长求子字符串
public static String longestPalindrome(String s) {
int len = s.length();
if (len < 2) {
return s;
}
int maxLen = 1;
int begin = 0;
// dp[i][j ] 表示 s[i..j] 是否是回文串
boolean[][] dp = new boolean[len][len];
// 初始化:所有长度为 1 的子串都是回文串
for (int i = 0; i < len; i++) {
dp[i][i] = true;
}
char[] charArray = s.toCharArray();
// 递推开始
// 先枚举子串长度
for (int L = 2; L <= len; L++) {
// 枚举左边界,左边界的上限设置可以宽松一些
for (int i = 0; i < len; i++) {
// 由 L 和 i 可以确定右边界,即 j - i + 1 = L 得
int j = L + i - 1;
// 如果右边界越界,就可以退出当前循环
if (j >= len) {
break;
}
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];
}
}
// 只要 dp[i][L] == true 成立,就表示子串 s[i..L] 是回文,此时记录回文长度和起始位置
if (dp[i][j] && j - i + 1 > maxLen) {
maxLen = j - i + 1;
begin = i;
}
}
}
return s.substring(begin, begin + maxLen);
}
}