题目要求

Given a string s, find the longest palindromic subsequence's length in s. You may assume that the maximum length of s is 1000.

Example 1:
Input:
"bbbab"
Output:
4
One possible longest palindromic subsequence is "bbbb".

Example 2:
Input:
"cbbd"
Output:
2
One possible longest palindromic subsequence is "bb".

现有一个字符串s,要求找出最长的回文子序列的长度。这里要注意,子序列和子字符串不同,允许序列中的元素不是连续的。

思路和代码

这是一道典型的动态规划的题目,假设我们已经知道数组中任意长度为i的子字符串的最长回文子序列长度,则可以推导出长度为i+1的子字符串的最长回文子序列长度。推导过程如下:

首先假设tmp[j-i][j]记录了[j-i,j]子字符串中的最长回文子序列长度,则对于[j-i-1, j]我们可知一定会有两种情况

  1. s[j-i-1]==s[j] 则最大的子序列长度等于tmp[j-i][j-1]+2,即等于[j-i,j-1]这个子字符串中的最大子序列长度加上2
  2. s[j-i-1]!=s[j],则最大的子序列长度等于Math.max(tmp[j-i][j], tmp[j-i-1][j-1]),即等于[j-i,j][j-i-1,j-1]两个子字符串中能够找出来的最大子序列长度。

代码如下:

    public int longestPalindromeSubseq(String s) {
        int[][] tmp = new int[s.length()][s.length()];
        for(int i = 0 ; i<s.length() ; i++) {
            for(int j = 0 ; j+i<s.length() ; j++) {
                if (i==0) {
                    tmp[j][j+i] = 1;
                }else if (s.charAt(j) == s.charAt(j+i)) {
                    if (i==1) {
                        tmp[j][j+i]  = 2;
                    } else {
                        tmp[j][j+i]  = 2 + tmp[j+1][j+i-1];
                    }
                }else {
                    tmp[j][j+i] = Math.max(tmp[j][j+i-1], tmp[j+1][j+i]);
                }
            }
        }
        return tmp[0][s.length()-1];
    }

一个空间复杂度的优化在于,我们只用一个一维数组存储以下标i为结尾的任意长度的子字符串的最长子序列,其中dp[j]存储的是[j,i]子字符串的最长子序列。那么,当计算下标为i+1结尾的任意长度的子字符串的最长子序列时,同样可以推导出来。

    public int longestPalindromeSubseq2(String s) {
        char[] str = s.toCharArray();
        //dp[j]表示以j为开头的的[j~i]的最长回数子序列长度,当i=s.length-1时,则dp中存储了所有以j为开始最远到i的最长回数子序列长度
        int[] dp = new int[str.length];
        int max = 0;

        for (int i=0; i<dp.length; i++) {
            dp[i] = 1;

            int maxSoFar = 0;
            for (int j=i-1; j>=0; j--) {
                int prev = dp[j];
                if (str[i] == str[j]) {
                    dp[j] = maxSoFar + 2;
                }
                maxSoFar = Math.max(prev, maxSoFar);
            }
        }

        for (int i : dp){
            max = Math.max(max, i);
        }
        return max;
    }

raledong
2.7k 声望2k 粉丝

心怀远方,负重前行