516.最长回文子序列
题目描述:
给你一个字符串 $s$ ,找出其中最长的回文子序列,并返回该序列的长度。
子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。
数据范围:
$1\le s.len \le 1000$
题解:
子序列问题有两种思路:
一维dp
类似最长上升子序列。
定义 $dp[i]$ 表示在子数组 $arr[0,\cdots,i]$ 中,以 $arr[i]$ 结尾的目标子序列(就是所求的子序列)的长度。
然后使用二重循环遍历更新。
二维dp
涉及到两个字符串或数组时。
定义 $dp[i,j]$ 表示在子数组 $arr[0,\cdots,i]$ 和 $arr[0, \cdots, j]$ 中,要求的目标子序列的长度。
涉及到一个字符或数组时。
定义 $dp[i,j]$ 表示在子数组 $arr[i,\cdots,j]$ 中,要求的目标子序列的长度。
也可以使用区间 $dp$ ,直接枚举区间,枚举左端点。
二维的一般都是需要判断 $arr[i] == arr[j]$ 的,相等时转移;不相等时取最大值。
一、直接 dp
定义 $dp[i,j]$ 表示在子数组 $s[i,\cdots,j]$ 中,回文子序列的长度。
那么可以得到转移方程
确定枚举顺序,因为 $dp[i][j]$ 需要使用到 $dp[i + 1][j]$ ,需要先得到 $dp[i + 1][j]$ ,因此第一维应该从大到小枚举;因为 $dp[i][j]$ 需要使用到 $dp[i][j - 1]$ ,需要先得到 $dp[i][j-1]$ ,因此第二维需要从前往后枚举。
二、区间 dp
直接使用区间 $dp$ ,递推方程不变,枚举方式改变
类似题目:
需要先求出最长的回文子序列,然后 $n - len$ 就是需要插入的次数。
因为 $dp[i][j]$ 需要从 $dp[i + 1][j], dp[i][j - 1], dp[i + 1][j - 1]$ 转移过来,如图
因此可以得到两种遍历方式,一种是斜着遍历,这就是区间dp的形式。
另一种是第二维倒着,第一维正着,这就是直接dp的形式。
代码:
1 | class Solution { |
区间dp
1 | class Solution { |