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_i.

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'}.

    分析

    要求所有不同回文子序列的数量。我们知道求所有回文子序列的动态规划。只需要在此基础上增加一维的状态。

    dp[x][i][j]表示s[i]=s[j]='a'+x的子问题的答案。

    if s[i]!='a'+x ,则dp[x][i][j]=dp[x][i+1][j]

    if s[j]!='a'+x,则dp[x][i][j]=dp[x][i][j-1]

    if s[i]=s[j]='a'+x,则dp[x][i][j]=2+dp[0][i+1][j-1]+dp[1][i+1][j-1]+dp[2][i+1][j-1]+dp[3][i+1][j-1]

    设n为字符串的长度,那么答案就是dp[0][0][n-1]+dp[1][0][n-1]+dp[2][0][n-1]+dp[3][0][n-1]

    class Solution {
    public:
      int countPalindromicSubsequences(string S) {
        int n = S.size();
        int mod = 1000000007;
        auto dp_ptr = new vector<vector<vector<int>>>(4, vector<vector<int>>(n, vector<int>(n)));
        auto& dp = *dp_ptr;
    
        for (int i = n-1; i >= 0; --i) {
          for (int j = i; j < n; ++j) {
            for (int k = 0; k < 4; ++k) {
              char c = 'a' + k;
              if (j == i) {
                if (S[i] == c) dp[k][i][j] = 1;
                else dp[k][i][j] = 0;
              } else { // j > i
                if (S[i] != c) dp[k][i][j] = dp[k][i+1][j];
                else if (S[j] != c) dp[k][i][j] = dp[k][i][j-1];
                else { // S[i] == S[j] == c
                  if (j == i+1) dp[k][i][j] = 2; // "aa" : {"a", "aa"}
                  else { // length is > 2
                    dp[k][i][j] = 2;
                    for (int m = 0; m < 4; ++m) { // count each one within subwindows [i+1][j-1]
                      dp[k][i][j] += dp[m][i+1][j-1];
                      dp[k][i][j] %= mod;
                    }
                  }
                }
              }
            }
          }
        }
    
        int ans = 0;
        for (int k = 0; k < 4; ++k) {
          ans += dp[k][0][n-1];
          ans %= mod;
        }
    
        return ans;
      }
    };


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值