Longest Substring with At Most K Distinct Characters medium
Description
Given a string s and an integer k, return the length of the longest substring of s that contains at most k distinct characters.
Examples
> Case 1:
s = "eceba", k = 2
Output: 3
Explanation: "ece" — two distinct characters (e and c), length 3.
> Case 2:
s = "aa", k = 1
Output: 2
> Case 3:
s = "abcabcabc", k = 0
Output: 0Constraints
1 <= s.length <= 5 × 10^40 <= k <= 50
State design
Pure variable-size, longest-valid. The state we maintain is a frequency map — character to count in the current window.
- Contiguous range? Yes.
- Monotone? Yes — distinct-character count can only stay the same or increase as the window grows.
- State?
freq: char → int. - Shrink rule? While
len(freq) > k. - When to record? After the shrink — window is just-barely valid.
Code
Time: O(n). Space: O(k).
Don’t forget to delete the map entry when the count hits zero. If you leave freq['a'] = 0 in the map, len(freq) keeps counting it as a distinct character, and the algorithm thinks the window has more distinct chars than it really does. Either delete the entry on zero, or check freq[c] > 0 when computing distinctness.
A special case: K = 2 is Fruit Into Baskets
You walk through a row of fruit trees. You can carry only two types of fruit. Starting from any tree, how many fruits can you collect?
That’s literally lengthOfLongestSubstringKDistinct(fruits, 2). Different domain, identical algorithm.
Analysis
- Time:
O(n). - Space:
O(k).
Same skin
- Fruit Into Baskets — K = 2.
- Longest Substring with At Most Two Distinct Characters — K = 2 again, same algorithm.
- Subarrays with K Different Integers — uses the at-most-K trick:
atMost(k) − atMost(k − 1). - Replace the Substring for Balanced String — inverted variant; find the smallest window such that outside the window, the character distribution is balanced.