2025.11.21 力扣每日一题

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

这个题目还可以,主要是对首尾相同字符的搜索,以及两相同字符间不同字符的数目的处理。

用的力扣官方解法,简单易懂

cpp 复制代码
class Solution {
public:
    int countPalindromicSubsequence(string s) {
        int n = s.size(); // 存储字符串s的长度
        int res = 0;      // 存储最终的会问子序列数量
        // 枚举所有可能的首尾字符
        for (char ch = 'a'; ch <= 'z'; ++ch) { // 从a-z,++表示变成下一个字母
            int l = 0, r = n - 1; // 定义字符串起始索引left 末尾索引right
            // 寻找该字符第一次出现的下标
            while (l < n && s[l] != ch) {
                l++;
            }
            // 寻找该字符最后一次出现的下标
            while (r >= 0 && s[r] != ch) {
                --r;
            }
            // 如果 r - l < 2,意味着 l 和 r
            // 指向同一个位置(r-l=0),或者它们是相邻的(r-l=1),都没有足够的空间容纳一个中间字符,因此无法构成长度为
            // 3 的回文子序列 。
            if (r - l < 2) {
                // 该字符未出现,或两下标中间的子串不存在
                continue;
            }
            // 定义一个 unordered_set(无序哈希集合),用于存储在 l 和 r
            // 之间发现的所有不同字符。unordered_set 的特性是自动去重
            //  利用哈希集合统计s[l+1..r-1]子串的字符总数,并更新答案
            unordered_set<char> charset;
            // 循环遍历 l 和 r 之间的所有字符(不包括 l 和 r 本身)。
            for (int k = l + 1; k < r; ++k) {
                // 当前遍历到的字符 s[k] 插入到哈希集合 charset 中。如果 s[k]
                // 已经存在于集合中,insert 操作不会做任何事情。
                charset.insert(s[k]);
            }
            // 环结束后,charset 中存储的就是 l 和 r
            // 之间所有不重复的中间字符。集合的大小(charset.size())就是以当前
            // ch 为首尾的不同回文子序列的数量。将这个数量加到最终结果 res 上。
            res += charset.size();
        }
        return res;
    }
};

代码的核心思路是**利用回文子序列 "首尾字符相同、中间字符任意" 的特点,通过枚举首尾字符 + 统计中间字符种类来计算不同回文子序列的数量,**逐部分解释:

一、题目核心要求

需要统计长度为 3 的不同回文子序列 的个数。长度为 3 的回文子序列的结构是 aba(首尾字符相同,中间字符任意),且相同的子序列只计数一次。

二、代码逻辑拆解

1. 枚举所有可能的 "首尾字符"

长度为 3 的回文子序列,首尾字符必须相同(记为 ch)。代码中通过 for (char ch = 'a'; ch <= 'z'; ++ch) 枚举 26 个小写字母作为首尾字符。

2. 找到首尾字符的 "第一次" 和 "最后一次" 出现位置
  • l:字符 ch 在字符串 s第一次出现的下标 (通过 while (l < n && s[l] != ch) 从左向右找);
  • r:字符 ch 在字符串 s最后一次出现的下标 (通过 while (r >= 0 && s[r] != ch) 从右向左找)。

r - l < 2(即 lr 之间没有至少 1 个字符),说明无法构成 "首尾为 ch、长度为 3" 的子序列,直接跳过当前字符。

3. 统计 "首尾之间" 的所有不同字符(中间字符)

首尾字符确定为 ch 后,中间字符可以是 s[l+1..r-1] 中的任意字符,且每个不同的中间字符对应一个不同的回文子序列 (如首尾是 a,中间是 b 对应 aba,中间是 c 对应 aca)。

代码中用 unordered_set<char> charset 统计 s[l+1..r-1] 中的所有不同字符(set 自动去重),charset.size() 就是当前首尾字符 ch 对应的不同回文子序列数量,将其累加到结果 res 中。

三、示例验证(以示例 1 s = "aabca" 为例)

  1. 枚举 ch = 'a'
    • l = 0(第一个 a),r = 4(最后一个 a);
    • 中间字符是 s[1..3] = "abc"charset 包含 a、b、c,大小为 3;
    • res += 3(此时 res = 3)。
  2. 枚举其他字符(如 b):
    • l = 2(第一个 b),r = 2(最后一个 b),r - l < 2,跳过。
  3. 最终 res = 3,与示例 1 的输出一致。

四、总结

这个代码的核心是 利用 "首尾字符相同 + 中间字符去重"的策略,通过枚举 26 个字母的首尾位置,结合哈希集合统计中间字符的种类,高效计算出所有不同的长度为 3 的回文子序列,时间复杂度为 O (26*n)(n 是字符串长度)。

相关推荐
vortex510 分钟前
几种 dump hash 方式对比分析
算法·哈希算法
Wei&Yan1 小时前
数据结构——顺序表(静/动态代码实现)
数据结构·c++·算法·visual studio code
团子的二进制世界2 小时前
G1垃圾收集器是如何工作的?
java·jvm·算法
吃杠碰小鸡2 小时前
高中数学-数列-导数证明
前端·数学·算法
故事不长丨2 小时前
C#线程同步:lock、Monitor、Mutex原理+用法+实战全解析
开发语言·算法·c#
long3162 小时前
Aho-Corasick 模式搜索算法
java·数据结构·spring boot·后端·算法·排序算法
近津薪荼2 小时前
dfs专题4——二叉树的深搜(验证二叉搜索树)
c++·学习·算法·深度优先
熊文豪2 小时前
探索CANN ops-nn:高性能哈希算子技术解读
算法·哈希算法·cann
熊猫_豆豆2 小时前
YOLOP车道检测
人工智能·python·算法
艾莉丝努力练剑3 小时前
【Linux:文件】Ext系列文件系统(初阶)
大数据·linux·运维·服务器·c++·人工智能·算法