Optimal: two at-most windows
Time O(n) Space O(n)atMost(k): grow right, shrink while the distinct count exceeds k, and add right − left + 1 (every subarray ending at right that starts in the window). Answer = atMost(k) − atMost(k − 1).
import java.util.HashMap;
import java.util.Map;
class Solution {
public int subarraysWithKDistinct(int[] nums, int k) {
return atMost(nums, k) - atMost(nums, k - 1);
}
private int atMost(int[] nums, int k) {
Map<Integer, Integer> count = new HashMap<>();
int left = 0, total = 0;
for (int right = 0; right < nums.length; right++) {
count.merge(nums[right], 1, Integer::sum);
while (count.size() > k) {
int out = nums[left++];
if (count.merge(out, -1, Integer::sum) == 0) count.remove(out);
}
total += right - left + 1;
}
return total;
}
}Verdict: Two linear passes.