Sale: Get 60% Off on all Pro Plans. Buy Now

Longest Substring with At Most K Distinct Characters

Problem

Given a string s and an integer k, return the length of the longest substring of s that contains at most k distinct characters.

  • 0 ≤ k ≤ 10⁵
  • 0 ≤ s.length ≤ 10⁵
  • s consists of ASCII characters

Example

Input: s = "eceba", k = 2
Output: 3

The longest substring with at most 2 distinct characters is "ece", which has length 3. The algorithm uses a sliding window to track character counts. Starting with the first character 'e', it expands the window to include 'c' and 'e' again, maintaining at most 2 distinct characters. When adding 'b' would exceed the limit, it shrinks the window from the left until the distinct count is back to 2. The maximum window length recorded during this process is 3.

Approach

Straightforward Solution

A brute-force approach would check every substring and count distinct characters, resulting in O(n^2) time complexity, which is inefficient for large inputs.

Core Observation

The problem requires finding the longest contiguous substring with a constraint on the number of distinct characters. This naturally suggests a sliding window approach that dynamically adjusts its boundaries to maintain the constraint.

Path to Optimal

Preview

The key insight is to use two pointers to represent a window and a hash map (or dictionary) to count characters within the window. Expand the right pointer to include new characters and update counts…

Full step-by-step walkthrough on Pro

Optimal Approach

Preview

Use a sliding window with two pointers and a dictionary to track character counts. Expand the right pointer to add characters, and shrink from the left when distinct characters exceed k…

Full step-by-step walkthrough on Pro

Want the full reasoning chain?

Unlock the complete walkthrough, line-by-line analysis, and recall drill.

Unlock Pro

Time

O(n)

Each character is visited at most twice: once when the right pointer expands the window and once when the left pointer shrinks it, resulting in linear time.

Space

O(k)

The dictionary stores counts of at most k distinct characters at any time, so space scales with k, which is at most the size of the input alphabet or k.

Pattern Spotlight

Sliding Window (Variable Size with Frequency Map)

Maintain a window that satisfies the problem's constraint by expanding the right pointer and contracting the left pointer only when the constraint is violated, using a frequency map to efficiently track the window's state.

Solution

Python
1class Solution:
2 def lengthOfLongestSubstringKDistinct(self, s: str, k: int) -> int:
3 if k <= 0 or not s:
4 return 0
5
6 counts = {}
7 left = 0
8 res = 0
9
10 for right, ch in enumerate(s):
11 counts[ch] = counts.get(ch, 0) + 1
12
13 while len(counts) > k:
14 left_ch = s[left]
15 counts[left_ch] -= 1
16 if counts[left_ch] == 0:
17 del counts[left_ch]
18 left += 1
19
20 res = max(res, right - left + 1)
21
22 return res

Step-by-Step Solution

1

Validate Input and Handle Edge Cases

3if k <= 0 or not s:
4 return 0

Objective

To immediately return 0 if k is zero or the input string is empty, as no valid substring can exist.

Key Insight

Checking for trivial or invalid inputs upfront prevents unnecessary computation and handles edge cases cleanly. If k is zero, no characters are allowed, so the longest substring length is zero. Similarly, an empty string has no substrings.

Interview Quick-Check

State & Boundaries

Return 0 immediately if k <= 0 or s is empty, as no valid substring can exist.

Common Pitfalls & Bugs

Failing to handle k=0 or empty string inputs can cause incorrect results or runtime errors.

2

Initialize Sliding Window State

To initialize the frequency map, left pointer, and result accumulator before scanning.

3

Expand Sliding Window and Track Character Frequencies

To iterate through the string with a right pointer, updating character counts and expanding the window.

4

Shrink Window to Maintain At Most K Distinct Characters

To move the left pointer forward while the window contains more than k distinct characters, updating counts accordingly.

5

Update Maximum Length of Valid Substring

To record the maximum window size seen so far that satisfies the constraint.

6

Return the Length of the Longest Valid Substring

To return the maximum length found after processing the entire string.

5 more steps with full analysis available on Pro.

Line Analysis

This solution has 3 Critical lines interviewers watch for.

Line 13 Critical
while len(counts) > k:

While the window has more than k distinct characters, shrink it from the left.

This loop restores the invariant that the window contains at most k distinct characters by shrinking from the left until len(counts) <= k.

Line 16 Critical
if counts[left_ch] == 0:

Check whether the leftmost character has fully left the window.

A character stops contributing to the distinct count only when its frequency becomes zero, so this check is required for correctness.

Line 17 Critical
del counts[left_ch]

Remove the character from the map when its count reaches zero.

Deleting the zero-count key ensures len(counts) equals the true number of distinct characters, allowing the while condition to terminate correctly.

Full line-by-line criticality + rationale for all 15 lines available on Pro.

Test Your Understanding

Why does shrinking the window from the left guarantee that the substring will again satisfy the 'at most k distinct characters' constraint?

See the answer with Pro.

Related Problems

Sliding Window pattern

Don't just read it. Drill it.

Reconstruct Longest Substring with At Most K Distinct Characters from memory until it sticks. AlgoDrill blanks out key lines and makes you fill them back in, step by step.

Unlock the Longest Substring with At Most K Distinct Characters drill

or drill a free problem