LeetCode——最长回文子序列

Q:给定一个字符串s,找到其中最长的回文子序列。可以假设s的最大长度为1000。

示例 1:
输入:
"bbbab"
输出:
4
一个可能的最长回文子序列为 "bbbb"。

示例 2:
输入:
"cbbd"
输出:
2
一个可能的最长回文子序列为 "bb"。

A:
引用自:《labuladong的算法小抄》
取决于 s[i] 和 s[j] 的字符:
如果它俩相等,那么它俩加上 s[i+1..j-1] 中的最⻓回⽂⼦序列就是s[i..j] 的最⻓回⽂⼦序列:

如果它俩不相等,说明它俩不可能同时出现在 s[i..j] 的最⻓回⽂⼦序列中,那么把它俩分别加⼊ s[i+1..j-1] 中,看看哪个⼦串产⽣的回⽂⼦序列更⻓即可:

if (s[i] == s[j])
// 它俩⼀定在最⻓回⽂⼦序列中
dp[i][j] = dp[i + 1][j - 1] + 2;
else
// s[i+1..j] 和 s[i..j-1] 谁的回⽂⼦序列更⻓?
dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);

⾸先明确⼀下 base case,如果只有⼀个字符,显然最⻓回⽂⼦序列⻓度是1,也就是 dp[i][j] = 1 (i == j) 。
因为 i 肯定⼩于等于 j ,所以对于那些 i > j 的位置,根本不存在什么⼦序列,应该初始化为 0。另外,看看刚才写的状态转移⽅程,想求 dp[i][j] 需要知道 dp[i+1][j-1] , dp[i+1][j] , dp[i][j-1] 这三个位置;再看看我们确定的 basecase,填⼊ dp 数组之后是这样:

为了保证每次计算 dp[i][j] ,左下右⽅向的位置已经被计算出来,只能斜着遍历或者反着遍历

选择反着遍历:

    public static int longestPalindromeSubseq(String s) {
        int size = s.length();
        if (size == 0)
            return 0;
        int[][] dp = new int[size][size];
        for (int i = 0; i < size; i++) {
            dp[i][i] = 1;
        }
        //反着遍历
        for (int i = size - 2; i >= 0; i--) {
            for (int j = i + 1; j < size; 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]);
            }
        }
        return dp[0][size - 1];
    }
posted @ 2020-03-27 22:14  Shaw_喆宇  阅读(498)  评论(0编辑  收藏  举报