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

相关推荐
行云流水201914 分钟前
编程竞赛算法选择:理解时间复杂度提升解题效率
算法
smj2302_796826522 小时前
解决leetcode第3768题.固定长度子数组中的最小逆序对数目
python·算法·leetcode
cynicme2 小时前
力扣3531——统计被覆盖的建筑
算法·leetcode
core5123 小时前
深度解析DeepSeek-R1中GRPO强化学习算法
人工智能·算法·机器学习·deepseek·grpo
mit6.8243 小时前
计数if|
算法
a伊雪3 小时前
c++ 引用参数
c++·算法
圣保罗的大教堂4 小时前
leetcode 3531. 统计被覆盖的建筑 中等
leetcode
Data_agent4 小时前
1688获得1688店铺列表API,python请求示例
开发语言·python·算法
2301_764441334 小时前
使用python构建的应急物资代储博弈模型
开发语言·python·算法