题目链接:力扣516-最长回文子序列
前情提要:
因为本人最近都来刷dp类的题目所以该题就默认用dp方法来做。
dp五部曲。
1.确定dp数组和i下标的含义。
2.确定递推公式。
3.dp初始化。
4.确定dp的遍历顺序。
5.如果没有ac打印dp数组 利于debug。
每一个dp题目如果都用这五步分析清楚,那么这道题就能解出来了。
题目思路:
如果你做过力扣647-回文子串或者看过我的那篇题解,那么做本题你会轻松不少。
本题题目要求找出s的最长回文子序列的长度。
注意这里的子序列可以不用连续。
话不多说直接开始我们的dp五部曲。
1.确定dp数组和i下标的含义。
该题的dp数组定义与力扣647相似,都要考虑回文串的性质。
所以dp[i] [j]定义的就是[i,j]范围内的最长回文子序列的长度。
2.确定递推公式。
在判断回文子串的题目中,关键逻辑就是看s[i]与s[j]是否相同。
如果s[i]与s[j]相同,那么dp[i] [j] = dp[i + 1] [j - 1] + 2;
如果不同,我们就要删除其中一个元素来看加上另外一个元素是否可以增加我们回文子序列的长度。
也就是说。如果s[i]与s[j]不相同,说明s[i]和s[j]的同时加入 并不能增加[i,j]区间回文子序列的长度,那么分别加入s[i]、s[j]看看哪一个可以组成最长的回文子序列。
那我们要删除哪个元素呢,不是由我们决定,主要由递推公式决定。
dp[i] [j] = Math.max(dp[i - 1] [j],dp[i] [j - 1]);
3.dp初始化。
由递推公式可以看出dp[i] [j]是由dp[i + 1] [j - 1]推出。
注意这里的j一定是比i要大于等于的。所以他们递推的起点其实就是i = j的时候。
重点就在于i == j的时候,当i == j时就说明这一个元素的最长回文子序列就为他本身 那么 dp[i] [j] = 1;
4.确定dp的遍历顺序。
由递推公式可以看出dp[i] [j]是由dp[i + 1] [j - 1]推出。
在二维dp数组可以看出是由它的左下方推出,所以需要从下到上,从左到右遍历。
所以遍历顺序为:
for(int i = s.length() - 1;i >= 0;i --){
for(int j = i + 1;j < s.length();j ++){
if(s.charAt(i) == s.charAt(j)){
dp[i][j] = dp[i + 1][j - 1] + 2;
}else{
dp[i][j] = Math.max(dp[i + 1][j],dp[i][j - 1]);
}
}
}
5.如果没有ac打印dp数组 利于debug。
class Solution {
public int longestPalindromeSubseq(String s) {
//dp的定义 在i到j的范围内的最长回文子序列的长度
int [][] dp = new int [s.length() + 1][s.length() + 1];
//递推公式 根据回文串的性质
//如果下标为i和j的元素相同那么在i到j的范围内的最长回文子序列的长度就为i + 1到j - 1的范围内的最长回文子序列的长度 + 2
//如果不相同 那么就可以删除下标i和j的任意一个元素 具体选择哪个 肯定要选择删除后获得更长的回文子序列
//初始化
//其实也可以由递推公式可以看出,每次都是由dp[i + 1][j - 1]推出。
//重点就在于i == j的时候,当i == j时就说明这一个元素的最长回文子序列就为他本身 那么 dp[i][j] = 1;
for(int i = 0;i < s.length();i ++){
//在这里dp[i][i] 其实就是j = i的情况
dp[i][i] = 1;
}
//遍历顺序 该题的递推是由dp[i + 1][j - 1]推出。
//在二维dp数组中就是由它的左下方推出来,所以就要从下到上从左到右遍历
for(int i = s.length() - 1;i >= 0;i --){
for(int j = i + 1;j < s.length();j ++){
if(s.charAt(i) == s.charAt(j)){
dp[i][j] = dp[i + 1][j - 1] + 2;
}else{
dp[i][j] = Math.max(dp[i + 1][j],dp[i][j - 1]);
}
}
}
//根据dp数组的定义 最后收集结果的地方就在于在0到s.length() - 1的范围内的最长回文子序列的长度 也就是整个字符串的最长回文子序列的长度
return dp[0][s.length() - 1];
}
}
这一篇博客就到这了,如果你有什么疑问和想法可以打在评论区,或者私信我。
我很乐意为你解答。那么我们下篇再见!