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 是字符串长度)。

相关推荐
小年糕是糕手2 小时前
【C++】C++入门 -- inline、nullptr
linux·开发语言·jvm·数据结构·c++·算法·排序算法
高洁012 小时前
具身智能-普通LLM智能体与具身智能:从语言理解到自主行动
人工智能·深度学习·算法·aigc·知识图谱
星期天22 小时前
3.2联合体和枚举enum,还有动态内存malloc,free,calloc,realloc
c语言·开发语言·算法·联合体·动态内存·初学者入门·枚举enum
Andy3 小时前
回文子串数目--动态规划算法
算法·动态规划
sin_hielo3 小时前
leetcode 1930
算法·leetcode
塞北山巅3 小时前
相机自动曝光(AE)核心算法——从参数调节到亮度标定
数码相机·算法
聆风吟º3 小时前
【数据结构入门手札】算法核心概念与复杂度入门
数据结构·算法·复杂度·算法的特性·算法设计要求·事后统计方法·事前分析估算方法
vir023 小时前
密码脱落(最长回文子序列)
数据结构·c++·算法
福尔摩斯张4 小时前
二维数组详解:定义、初始化与实战
linux·开发语言·数据结构·c++·算法·排序算法