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, ... and B_1, B_2, ... are different if there is some i for which A_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]

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
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++]

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
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++]

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
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:

http://zxi.mytechroad.com/blog/dynamic-programming/leetcode-730-count-different-palindromic-subsequences/

 

posted @   Veritas_des_Liberty  阅读(269)  评论(0编辑  收藏  举报
编辑推荐:
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
阅读排行:
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· DeepSeek 解答了困扰我五年的技术问题。时代确实变了!
· 本地部署DeepSeek后,没有好看的交互界面怎么行!
· 趁着过年的时候手搓了一个低代码框架
· 推荐一个DeepSeek 大模型的免费 API 项目!兼容OpenAI接口!
历史上的今天:
2018-03-13 D - Back and Forth(模拟)
2018-03-13 I - 一次元リバーシ / 1D Reversi(水题)
点击右上角即可分享
微信分享提示