前言
力扣第5题 最长回文子串动态规划的解题思路
一、初学者的动态规划理解
以下为我根据本体所理解的动态规划思路,仅供参考。
目的是找回文字符串,以回文字符串特点入手,例如回文s=“cabbac”;
s[0]==s[5],s[1]==s[4],s[2]==s[3]
如果最外两个字符相等s[0]==s[5],则判断内一层的字符是否相等s[1]==s[4],直到最内的两个数相等位置,都为真,则此字符串为回文字符串
但如果每次循环都进行 判断,那字符过长会增加消耗,所以采用动态规划的方式,例如最里层的两个字符为回文字符串就把结果记录为真,外层判断是否为回文字符串时直接调用此前的结果,以达到节省时间的效果。
二、代码解析
1.创建bool二维数组
创建一个二维bool类型数组dp[i][j],代表字符串的起点和终点,例如s="cabbac",dp[1][2]则代表判断"ab"是否为回文字符串的结果
boolean dp[][] = new boolean[s.length()][s.length()];
2.初始化二维数组
因为只需要按顺序判断所选择的字符串是否为回我字符串,所以不是整个二维数组都会用到,例如
dp[2][1]是判断"ab"从b到a是否是回文字符串,没必要用到。所以创建的二维数组实际上只会用到一半。但全初始化为真也无所谓。
for (int i = 0; i < s.length(); i++) {
Arrays.fill(dp[i],true);
}
3.核心思路
初始化开始和结尾的节点
int start = 0;
int end = 0;
从最外层向里判断,判断的条件是(此层的值是否满足回文字符串条件)&&(里层的判断结果)
结果为真,则记录end和start
for (int i = s.length() - 1; i >= 0; i--) {
for (int j = i + 1; j < s.length(); j++) {
dp[i][j] = (s.charAt(i) == s.charAt(j)) && ((dp[i + 1][j - 1])||(i+1)>(j-1));
if (dp[i][j] == true && (j - i) > (end - start)) {
end = j;
start = i;
}
}
}
最后返回字符串
//substring()是左闭右开的区间,记得尾部+1
return s.substring(start, end+1);
public String longestPalindrome(String s) {
//动态规划法
//创建一个二维bool类型数组dp[i][j](i和j表示字符下标,i要小于j,db[i][j]表示从i到j的字符是否为回文子串)
boolean dp[][] = new boolean[s.length()][s.length()];
int start = 0;
int end = 0;
for (int i = 0; i < s.length(); i++) {
Arrays.fill(dp[i],true);
}
for (int i = s.length() - 1; i >= 0; i--) {
for (int j = i + 1; j < s.length(); j++) {
dp[i][j] = (s.charAt(i) == s.charAt(j)) && ((dp[i + 1][j - 1])||(i+1)>(j-1));
if (dp[i][j] == true && (j - i) > (end - start)) {
end = j;
start = i;
}
}
}
//substring()是左闭右开
return s.substring(start, end+1);
}
public String longestPalindrome(String s) { //动态规划法 //创建一个二维bool类型数组dp[i][j](i和j表示字符下标,i要小于j,db[i][j]表示从i到j的字符是否为回文子串) boolean dp[][] = new boolean[s.length()][s.length()]; int start = 0; int end = 0; for (int i = 0; i < s.length(); i++) { Arrays.fill(dp[i],true); } for (int i = s.length() - 1; i >= 0; i--) { for (int j = i + 1; j < s.length(); j++) { //(i+1)>(j-1)可以删除 dp[i][j] = (s.charAt(i) == s.charAt(j)) && ((dp[i + 1][j - 1])||(i+1)>(j-1)); if (dp[i][j] == true && (j - i) > (end - start)) { end = j; start = i; } } } //substring()是左闭右开 return s.substring(start, end+1); }