leetcode刷题笔记

本文详细介绍了LeetCode第730题《统计不同回文子序列》的解题思路和代码实现。通过动态规划方法,计算字符串中不同非空回文子序列的数量,对结果取模1000000007。文章讲解了状态转移方程的建立,并给出了完整的C++代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

leetcode刷题笔记——01

730. 统计不同回文子序列

给定一个字符串 S,找出 S 中不同的非空回文子序列个数,并返回该数字与 10^9 + 7 的模。

通过从 S 中删除 0 个或多个字符来获得子序列。

如果一个字符序列与它反转后的字符序列一致,那么它是回文字符序列。

如果对于某个 i,A_i != B_i,那么 A_1, A_2, … 和 B_1, B_2, … 这两个字符序列是不同的。
字符串 S 的长度将在[1, 1000]范围内。
每个字符 S[i] 将会是集合 {‘a’, ‘b’, ‘c’, ‘d’} 中的某一个。

思路分析

记dp[x][i][j]表示子字符串S[i~j]中不同回文子序列的数目,其中(0<x<4),s[i]=s[j]=a+‘x’,
1、当s[i] !=a+'x’时,dp[x][i][j]=dp[x][i+1][j]
2、当s[j] !=a+'x’时,dp[x][i][j]=dp[x][i][j-1]
3、当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],
当第一个和最后一个字符相同时,我们需要计算子串 S[i+1][j-1] 中所有不同的回文(a、b、c、d 中的每一个),因为dp[x]表示的是以a+'x’作为边界的回文序列数目,子串s[i+1] [j-1]中的回文序列加上i、j这两个边界字符,构成了dp[x][i][j]的一部分,相比于dp[][i+1][j-1],dp[x][i][j]还要多加2个回文序列,分别为(以x=0为例)a、aa,所以这个2表示的是a、aa

两侧加字符 ch 后,ch 和 chch 丢失了,所以 +2。例如:

aa: a aa
baab: bab baab b bb
bbaabb: bbabb bbaabb bbb bbbb b bb
所以代码如下:

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;
  }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值