这是我参与8月更文挑战的第12天,活动详情查看:8月更文挑战
516. 最长回文子序列
给你一个字符串 s ,找出其中最长的回文子序列,并返回该序列的长度。
子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。
- 示例 1:
输入:s = "bbbab" 输出:4 解释:一个可能的最长回文子序列为 "bbbb" 。
- 示例 2:
输入:s = "cbbd" 输出:2 解释:一个可能的最长回文子序列为 "bb" 。
提示:
1 <= s.length <= 1000 s 仅由小写英文字母组成
解题思路
对于一个子序列而言,如果它是回文子序列,并且长度大于 2,那么将它首尾的两个字符去除之后,它仍然是个回文子序列。因此可以用动态规划的方法计算给定字符串的最长回文子序列。
数组定义
dp[i][j]表示区间[i,j]内的最长的最长回文子序列长度
初始化
dp[i][i]初始化为1,因为一个字母就是一个长度为1的回文序列
状态转移
dp[i][j]=Math.max(dp[i+1][j],dp[i][j-1],dp[i+1][j-1]+2(如果s[i]==s[j],就可以为回文子序列多加2个元素))
设当前区间长度为n 如果s[i]!=s[j]的话,我们就在dp[i+1][j]和dp[i][j-1]两个长度为n-1的子序列中,选出更长的那个作为dp[i][j]的结果
代码
class Solution {
public int longestPalindromeSubseq(String s) {
int n = s.length(),res=1;
int[][] dp = new int[n][n];
//初始化
for (int i = 0; i < n; i++) {
dp[i][i] = 1;
}
for (int len = 2; len <= n; len++)
for (int i = 0; i + len - 1 < n; i++) {
if (len==2)
{
dp[i][i+1]=s.charAt(i)==s.charAt(i+1)?2:1;
}else {
dp[i][i+len-1]=Math.max(dp[i+1][i+len-1],dp[i][i+len-2]);
if (s.charAt(i)==s.charAt(i+len-1))
dp[i][i+len-1]= Math.max( dp[i][i+len-1],dp[i+1][i+len-2]+2);
}
}
return dp[0][n-1];
}
}