Lesson 7.4 · Sliding Window
Windows with Counts and the "At Most K" Trick
Keep a count map of what's inside the window, track how many requirements are met, and turn "exactly K" into "at most K" minus "at most K − 1".
15 min
Think of it like this
A cashier's tray with a slot per coin type. As coins enter and leave the window you adjust each slot, and you keep one extra note: how many coin types currently meet the order's requirement, so you never need to check every slot.
1.Count maps and a "satisfied" counter
For problems like "smallest window containing all letters of t", keep need[c] (from t) and have[c] (in the window). Maintain formed, the number of letters whose have has reached need. Update it only when a count crosses the requirement, so validity checks are O(1).
2.Exactly K = at most K − at most (K − 1)
Counting subarrays with exactly K distinct values is awkward for a window: adding an element can keep the count at K, so you don't know when to shrink. But counting subarrays with at most K distinct values is easy: for each right, every window from left to right is valid, adding right − left + 1 subarrays.
Subarrays with exactly K = (at most K) − (at most K − 1). Two simple windows replace one hard one.
import java.util.HashMap;
import java.util.Map;
public class Main {
static int atMost(int[] a, int k) {
Map<Integer, Integer> count = new HashMap<>();
int left = 0, total = 0;
for (int right = 0; right < a.length; right++) {
count.merge(a[right], 1, Integer::sum);
while (count.size() > k) {
int out = a[left++];
if (count.merge(out, -1, Integer::sum) == 0) count.remove(out);
}
total += right - left + 1; // all windows ending at right
}
return total;
}
public static void main(String[] args) {
int[] a = {1, 2, 1, 2, 3};
System.out.println("at most 2: " + atMost(a, 2));
System.out.println("exactly 2: " + (atMost(a, 2) - atMost(a, 1)));
}
}Output
at most 2: 12
exactly 2: 7Remember
- Track a
formed/satisfiedcounter so validity is O(1). - Remove keys whose count drops to 0 when the map's size matters.
- Exactly K = atMost(K) − atMost(K − 1).
Common mistakes
- Leaving zero-count keys in the map, so
size()overcounts distinct values. - Trying to count "exactly K" with a single window.