力扣周末回顾题6
题目出处:点击此处
考点:动态规划,字符串,回文,中心扩散法(本博文不涉及)
回顾:
动态规划五要素:
1.判断状态是否转移(是否能用dp数组表示?)
2.状态转移方程表示(dp数组的判断,相当于分类讨论)
3.初始化(考虑边界)
4.输出(验证结果)
5.压缩,优化。
题解:
1.找到最长的回文子串
(注意三个个限定:最长,回文,子串)
考虑到肯定设计到穷举+剪枝,必定可以用状态转移。
————————————————————————————————
2.状态DP【i】【j】代表字符串以i开头,j结尾的字符串是否是回文。
那么如何判定一个字符串是回文呢?
如果 i == j ,并且dp【i+1】【j-1】也是回文则说明DP【i】【j】就是回文。
(这个条件要发现真的不简单,发现不了的读者要多归纳总结)
—————————————————————————————————
特殊边界情况:
我们可以知道,当满足 i == j 之后,有些值是不需要判断【i-1】【j-1】,直接可以知道是回文的,条件即:
j - i < 3;
相当于字符串只有一个或两个字符。
—————————————————————————————————
3.初始化
全部置为false,没啥好说的。
————————————————————————————————
4.输出
这里要注意了,我们这次要得不是DP【length-1】【length-1】,而是记录
在过程中最大长度,并记录起始的字符位置。
这里是未经优化的版本:
时间复杂度O(n2),空间复杂度O(n2);
执行用时:136 ms。
class Solution {
public String longestPalindrome(String s) {
char[] characterlist = s.toCharArray();
int length = characterlist.length;
// 特殊情况
if(length == 0){
return "";
}
boolean[][] dptable = new boolean[length][length];
// 初始化
for(int i = 0;i<length;i++){
for(int j = 0; j<length;j++){
dptable[i][j] = false;
}
}
int maxlen = 0;
int maxstart = 0;
// 一列一列进行dp计算
for(int j = 0; j< length; j++){
for(int i = 0; i<length; i++){
// 行不能大于列
if(i > j){
break;
}
// 左右相等
if(characterlist[i] == characterlist[j]){
// 边界条件,无条件置为正确;
if( j - i < 3){
dptable[i][j] = true;
// 记录最长的字符串
if(j-i+1 > maxlen){
maxlen = j - i + 1;
maxstart = i;
}
continue;
}
// 内部也是回文
if(dptable[i+1][j-1] == true){
dptable[i][j] = true;
// 记录最长的字符串
if(j-i+1 > maxlen){
maxlen = j - i + 1;
maxstart = i;
}
continue;
}
}
dptable[i][j] = false;
}
}
return s.substring(maxstart,maxstart+maxlen);
}
}
5.压缩,优化。
经过打表,我们可以发现,从始至终这个dp表都是只有一列在依照上一列进
行更新。于是我们可以压缩为一列。
优化后:
时间复杂度O(n2),空间复杂度O(n);
执行用时:37ms。
class Solution {
public String longestPalindrome(String s) {
char[] characterlist = s.toCharArray();
int length = characterlist.length;
// 特殊情况
if(length == 0){
return "";
}
boolean[] dptable = new boolean[length];
// 初始化
for(int i = 0;i<length;i++){
dptable[i] = false;
}
int maxlen = 0;
int maxstart = 0;
// 一列一列进行dp计算
for(int j = 0; j< length; j++){
for(int i = 0; i<length; i++){
// 行不能大于列
if(i > j){
break;
}
// 左右相等
if(characterlist[i] == characterlist[j]){
// 边界条件,无条件置为正确;
if( j - i < 3){
dptable[i] = true;
// 记录最长的字符串
if(j-i+1 > maxlen){
maxlen = j - i + 1;
maxstart = i;
}
continue;
}
// 内部也是回文
if(dptable[i+1] == true){
dptable[i] = true;
// 记录最长的字符串
if(j-i+1 > maxlen){
maxlen = j - i + 1;
maxstart = i;
}
continue;
}
}
dptable[i] = false;
}
}
return s.substring(maxstart,maxstart+maxlen);
}
}