题目链接
1456. 定长子串中元音的最大数目
题目描述
给定一个字符串 s 和一个整数 k,请找出字符串中长度为 k 的子串中包含的最大元音字母数量。元音字母包括 a、e、i、o、u。
解法分析:滑动窗口法
核心思路
该解法采用滑动窗口技术,通过维护一个长度为 k 的窗口,遍历字符串时动态计算窗口内的元音字母数量,从而找到最大值。具体步骤如下:
- 右指针扩展窗口,统计当前字符是否为元音并累加计数
- 当窗口长度达到
k后,左指针开始滑动,每次移除窗口左边界的字符 - 实时更新窗口内元音字母的最大数量
代码实现
class Solution:def maxVowels(self, s: str, k: int) -> int:l = 0 # 左指针cnt = 0 # 当前窗口内元音字母数量ans = 0 # 最大元音字母数量for r in range(len(s)):# 统计当前字符是否为元音,是则cnt加1cnt += 1 if s[r] in "aeiou" else 0# 当窗口长度达到k时,开始滑动窗口if r + 1 >= k:ans = max(ans, cnt) # 更新最大值cnt -= 1 if s[l] in "aeiou" else 0 # 移除左边界字符的计数l += 1 # 左指针右移,窗口滑动return ans
代码解析
-
初始化变量:
l:滑动窗口的左指针,初始位置为0cnt:记录当前窗口内的元音字母数量,初始为0ans:记录最大元音字母数量,初始为0
-
遍历字符串:
- 右指针
r从0开始遍历每个字符 cnt += 1 if s[r] in "aeiou" else 0:判断当前字符是否为元音,若是则cnt加1
- 右指针
-
窗口滑动逻辑:
- 当
r + 1 >= k时,说明窗口长度已达到k(索引从0开始,r+1表示当前窗口长度) ans = max(ans, cnt):更新当前窗口内元音字母的最大数量cnt -= 1 if s[l] in "aeiou" else 0:减去左边界字符的元音计数l += 1:左指针右移,窗口向右滑动一位
- 当
-
结果返回:
- 遍历结束后,
ans即为所有长度为k的子串中元音字母的最大数量
- 遍历结束后,
关键逻辑说明
- 窗口长度控制:通过
r + 1 >= k判断窗口是否达到指定长度,确保窗口始终保持长度为k - 动态计数:每次窗口滑动时,仅需更新左边界字符的计数,避免重新计算整个窗口
- 时间优化:滑动窗口技术使得每个字符仅被访问两次(进入和离开窗口时),时间复杂度为线性
复杂度分析
- 时间复杂度:O(n),其中
n是字符串长度。右指针遍历字符串一次,左指针最多移动n次,总操作次数为 O(n)。 - 空间复杂度:O(1),仅使用常数级额外空间存储指针和计数变量。
示例详解
以输入 s = "abciiidef", k = 3 为例:
-
初始化:
l=0, cnt=0, ans=0 -
r=0,字符’a’:
a是元音,cnt=1r+1=1 < 3,不滑动窗口
-
r=1,字符’b’:
b不是元音,cnt=1r+1=2 < 3,不滑动窗口
-
r=2,字符’c’:
c不是元音,cnt=1r+1=3 >= 3,进入滑动:ans = max(0, 1) = 1s[l=0]='a'是元音,cnt=1-1=0l=1
-
r=3,字符’i’:
i是元音,cnt=0+1=1r+1=4 >= 3:ans = max(1, 1) = 1s[l=1]='b'不是元音,cnt=1-0=1l=2
-
r=4,字符’i’:
i是元音,cnt=1+1=2r+1=5 >= 3:ans = max(1, 2) = 2s[l=2]='c'不是元音,cnt=2-0=2l=3
-
r=5,字符’i’:
i是元音,cnt=2+1=3r+1=6 >= 3:ans = max(2, 3) = 3s[l=3]='i'是元音,cnt=3-1=2l=4
-
r=6,字符’d’:
d不是元音,cnt=2+0=2r+1=7 >= 3:ans = max(3, 2) = 3s[l=4]='i'是元音,cnt=2-1=1l=5
-
r=7,字符’e’:
e是元音,cnt=1+1=2r+1=8 >= 3:ans = max(3, 2) = 3s[l=5]='i'是元音,cnt=2-1=1l=6
-
r=8,字符’f’:
f不是元音,cnt=1+0=1r+1=9 >= 3:ans = max(3, 1) = 3s[l=6]='d'不是元音,cnt=1-0=1l=7
-
最终返回
3,对应子串"iii"(索引3-5)。
总结
该解法利用滑动窗口高效解决了定长子串的元音计数问题,核心在于维护固定长度的窗口并动态更新计数。滑动窗口技术在此类问题中具有显著优势:
- 避免了暴力枚举所有子串的O(n²)复杂度
- 通过双指针移动实现线性时间复杂度
- 仅需常数空间存储临时变量
此方法适用于所有"定长子串统计"问题,如子串中特定字符计数、子串和计算等,是算法设计中的基础技巧。