LeetCode #1456 Medium

Maximum Number of Vowels in a Substring

Maximum Number of Vowels in a Substring of Given Length: return the maximum number of vowels in any substring of s with length exactly k.

Constraints
  • 1 <= s.length <= 10⁵
  • s consists of lowercase English letters.
  • 1 <= k <= s.length
stringsliding-window
Open on LeetCode ↗
02

Intuition

Consecutive windows of length k overlap in k-1 characters, so recounting each one wastes almost everything. Count the first window once, then slide: add the character entering on the right, subtract the one leaving on the left. Each step costs two comparisons regardless of k.

How to spot this pattern

A fixed-length window with a quantity to maximise is the cleanest sliding-window signature — the phrase 'substring of given length k' is the giveaway. Once the window size is constant, the update is always the same shape: add the entering element, remove the leaving one. Same machinery as Maximum Average Subarray and Find All Anagrams in a String.

03

Approach

Try it first

Before reading on: write two neighbouring windows of length 3 under each other and mark what actually changed. How many characters differ? Aim for O(n) rather than O(n·k).

1

Why recounting is quadratic

There are n - k + 1 windows and counting each from scratch costs O(k), giving O(n·k) — with n up to 10⁵ and k up to n, that is 10¹⁰ operations. But the window at position i and the window at i+1 differ by exactly two characters. Everything else is shared, so almost the entire count is being recomputed for no reason.

2

Build the first window, then slide

Count vowels in s[0..k-1] directly — that is the only full count you ever do. Then for each subsequent position, the new window gains s[i] and loses s[i-k]. Increment the running count if the entering character is a vowel, decrement if the leaving one was. The count is now correct for the new window in O(1), and you compare it against the best seen so far.

3

Fixed versus variable windows

This is a fixed-size window: k never changes, so there is no inner loop shrinking the left edge. That makes it the simplest form of the pattern — one pointer, one arithmetic update per step. Total cost is O(n) time and O(1) space. An early exit is possible when the count reaches k, since no window can beat an all-vowel one; on typical inputs it rarely fires, but it is free to add.

04

Solution & live demo

1class Solution:
2 def maxVowels(self, s, k):
3 vowels = set("aeiou")
4 count = sum(1 for ch in s[:k] if ch in vowels)
5 best = count
6 for i in range(k, len(s)):
7 count += s[i] in vowels
8 count -= s[i - k] in vowels
9 best = max(best, count)
10 return best
05

Common pitfalls

Recounting each window

✗ Wrong
for i in range(len(s) - k + 1):
    best = max(best, sum(1 for c in s[i:i+k] if c in vowels))
✓ Right
count += s[i] in vowels
count -= s[i - k] in vowels

Correct but O(n·k), which times out at the upper constraints. The slice also allocates a new string on every iteration.

Subtracting the wrong index

✗ Wrong
count -= s[i - k + 1] in vowels
✓ Right
count -= s[i - k] in vowels

When s[i] enters, the window covers i-k+1 … i, so the character that just left is at i-k. Off by one here silently keeps a stale character in the count.

Forgetting to seed with the first window

✗ Wrong
count = 0
for i in range(k, len(s)):
✓ Right
count = sum(1 for ch in s[:k] if ch in vowels)
for i in range(k, len(s)):

The slide loop starts at index k and assumes the first window is already counted. Starting from zero undercounts every window by whatever the first one contained.

06

Edge cases

k equals the string length

Only one window exists; the initial count is the answer and the slide loop never runs.

No vowels at all

The running count stays 0 and the answer is 0.

All vowels

Every window scores k, which is the maximum possible.

k = 1

The window is a single character; the answer is 1 if any vowel exists, else 0.

Vowels clustered at the end

Sliding keeps the count accurate to the last window, so a late cluster is still found.

07

Complexity

Time
O(n)
Space
O(1)
One full count for the first window, then O(1) per slide. The vowel set is a fixed five entries.