LC.P516[最长回文子序列]

题目描述

给你一个字符串 s ,找出其中最长的回文子序列,并返回该序列的长度。

子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。

示例 1:

输入:s = “bbbab”
输出:4
解释:一个可能的最长回文子序列为 “bbbb” 。

示例 2:

输入:s = “cbbd”
输出:2
解释:一个可能的最长回文子序列为 “bb” 。

提示:

  • 1 <= s.length <= 1000
  • s 仅由小写英文字母组成

方法一:区间DP+记忆化搜索

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {

String s;
int[][] cache;

public int longestPalindromeSubseq(String s) {
this.s = s;
int n = s.length();
cache = new int[n][n];
return dfs(0, n - 1);
}

private int dfs(int i, int j) {
if (i > j) return 0; // 空串
if (i == j) return 1; // 只有一个字母
if (cache[i][j] != 0) return cache[i][j];
if (s.charAt(i) == s.charAt(j)) {
cache[i][j] = dfs(i + 1, j - 1) + 2; // 都选
return cache[i][j];
}
cache[i][j] = Math.max(dfs(i + 1, j), dfs(i, j - 1)); // 枚举哪个不选
return cache[i][j];
}
}
  • 时间复杂度:$O(n^2)$
  • 空间复杂度:$O(n^2)$

方法二:1:1翻译成递推

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution {
public int longestPalindromeSubseq(String S) {
char[] s = S.toCharArray();
int n = s.length;
int[][] f = new int[n][n];
for (int i = n - 1; i >= 0; --i) {
f[i][i] = 1;
for (int j = i + 1; j < n; ++j) {
if (s[i] == s[j]) f[i][j] = f[i + 1][j - 1] + 2;
else f[i][j] = Math.max(f[i + 1][j], f[i][j - 1]);
}
}
return f[0][n - 1];
}
}
  • 时间复杂度:$O(n^2)$
  • 空间复杂度:$O(n^2)$