LintCode刷题——最长的回文序列(区间DP)
题目描述
描述
给一字符串 s, 找出在 s 中的最长回文子序列的长度. 你可以假设 s 的最大长度为 1000
.
样例
样例1
输入: "bbbab"
输出: 4
解释:
一个可能的最长回文序列为 "bbbb"
样例2
输入: "bbbbb"
输出: 5
标签
优步 亚马逊 动态规划 区间型动态规划
分析
区间DP,与序列型动态规划的思考方式不同,区间DP每次都以区间进行讨论,但也是从小区间到大区间的这种顺序进行,这一点还是和任意类型的动态规划相符,因为动态规划算法的核心思想就是想一步步通过求解子问题的解进而递推出原问题的解的过程,所以仍然要先计算小区间,再计算大区间。
这里我们要注意的点:对长度为0的区间和长度为1的区间要特殊处理一下,不然后面就会有些许麻烦或不必要的问题
AC代码
1 public class Solution { 2 /** 3 * @param s: the maximum length of s is 1000 4 * @return: the longest palindromic subsequence's length 5 */ 6 public int longestPalindromeSubseq(String s) { 7 // write your code here 8 if (s == null || s.length() == 0) { 9 return 0; 10 } 11 char[] c = s.toCharArray(); 12 int n = c.length; 13 14 // 定义状态:f[i][j] 表示区间(i,j)的最长回文子序列长度 15 // 区间型动态规划,不用开n + 1 16 int[][] f = new int[n][n]; 17 18 /* 19 区间型动态规划的注意点:要从考虑区间开始,而且是从小区间到大区间 20 */ 21 // 初始化 22 // 特殊处理区间0,即本身 23 for (int i = 0; i < n; i++) { 24 f[i][i] = 1; 25 } 26 27 // 特殊处理区间1 28 for (int i = 0; i < n - 1; i++) { 29 if (c[i] == c[i + 1]) { 30 f[i][i + 1] = 2; 31 } else { 32 f[i][i + 1] = 1; 33 } 34 } 35 36 // 转移方程 37 // 分区间,从区间为2开始,注意:区间最大为n - 1 38 for (int len = 2; len < n; len++) { 39 // 定住左边界 40 for (int i = 0; i + len <= n - 1; i++) { 41 // 右边界 42 int j = i + len; 43 if (c[i] == c[j]) { 44 // 这里很容易犯错误,是+2,而不是像最长公共子序列一样+1 45 f[i][j] = f[i + 1][j - 1] + 2; 46 } else { 47 f[i][j] = Math.max(f[i + 1][j], f[i][j - 1]); 48 } 49 } 50 } 51 52 // 返回结果 53 return f[0][n - 1]; 54 } 55 }
LintCode链接:https://www.lintcode.com/problem/667/