Return the number of non-empty substrings of s that contain at most k
distinct characters.
countAtMostKDistinct(s, k)
Input format: s | k.
s="abc", k=2 // → 5 (a, b, c, ab, bc)
s="aa", k=1 // → 3 (a, a, aa)
s="abc", k=0 // → 0
You need to count every substring with at most k distinct characters. Checking each substring directly and counting distinct characters from scratch is O(n²) substrings — wasteful since consecutive candidates overlap almost entirely.
For a fixed ending position, growing the substring leftward only ever keeps the distinct count the same or grows it — never shrinks. Equivalently, shrinking from the left only keeps it the same or decreases it. That monotonic relationship is what makes a two-pointer window valid: there's a clean boundary left where everything from left to right has at most k distinct characters.
Maintain a running frequency map. When a new character pushes the distinct count above k, shrink from the left — decrement, delete if zero, advance — until the count is k or fewer.
Once [left, right] is valid, every substring ending at right and starting anywhere from left to right is also valid, since starting further right only removes characters and can't increase distinctness. Count them all at once: there are right - left + 1 of them.
s[right], updating the map.right - left + 1 to the running total.right.Both pointers move forward monotonically — O(n) total. The batch count (right - left + 1) replaces an O(n) inner enumeration, collapsing total work from O(n²) to O(n).
def count_at_most_k_distinct(s, k):
count = {}
left = 0
total = 0
for right in range(len(s)):
count[s[right]] = count.get(s[right], 0) + 1
while len(count) > k:
count[s[left]] -= 1
if count[s[left]] == 0:
del count[s[left]]
left += 1
total += right - left + 1
return total
Sign in to join the discussion.
No comments yet. Be the first to ask a question.
Press Run to execute your code, or Submit to test and complete this problem.