Algorithm

Subarrays with K Different Integers

Sliding Window Pattern

Subarrays with K Different Integers

Given an integer array nums and an integer k, return the number of good subarrays of nums. A good subarray is a subarray where the number of different integers in that subarray is exactly k.

CONSTRAINTS
  • 1 <= nums.length <= 2 × 10⁴
  • 1 <= nums[i], k <= nums.length
EXAMPLE 1
Input: nums = [1,2,1,2,3], k = 2
Output: 7
Subarrays with exactly 2 distinct integers: [1,2], [2,1], [1,2], [2,3], [1,2,1], [2,1,2], [1,2,1,2]. atMost(2)=12, atMost(1)=5, 12-5=7.
EXAMPLE 2
Input: nums = [1,2,1,3,4], k = 3
Output: 3
Subarrays with exactly 3 distinct integers: [1,2,1,3], [2,1,3], [1,3,4]. atMost(3)-atMost(2)=3.
EXAMPLE 3
Input: nums = [1,1,1,1], k = 1
Output: 10
All N*(N+1)/2 = 10 subarrays contain exactly 1 distinct integer. atMost(1) = 10, atMost(0) = 0, difference = 10.
Does 'exactly K distinct' mean no more and no fewer than K different values?
Correct. A subarray with 1 or 3 distinct values does not count when K=2. Exactly K means precisely K distinct integers.
Can a single element count as a valid subarray?
Yes. A single element has exactly 1 distinct integer. It counts when K=1.

Count the contiguous subarrays that hold exactly k distinct integers. Two things make this harder than the windows before it: we must count all of them (not find one best), and the condition is "exactly", which — as flagged back in Longest Substring Without Repeating Characters — is the case where the plain sliding window breaks.

Why "exactly k" won't drive a window

A window works only when the rule is one-directional at the edges. "At most k distinct" is: adding a new value can only raise the distinct-count (toward invalid), removing on the left can only lower it (toward valid) — clean, one-directional, exactly the Fruit Into Baskets rule with a general k. But "exactly k" is not: extending right might keep you at k or jump to k+1, and shrinking might keep you at k or drop to k−1. There is no single left position where the window becomes valid, so left has nowhere fixed to sit. The brute force that recounts distinct values for every subarray is O(N²) and too slow for 2 × 10⁴.

Turn "exactly" into a subtraction of two "at most"s

Here is the trick that rescues it. Let atMost(x) = the number of subarrays with at most x distinct integers. Then:

Key Insightexactly(k) = atMost(k) − atMost(k−1). Subarrays with at most k distinct, minus those with at most k−1 distinct, leaves precisely those with k − and atMost is a monotonic, windowable quantity.
Counting "at most x" in one pass

Run the at-most-x-distinct window (the Fruit Into Baskets machine with 2 replaced by x). The counting step is the new idea: when the window [left..right] is valid, it contributes right - left + 1 new subarrays — namely every subarray that ends at right, since each start from left to right gives a valid window, and any start before left would exceed x distinct. Summing that over all right counts every at-most-x subarray exactly once.

python
def subarraysWithKDistinct(nums, k):
    def at_most(x):
        count = 0
        left = 0
        freq = {}
        for right in range(len(nums)):
            freq[nums[right]] = freq.get(nums[right], 0) + 1
            while len(freq) > x:
                freq[nums[left]] -= 1
                if freq[nums[left]] == 0:
                    del freq[nums[left]]
                left += 1
            count += right - left + 1     # subarrays ending at right with <= x distinct
        return count
    return at_most(k) - at_most(k - 1)
Crucial Notecount += right - left + 1 is the whole counting insight in one line. It works because within a valid at-most-x window every suffix ending at right is itself valid — so the window's width equals the number of fresh subarrays this step adds.
Worked Example:nums = [1, 2, 1], k = 2
atMost(2): right=0 [1] adds 1; right=1 [1,2] adds 2; right=2 [1,2,1] (still 2 distinct) adds 3 → total 6.
atMost(1): right=0 [1] adds 1; right=1 forces left to 1, [2] adds 1; right=2 forces left to 2, [1] adds 1 → total 3.
exactly(2) = 6 − 3 = 3 — the subarrays [1,2], [2,1], and [1,2,1].
How it maps onto the pattern

The window itself is unchanged from Fruit Into Baskets — same at-most-x-distinct machine, slots (a) invalid = more than x distinct, (b)/(c) tally in and out with delete-at-zero. What is new sits around it: the count += width trick to total subarrays, and the atMost(k) − atMost(k−1) reduction to handle an "exactly" condition a window cannot chase directly. Bank both — "count subarrays with exactly k of something" almost always means: count at-most-k, count at-most-(k−1), subtract; and "number of valid subarrays ending here" is the window width. The same recipe converts "exactly k odd numbers", "exactly k distinct", and similar counting variants into two runs of a monotone window.

Interactive Strategy Visualization

K Different Integers

k=2 Exact
Set Difference Trick
1
0
2
1
1
2
2
3
3
4
At Most 2 Count
1
O(N²) Brute Force
O(N) Difference of Two atMost Windows