516. 最长回文子序列

159 阅读2分钟

这是我参与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];
    }
}