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

题目链接

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

题目描述

给定一个字符串 s 和一个整数 k,请找出字符串中长度为 k 的子串中包含的最大元音字母数量。元音字母包括 aeiou

解法分析:滑动窗口法

核心思路

该解法采用滑动窗口技术,通过维护一个长度为 k 的窗口,遍历字符串时动态计算窗口内的元音字母数量,从而找到最大值。具体步骤如下:

  1. 右指针扩展窗口,统计当前字符是否为元音并累加计数
  2. 当窗口长度达到 k 后,左指针开始滑动,每次移除窗口左边界的字符
  3. 实时更新窗口内元音字母的最大数量

代码实现

class Solution:
    def maxVowels(self, s: str, k: int) -> int:
        l = 0          # 左指针
        cnt = 0        # 当前窗口内元音字母数量
        ans = 0        # 最大元音字母数量
        
        for r in range(len(s)):
            # 统计当前字符是否为元音,是则cnt加1
            cnt += 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

代码解析

  1. 初始化变量

    • l:滑动窗口的左指针,初始位置为0
    • cnt:记录当前窗口内的元音字母数量,初始为0
    • ans:记录最大元音字母数量,初始为0
  2. 遍历字符串

    • 右指针 r 从0开始遍历每个字符
    • cnt += 1 if s[r] in "aeiou" else 0:判断当前字符是否为元音,若是则cnt加1
  3. 窗口滑动逻辑

    • r + 1 >= k 时,说明窗口长度已达到 k(索引从0开始,r+1 表示当前窗口长度)
    • ans = max(ans, cnt):更新当前窗口内元音字母的最大数量
    • cnt -= 1 if s[l] in "aeiou" else 0:减去左边界字符的元音计数
    • l += 1:左指针右移,窗口向右滑动一位
  4. 结果返回

    • 遍历结束后,ans 即为所有长度为 k 的子串中元音字母的最大数量

关键逻辑说明

  • 窗口长度控制:通过 r + 1 >= k 判断窗口是否达到指定长度,确保窗口始终保持长度为 k
  • 动态计数:每次窗口滑动时,仅需更新左边界字符的计数,避免重新计算整个窗口
  • 时间优化:滑动窗口技术使得每个字符仅被访问两次(进入和离开窗口时),时间复杂度为线性

复杂度分析

  • 时间复杂度:O(n),其中 n 是字符串长度。右指针遍历字符串一次,左指针最多移动 n 次,总操作次数为 O(n)。
  • 空间复杂度:O(1),仅使用常数级额外空间存储指针和计数变量。

示例详解

以输入 s = "abciiidef", k = 3 为例:

  1. 初始化l=0, cnt=0, ans=0

  2. r=0,字符’a’

    • a 是元音,cnt=1
    • r+1=1 < 3,不滑动窗口
  3. r=1,字符’b’

    • b 不是元音,cnt=1
    • r+1=2 < 3,不滑动窗口
  4. r=2,字符’c’

    • c 不是元音,cnt=1
    • r+1=3 >= 3,进入滑动:
      • ans = max(0, 1) = 1
      • s[l=0]='a' 是元音,cnt=1-1=0
      • l=1
  5. r=3,字符’i’

    • i 是元音,cnt=0+1=1
    • r+1=4 >= 3
      • ans = max(1, 1) = 1
      • s[l=1]='b' 不是元音,cnt=1-0=1
      • l=2
  6. r=4,字符’i’

    • i 是元音,cnt=1+1=2
    • r+1=5 >= 3
      • ans = max(1, 2) = 2
      • s[l=2]='c' 不是元音,cnt=2-0=2
      • l=3
  7. r=5,字符’i’

    • i 是元音,cnt=2+1=3
    • r+1=6 >= 3
      • ans = max(2, 3) = 3
      • s[l=3]='i' 是元音,cnt=3-1=2
      • l=4
  8. r=6,字符’d’

    • d 不是元音,cnt=2+0=2
    • r+1=7 >= 3
      • ans = max(3, 2) = 3
      • s[l=4]='i' 是元音,cnt=2-1=1
      • l=5
  9. r=7,字符’e’

    • e 是元音,cnt=1+1=2
    • r+1=8 >= 3
      • ans = max(3, 2) = 3
      • s[l=5]='i' 是元音,cnt=2-1=1
      • l=6
  10. r=8,字符’f’

    • f 不是元音,cnt=1+0=1
    • r+1=9 >= 3
      • ans = max(3, 1) = 3
      • s[l=6]='d' 不是元音,cnt=1-0=1
      • l=7
  11. 最终返回 3,对应子串 "iii"(索引3-5)。

总结

该解法利用滑动窗口高效解决了定长子串的元音计数问题,核心在于维护固定长度的窗口并动态更新计数。滑动窗口技术在此类问题中具有显著优势:

  1. 避免了暴力枚举所有子串的O(n²)复杂度
  2. 通过双指针移动实现线性时间复杂度
  3. 仅需常数空间存储临时变量

此方法适用于所有"定长子串统计"问题,如子串中特定字符计数、子串和计算等,是算法设计中的基础技巧。

你可能感兴趣的:(滑动窗口与双指针,leetcode,算法,职场和发展)