2Brute2Best
🔥0
05

Exactly K (Sliding Window Sub-pattern)

Count subarrays with exactly K of something. Direct windows fail, so compute atMost(K) − atMost(K − 1).

Signals in the problem statement
  • ›

    "exactly k distinct"

  • ›

    "exactly k odd numbers"

  • ›

    "sum equals goal" on a 0/1 array

What makes it different

Not monotonic on its own. Turning it into two monotonic counts is the whole trick.

Questions

ordered from “learn the idea” to “recognise it without help”
  1. 1
    Binary Subarrays With Sum
    Basic Anchor·LeetCode #930
    Medium
  2. 2
    Count Number of Nice Subarrays
    Basic Reinforcement·LeetCode #1248
    Medium
  3. 3
    Subarrays with K Different Integers
    Slight Variation·LeetCode #992
    Hard
  4. 4
    Count Subarrays With Fixed Bounds
    Tricky / Edge Case·LeetCode #2444
    Hard

Template

atmost-template.cpp
// Count subarrays satisfying an "at most" rule.
// For a fixed right end, every start in [left..right] is valid.
long long countAtMost(vector<int>& a, int k) {
    if (k < 0) return 0;                  // "at most -1" is impossible (use k <= 0 for distinct counts)
    long long count = 0;
    int left = 0;
    for (int right = 0; right < (int)a.size(); right++) {
        add(a[right]);
        while (!valid(k)) { remove(a[left]); left++; }
        count += right - left + 1;        // subarrays ending at right
    }
    return count;
}

// "Exactly K" is not monotonic, so use two "at most" counts:
long long countExactly(vector<int>& a, int k) {
    return countAtMost(a, k) - countAtMost(a, k - 1);
}
Remember this · Sliding Window
Trigger
Contiguous subarray / substring + longest, shortest, maximum, count, or "of size K".
Think
Can I keep a valid range and move it, instead of checking every subarray from scratch?
Key question
When is my current window valid?