730. Count Different Palindromic Subsequences
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, ...
andB_1, B_2, ...
are different if there is somei
for whichA_i != B_
Example 1:
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:
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'}
.
Approach #1: DFS + Memeory. [C++][MLE]
class Solution { public: int countPalindromicSubsequences(string S) { return count(S); } private: unordered_map<string, long> memo; static constexpr long mod = 1000000007; int count(const string& s) { if (s.empty()) return 0; if (s.length() == 1) return 1; if (memo[s] > 0) return memo[s]; int len = s.length(); long ans = 0; if (s[0] == s[len-1]) { int l = 1, r = len - 2; while (l <= r && s[l] != s[0]) l++; while (l <= r && s[r] != s[len-1]) r--; if (l > r) ans = count(s.substr(1, len-2))*2 + 2; else if (l == r) ans = count(s.substr(1, len-2))*2 + 1; else ans = count(s.substr(1, len-2))*2 - count(s.substr(l+1, r-l-1)); } else { ans = count(s.substr(0, len-1)) + count(s.substr(1, len-1)) - count(s.substr(1, len-2)); } ans = (ans + mod) % mod; // cout << ans << endl; return memo[s] = ans; } };
Approach #2: Optimization. [C++]
class Solution { public: int countPalindromicSubsequences(string S) { int len = S.length(); memo = vector<int>(len*(len+1)+1, 0); return count(S, 0, len-1); } private: vector<int> memo; static constexpr long mod = 1000000007; int count(const string& S, int s, int e) { if (s > e) return 0; if (s == e) return 1; int key = s * S.length() + e; if (memo[key] > 0) return memo[key]; int len = S.length(); long ans = 0; if (S[s] == S[e]) { int l = s+1, r = e-1; while (l <= r && S[l] != S[s]) l++; while (l <= r && S[r] != S[e]) r--; if (l > r) ans = count(S, s+1, e-1)*2 + 2; else if (l == r) ans = count(S, s+1, e-1)*2 + 1; else ans = count(S, s+1, e-1)*2 - count(S, l+1, r-1); } else { ans = count(S, s+1, e) + count(S, s, e-1) - count(S, s+1, e-1); } return memo[key] = (ans + mod) % mod; } };
Approach #3: DP. [C++]
class Solution { long mod = 1000000007; public int countPalindromicSubsequences(String S) { int len = S.length(); long[][] dp = new long[len][len]; for (int i = 0; i < len; ++i) dp[i][i] = 1; for (int k = 1; k <= len; ++k) { for (int i = 0; i < len-k; ++i) { int j = i + k; if (S.charAt(i) == S.charAt(j)) { dp[i][j] = dp[i+1][j-1] * 2; int l = i + 1; int r = j - 1; while (l <= r && S.charAt(l) != S.charAt(i)) l++; while (l <= r && S.charAt(r) != S.charAt(j)) r--; if (l > r) dp[i][j] += 2; else if (l == r) dp[i][j] += 1; else dp[i][j] -= dp[l+1][r-1]; } else dp[i][j] = dp[i+1][j] + dp[i][j-1] - dp[i+1][j-1]; dp[i][j] = (dp[i][j] + mod) % mod; } } return (int)dp[0][len-1]; } }
Reference:
永远渴望,大智若愚(stay hungry, stay foolish)