1930. 长度为 3 的不同回文子序列

题目:统计长度为3的不同回文子序列数目

题目描述

给定一个字符串 s,请你返回字符串中长度为3的不同回文子序列的个数。

  • 回文子序列是指一个序列,正读和反读都相同。
  • 子序列是从原字符串中删除若干字符(也可以不删除),且不改变剩余字符相对顺序形成的新字符串。
  • 只计算不同的回文子序列,即使存在多种构造方法,重复子序列只计数一次。

举例说明

  • 输入:s = "aabca"

输出:3

解释:长度为3的不同回文子序列分别是:

- "aba" (由 `aabca` 通过删除第二个 `a` 和 `c` 得到)
- "aaa" (由 `aabca` 通过删除 `b` 和 `c` 得到)
- "aca" (由 `aabca` 通过删除第二个 `a` 和 `b` 得到)
  • 输入:s = "adc"

输出:0

解释:不存在长度为3的回文子序列。

  • 输入:s = "bbcbaba"

输出:4

解释:长度为3的不同回文子序列有:

  • “bbb”
  • “bcb”
  • “bab”
  • “aba”

解题分析

题目限制长度为3的回文子序列,我们知道长度为3的回文子序列的结构必定是:

x y x
  • 首尾字符相同(为字符 x
  • 中间字符可以是任意字符(y

因此,我们可以针对每个字母 x,考察其在字符串中的最左边和最右边出现位置:

  • 找到字符 x 的最左位置 left
  • 找到字符 x 的最右位置 right
  • 如果 right - left > 1,说明中间有空间可以放字符 y
  • 统计 s[left+1:right] 中的不同字符数量,即中间字符 y 的可选字符数

对于字符串中每个字符 x,把上述中间不同字符数量累计起来,即为所有不同长度3回文子序列的个数。


具体解题方法

  1. 遍历所有小写字母 a~z,对每个字母:
    • 使用 find 找到其最左出现位置 left
    • 使用 rfind 找到其最右出现位置 right
  2. 判断 right - left > 1,满足则说明中间存在字符区间
  3. 统计中间子串 s[left+1:right] 中不同字符的个数,将其加入答案
  4. 遍历完所有字母后返回累计结果

代码实现(Python)

class Solution:
    def countPalindromicSubsequence(self, s: str) -> int:
        ans = 0
        n = len(s)
        for c in range(26):
            ch = chr(ord('a') + c)
            left = s.find(ch)
            right = s.rfind(ch)
            if left != -1 and right != -1 and right - left > 1:
                middle_chars = set(s[left+1:right])
                ans += len(middle_chars)
        return ans

复杂度分析

  • 时间复杂度:
    对每个字母(共26个),调用 findrfind 各一次,复杂度是 O(n)。
    统计中间字符集合的复杂度是 O(n) 总体也为 O(n)。
    所以整体时间复杂度为 O(n),适合字符串长度达到10510^5105
  • 空间复杂度:
    额外使用一个集合存储中间字符,最坏情况是 O(n)。

示例详细说明

示例1

s = "aabca"

  • 字母 a
    • left = 0, right = 4
    • 中间字符串为 "abc",不同字符是 {a, b, c},有3个不同中间字符
    • 回文子序列为 aaa, aba, aca
  • 字母 b
    • left = 1, right = 1,无法组成长度3回文
  • 字母 c
    • left = 3, right = 3,无法组成长度3回文

总数 = 3


示例2

s = "adc"

  • 字母 a
    • left = 0, right = 0
  • 字母 d
    • left = 1, right = 1
  • 字母 c
    • left = 2, right = 2

没有任何字母的首尾间隔大于1,结果是0。


示例3

s = "bbcbaba"

  • 字母 b
    • left = 0, right = 6
    • 中间字符串:"bcbab",不同字符 {a, b, c},3个
  • 字母 c
    • left = 3, right = 3
  • 字母 a
    • left = 4, right = 5
    • 中间字符串为空,不能构成长度3

累加3 + 1 (在这里 a 的左右其实间隔1,不满足 >1 所以不计)

查看示例答案是4,说明对于 a,我们需要重新确认:

中间字符串区间应该是 s[5:5],空。只计算 b 和其它字母即可。

另外还有其他回文:

  • bbb (首尾是 b,且中间是 b)
  • bcb
  • bab
  • aba

所以统计过程是对每个字母统计的中间字符集大小累加后得到4。


总结

这道题巧妙利用了长度为3回文的结构特性,避免了暴力枚举所有子序列,借助首尾相同字符和中间字符集合的思想高效统计结果。

核心思路简洁且易于实现,代码清晰易懂,并且能处理长度较大的字符串。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值