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 种),属于常数级空间
相关推荐
旖旎夜光4 小时前
C++(17)
c++·学习
Larry_Yanan5 小时前
Qt多进程(三)QLocalSocket
开发语言·c++·qt·ui
superman超哥5 小时前
仓颉语言中元组的使用:深度剖析与工程实践
c语言·开发语言·c++·python·仓颉
专注于大数据技术栈5 小时前
java学习--StringBuilder
java·学习
锦瑟弦音5 小时前
微信小游戏分包(cocos自带分包)
笔记·游戏
LYFlied5 小时前
【每日算法】LeetCode 153. 寻找旋转排序数组中的最小值
数据结构·算法·leetcode·面试·职场和发展
唐装鼠5 小时前
rust自动调用Deref(deepseek)
开发语言·算法·rust
找方案5 小时前
我的 all-in-rag 学习笔记:文本分块 ——RAG 系统的 “信息切菜术“
人工智能·笔记·all-in-rag
HXR_plume5 小时前
【Web信息处理与应用课程笔记1】网页排序(上)
笔记
Lucas555555556 小时前
现代C++四十不惑:AI时代系统软件的基石与新征程
开发语言·c++·人工智能