Problem Statement: Solution: import java.util.HashMap; class Solution { public int subarraysWithKDistinct(int[] nums, int k) { /* * atMostKDistinct(nums, k): * Counts the number of subarrays with at most k distinct integers. * This includes subarrays with 0, 1, 2, ..., up to k distinct integers. * * atMostKDistinct(nums, k-1): * Counts the number of subarrays with at most k-1 distinct integers. * This includes subarrays with 0, 1, 2, ..., up to k-1 distinct integers. ---------------------------------------------------------------------------------------------------- * exactlyKDistinct(nums, k) = atMostKDistinct(nums, k) - atMostKDistinct(nums, k-1) */ return atMostKDistinct(nums, k) - atMostKDistinct(nums, k - 1); } private int atMostKDistinct(int[] nums, int k) { HashMap<Integer, Integer> fMap = new HashMap<>(); int start = 0; int end = 0; int count = 0; /* * The idea is to keep expanding the right boundary of the window till the count * of distinct elements in the window is less than or equal to K and * when the count of distinct elements inside the window becomes more than K, * start shrinking the window from the left till the count becomes less than or equal * to K. * Also for every expansion, keep counting the subarrays as `end – start + 1` * where right and left are the boundaries of the current window. */ while (end < nums.length) { // Add the current number to the frequency map fMap.put(nums[end], fMap.getOrDefault(nums[end], 0) + 1); // If the map size exceeds k, we need to shrink the window while (fMap.size() > k) { fMap.put(nums[start], fMap.get(nums[start]) - 1); if (fMap.get(nums[start]) == 0) { fMap.remove(nums[start]); } start++; } // The number of subarrays with at most k distinct elements // ending at the current 'end' index is (end - start + 1) if (fMap.size() <= k) { // btw we don't need this condition, it's just for clarity int windowSize = end - start + 1; count += windowSize; } // Move the end pointer to the right end++; } return count; } }