858 字
4 分钟
1456. 定长子串中元音的最大数目
1456. 定长子串中元音的最大数目
题目描述
给你字符串 s 和整数 k。
请你在字符串 s 中找到长度为 k 的子串,使得子串中元音字母(a, e, i, o, u)的数目最大,并返回该最大值。
示例 1:
输入:s = "abciiidef", k = 3输出:3解释:子串 "iii" 包含 3 个元音字母。示例 2:
输入:s = "aeiou", k = 2输出:2示例 3:
输入:s = "leetcode", k = 3输出:2提示:
1 <= s.length <= 10^5s由小写英文字母组成1 <= k <= s.length
解法思路
定长滑动窗口,核心思想是:维护一个长度为 k 的窗口,统计窗口内元音个数,滑动时只考虑离开窗口的字母和进入窗口的字母,中间字母无需重复统计,从而把每步更新降到 O(1)。
暴力枚举所有子串要 O(nk),而向右滑一个位置时,只需:
- 移除离开窗口的字母
s[i-k],是元音则计数-1; - 加入进入窗口的字母
s[i],是元音则计数+1。
定长滑窗统一三步套路(入-更新答案-出):
- 入:枚举右端点
i,把s[i]计入窗口元音数。若左端点i-k+1 < 0,说明窗口长度不足 k(尚未形成第一个窗口),继续下一步循环。 - 更新答案:此时窗口长度为 k,用当前元音数更新答案最大值。
- 出:把左端点
i-k+1处元素移出窗口,更新元音数,为下一轮做准备。
逐步举例(s = "abciiidef", k = 3,用 vowel 表示当前窗口元音数):
- 从左到右遍历。先统计前
k-1=2个字母a, b的元音数:vowel = 1。 i=2,c进入窗口 → 窗口abc,vowel = 1,得第 1 个长 k 子串,更新ans = 1;出a→vowel = 0。i=3,i进入窗口 → 窗口bci,vowel = 1,更新ans = 1;出b→vowel = 1。i=4,i进入窗口 → 窗口cii,vowel = 2,更新ans = 2;出c→vowel = 2。i=5,i进入窗口 → 窗口iii,vowel = 3,更新ans = 3;出i→vowel = 2。i=6,d进入窗口 → 窗口iid,vowel = 2,更新ans仍为 3;出i→vowel = 1。i=7,e进入窗口 → 窗口ide,vowel = 2;出i→vowel = 1。i=8,f进入窗口 → 窗口def,vowel = 1。
遍历结束,ans = 3,与预期一致。可以看到每步只处理进/出窗口的 2 个字符,窗口内其余元素不重复统计。
优化:答案的理论最大值就是 k(窗口内全是元音)。一旦 ans == k,答案无法再增大,可直接提前退出循环,进一步减少遍历。
代码见下方。关于外围的
set/直接in "aeiou"判断元音的写法、以及”入-更新-出”三步边界条件,参考灵茶山艾府对该题(也是定长滑窗模板题)的完整讲解。
复杂度分析
- 时间复杂度:O(n),其中 n 是
s的长度,每步滑动 O(1)。 - 空间复杂度:O(1),仅使用常数额外空间。
代码实现
class Solution: def maxVowels(self, s: str, k: int) -> int: vowels = set("aeiou") cur = sum(1 for c in s[:k] if c in vowels) ans = cur for i in range(k, len(s)): cur += (s[i] in vowels) - (s[i - k] in vowels) if cur > ans: ans = cur return ansimport unittest
class TestMaxVowels(unittest.TestCase): def setUp(self): self.solution = Solution()
def test_example1(self): self.assertEqual(self.solution.maxVowels("abciiidef", 3), 3)
def test_example2(self): self.assertEqual(self.solution.maxVowels("aeiou", 2), 2)
def test_example3(self): self.assertEqual(self.solution.maxVowels("leetcode", 3), 2)
def test_single_char(self): self.assertEqual(self.solution.maxVowels("a", 1), 1)
def test_no_vowel(self): self.assertEqual(self.solution.maxVowels("bcdfg", 2), 0)
if __name__ == "__main__": unittest.main() 1456. 定长子串中元音的最大数目
https://h1s97x.github.io/posts/coding/coding-1456-max-vowels/