leetcode 730

问题

Given a string S, find the number of different non-empty palindromic subsequences in S, and return that number modulo 10^9 + 7.

A subsequence of a string S is obtained by deleting 0 or more characters from S.

A sequence is palindromic if it is equal to the sequence reversed.

Two sequences A_1, A_2, ... and B_1, B_2, ... are different if there is some i for which A_i != B_i.

Example 1:

1
2
3
4
5
6
Input: 
S = 'bccb'
Output: 6
Explanation:
The 6 different non-empty palindromic subsequences are 'b', 'c', 'bb', 'cc', 'bcb', 'bccb'.
Note that 'bcb' is counted only once, even though it occurs twice.

Example 2:

1
2
3
4
5
Input: 
S = 'abcdabcdabcdabcdabcdabcdabcdabcddcbadcbadcbadcbadcbadcbadcbadcba'
Output: 104860361
Explanation:
There are 3104860382 different non-empty palindromic subsequences, which is 104860361 modulo 10^9 + 7.

Note:

The length of S will be in the range [1, 1000].

Each character S[i] will be in the set {'a', 'b', 'c', 'd'}.

分析

https://leetcode.com/problems/count-different-palindromic-subsequences/discuss/109507/Java-96ms-DP-Solution-with-Detailed-Explanation

https://www.youtube.com/watch?v=UjiFFYU3EKM

$dp[i][j]$ 表示字符串 $s[i…j]$ 所包含的不重复的回文子序列的数量。

当 $s[i] \neq s[j]$ 时,$dp[i][j] = dp[i+1][j] + d[i][j-1] - dp[i+1][j-1]$

当 $s[i] == s[j]$ 时,$l$ 表示从 $s[(i+1) … j]$ 中,最左边使 $s[l] == s[i]$ 的下标;$r$ 表示从 $s[i … (j-1)]$ 中,最左边使 $s[r] == s[j]$ 的下标;

  1. $l < r$ 时,$dp[i][j] = 2*dp[i+1][j-1]-dp[l+1][r-1] $
  2. $l == r$ 时,$dp[i][j] = 2*dp[i+1][j-1] + 1$
  3. $l > r$ 时,$dp[i][j] = 2*dp[i+1][j-1] + 2$

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Solution {
public:
const int mod = 1e9+7;
int countPalindromicSubsequences(string S) {
int n = S.size();
vector<vector<int>> dp(n, vector<int>(n, 0));
// 空串表示为0,eg. dp[i][j] = 0(i > j)
for (int i = 0; i < n; ++i)
dp[i][i] = 1;

for (int len = 2; len <= n; ++len) {
for (int i = 0; i < n-len+1; ++i) {
int j = i+len-1;
if (S[i] == S[j]) {
int l = i+1;
int r = j-1;
while (l <= r && S[l] != S[i])
l++;
while (l <= r && S[r] != S[j])
r--;
if (l < r) {
dp[i][j] = 2*dp[i+1][j-1] - dp[l+1][r-1];
} else if (l == r) {
dp[i][j] = 2*dp[i+1][j-1] + 1;
} else {
dp[i][j] = 2*dp[i+1][j-1] + 2;
}
} else {
dp[i][j] = dp[i+1][j]+dp[i][j-1]-dp[i+1][j-1];
}
dp[i][j] = dp[i][j]<0? dp[i][j] + mod: dp[i][j]%mod;
}
}
return dp[0][n-1];
}
};