Leetcode 63 定长子串中元音的最大数目

1 题目

1456. 定长子串中元音的最大数目

给你字符串 s 和整数 k

请返回字符串 s 中长度为 k 的单个子字符串中可能包含的最大元音字母数。

英文中的 元音字母 为(a, e, i, o, u)。

示例 1:

复制代码
输入:s = "abciiidef", k = 3
输出:3
解释:子字符串 "iii" 包含 3 个元音字母。

示例 2:

复制代码
输入:s = "aeiou", k = 2
输出:2
解释:任意长度为 2 的子字符串都包含 2 个元音字母。

示例 3:

复制代码
输入:s = "leetcode", k = 3
输出:2
解释:"lee"、"eet" 和 "ode" 都包含 2 个元音字母。

示例 4:

复制代码
输入:s = "rhythms", k = 4
输出:0
解释:字符串 s 中不含任何元音字母。

示例 5:

复制代码
输入:s = "tryhard", k = 4
输出:1

提示:

  • 1 <= s.length <= 10^5
  • s 由小写英文字母组成
  • 1 <= k <= s.length

2 代码实现

cpp 复制代码
class Solution {
public:
    int maxVowels(string s, int k) {
       unordered_set<char> vowels ={'a' , 'e' , 'i' ,'o' ,'u'};
       unordered_map<char , int > window ;

       int left = 0 ;
       int right = 0 ;
       int max_count = 0 ;
       int current_vowel_total = 0 ;

       while(right < s.size()){
        char c = s[right];
        if(vowels.count(c)){
            window[c]++;
            current_vowel_total++;
        }
        right++;

        while(right - left == k ){
            max_count = max (max_count,current_vowel_total);

            char d = s[left];
            if (vowels.count(d)){
                window[d]--;
                current_vowel_total--;
                if(window[d] == 0){
                    window.erase(d);
                }
            }
            left++;
        }
       } 
       return max_count;
    }
};

完整的代码:

cpp 复制代码
#include <iostream>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <algorithm>
using namespace std;

class Solution {
public:
    int maxVowels(string s, int k) {
        // 定义元音集合,用于快速判断字符是否为元音
        unordered_set<char> vowels = {'a', 'e', 'i', 'o', 'u'};
        // 用 map 记录窗口内各元音字母的出现次数(key:元音字符,value:出现次数)
        unordered_map<char, int> window;
        
        int left = 0, right = 0;
        int max_count = 0;
        int current_vowel_total = 0; // 辅助变量:窗口内元音总数(避免每次遍历 map 求和)
        
        while (right < s.size()) {
            // 1. 右移窗口:将当前字符加入窗口
            char c = s[right];
            if (vowels.count(c)) { // 仅统计元音字母
                window[c]++;       // map 中记录该元音的出现次数
                current_vowel_total++; // 元音总数同步增加
            }
            right++; // 增大窗口
            
            // 2. 窗口内数据更新(已通过 map 和 current_vowel_total 维护)
            
            // 3. 判断窗口是否达到定长k:达到后收缩左侧,并更新最大值
            while (right - left == k) {
                // 更新最大元音数(当前窗口是有效定长窗口)
                max_count = max(max_count, current_vowel_total);
                
                // 4. 左移窗口:将左侧字符移出窗口
                char d = s[left];
                if (vowels.count(d)) { // 若移出的是元音
                    window[d]--;       // map 中对应计数减1
                    current_vowel_total--; // 元音总数同步减少
                    // 若该元音计数为0,可从map中删除(可选,不影响结果)
                    if (window[d] == 0) {
                        window.erase(d);
                    }
                }
                left++; // 缩小窗口
            }
        }
        
        return max_count;
    }
};

// 测试代码
int main() {
    Solution sol;
    cout << sol.maxVowels("abciiidef", 3) << endl;    // 输出 3
    cout << sol.maxVowels("aeiou", 2) << endl;        // 输出 2
    cout << sol.maxVowels("leetcode", 3) << endl;     // 输出 2
    cout << sol.maxVowels("rhythms", 4) << endl;      // 输出 0
    cout << sol.maxVowels("tryhard", 4) << endl;      // 输出 1
    return 0;
}

核心说明(严格遵循滑动窗口框架 + map 用法):

算法笔记 14 滑动窗口-CSDN博客(含框架模板)

框架模板:

cpp 复制代码
// 滑动窗口算法伪码框架
void slidingWindow(string s) {
    // 用合适的数据结构记录窗口中的数据,根据具体场景变通
    // 比如说,我想记录窗口中元素出现的次数,就用 map
    // 如果我想记录窗口中的元素和,就可以只用一个 int
    auto window = ...
 
    int left = 0, right = 0;
    while (right < s.size()) {
        // c 是将移入窗口的字符
        char c = s[right];
        window.add(c);
        // 增大窗口
        right++;
 
        // 进行窗口内数据的一系列更新
        ...
 
        // *** debug 输出的位置 ***
        printf("window: [%d, %d)\n", left, right);
        // 注意在最终的解法代码中不要 print
        // 因为 IO 操作很耗时,可能导致超时
 
        // 判断左侧窗口是否要收缩
        while (window needs shrink) {
            // d 是将移出窗口的字符
            char d = s[left];
            window.remove(d);
            // 缩小窗口
            left++;
 
            // 进行窗口内数据的一系列更新
            ...
        }
    }
}
1. 窗口数据结构:unordered_map<char, int>
  • key:窗口内的元音字符(非元音字符不存入 map)
  • value:对应元音字符在窗口内的出现次数
  • 作用:严格按照要求用 map 记录窗口内的相关数据(此处为元音的频次)
2. 辅助变量 current_vowel_total
  • 用于快速获取窗口内元音总数,避免每次需要统计时遍历 map 求和(优化效率)
  • 与 map 数据严格同步:加入元音时 map 计数 +1、总数 +1;移出元音时 map 计数 -1、总数 -1
3. 滑动窗口核心流程(完全匹配框架):
步骤 操作 细节
窗口扩张 右指针右移 若字符是元音,更新 map 计数和总数
窗口内更新 维护 map 和总数 同步数据,无需额外逻辑
收缩条件 right - left == k 定长窗口,达到长度则必须收缩左侧
窗口收缩 左指针右移 若字符是元音,更新 map 计数(计数为 0 时可删除 key)和总数
结果更新 收缩前记录最大值 确保每个定长窗口的元音数都被考虑
4. 时间复杂度与空间复杂度
  • 时间复杂度:O (n),n 为字符串长度。每个字符仅被左右指针各访问一次,map 操作(插入、删除、修改)均为 O (1)(哈希表平均情况)
  • 空间复杂度:O (1),map 中最多存储 5 个 key(元音字母共 5 种),属于常数级空间
相关推荐
"菠萝"1 小时前
C#知识学习-020(访问关键字)
开发语言·学习·c#
●VON1 小时前
Electron 项目在“鸿蒙端”与“桌面端”运行的区别
javascript·学习·electron·openharmony
箫笙默1 小时前
JS基础 - 正则笔记
开发语言·javascript·笔记
لا معنى له2 小时前
残差网络论文学习笔记:Deep Residual Learning for Image Recognition全文翻译
网络·人工智能·笔记·深度学习·学习·机器学习
小白程序员成长日记2 小时前
2025.11.29 力扣每日一题
数据结构·算法·leetcode
张丶大帅2 小时前
JS案例合集
开发语言·javascript·笔记
b***66612 小时前
【golang学习之旅】使用VScode安装配置Go开发环境
vscode·学习·golang
在黎明的反思3 小时前
进程通信之消息队列(IPC)
算法