题目描述
给定一个字符串 s,返回 s 中不同的非空「回文子序列」个数 。
通过从 s 中删除 0 个或多个字符来获得子序列。
如果一个字符序列与它反转后的字符序列一致,那么它是「回文字符序列」。
如果有某个 i
, 满足 ai != bi
,则两个序列 a1, a2, ...
和 b1, b2, ...
不同。
注意:
- 结果可能很大,你需要对
10^9 + 7
取模 。
示例 1:
输入:s = 'bccb'
输出:6
解释:6 个不同的非空回文子字符序列分别为:'b', 'c', 'bb', 'cc', 'bcb', 'bccb'。
注意:'bcb' 虽然出现两次但仅计数一次。
示例 2:
输入:s = 'abcdabcdabcdabcdabcdabcdabcdabcddcbadcbadcbadcbadcbadcbadcbadcba'
输出:104860361
解释:共有 3104860382 个不同的非空回文子序列,104860361 对 109 + 7 取模后的值。
提示:
1 <= s.length <= 1000
s[i]
仅包含'a'
,'b'
,'c'
或'd'
我猜测是要根据最大的回文串推算出有多少个小回文串,而不是一个一个地计数,毕竟示例二的数量就已经超过了int的上限231-1,所以基本排除暴力法。
果然,官方用了dp,我看不懂,应该说我对解析就不理解了,奉上代码。
class Solution {
private final int MOD = 1000000007;
public int countPalindromicSubsequences(String s) {
char[] chars = s.toCharArray();
int len = chars.length;
int[][] dp = new int[len][4];
dp[0][chars[0] - 'a']++;
for (int j = 1; j < len; j++) {
int cur = chars[j] - 'a';
dp[j][cur]++;
int charVal = 1;
int lastK = 0;
for (int i = j - 1; i >= 0; i--) {
if (chars[i] == chars[j]) {
charVal = 2;
for (int k = 0; k < 4; k++) {
if (k == cur) {
charVal += lastK;
} else {
charVal += dp[i + 1][k];
}
charVal %= MOD;
}
}
lastK = dp[i][cur];
dp[i][cur] = charVal;
}
}
int ans = 0;
for (int k = 0; k < 4; k++) {
ans += dp[0][k];
ans %= MOD;
}
return ans;
}
}
赶紧去学习dp,不然后面不知道多少题目不会写。