from collections import defaultdict
class Solution:
def subarraysWithKDistinct(self, nums, k):
def atMostK(nums, k):
count = defaultdict(int)
res = left = 0
for right, num in enumerate(nums):
if count[num] == 0:
k -= 1
count[num] += 1
while k < 0:
count[nums[left]] -= 1
if count[nums[left]] == 0:
k += 1
left += 1
res += right - left + 1
return res
return atMostK(nums, k) - atMostK(nums, k-1)
#include <vector>
#include <unordered_map>
using namespace std;
class Solution {
public:
int subarraysWithKDistinct(vector<int>& nums, int k) {
return atMostK(nums, k) - atMostK(nums, k - 1);
}
private:
int atMostK(vector<int>& nums, int k) {
unordered_map<int, int> count;
int left = 0, res = 0;
for (int right = 0; right < nums.size(); ++right) {
if (count[nums[right]] == 0) --k;
++count[nums[right]];
while (k < 0) {
--count[nums[left]];
if (count[nums[left]] == 0) ++k;
++left;
}
res += right - left + 1;
}
return res;
}
};
import java.util.*;
class Solution {
public int subarraysWithKDistinct(int[] nums, int k) {
return atMostK(nums, k) - atMostK(nums, k - 1);
}
private int atMostK(int[] nums, int k) {
Map<Integer, Integer> count = new HashMap<>();
int res = 0, left = 0;
for (int right = 0; right < nums.length; ++right) {
count.put(nums[right], count.getOrDefault(nums[right], 0) + 1);
if (count.get(nums[right]) == 1) k--;
while (k < 0) {
count.put(nums[left], count.get(nums[left]) - 1);
if (count.get(nums[left]) == 0) k++;
left++;
}
res += right - left + 1;
}
return res;
}
}
var subarraysWithKDistinct = function(nums, k) {
function atMostK(nums, k) {
let count = new Map();
let res = 0, left = 0;
for (let right = 0; right < nums.length; ++right) {
count.set(nums[right], (count.get(nums[right]) || 0) + 1);
if (count.get(nums[right]) === 1) k--;
while (k < 0) {
count.set(nums[left], count.get(nums[left]) - 1);
if (count.get(nums[left]) === 0) k++;
left++;
}
res += right - left + 1;
}
return res;
}
return atMostK(nums, k) - atMostK(nums, k - 1);
};
Given an integer array nums
and an integer k
, your task is to find the number of contiguous subarrays in nums
that contain exactly k
different integers.
Key constraints:
k
distinct integers.nums
can be reused in multiple subarrays.k
is within the range of the number of unique elements in nums
.
The brute-force way to solve this problem is to consider every possible subarray of nums
, count how many distinct numbers it contains, and increment our answer if that count is exactly k
.
However, this approach is inefficient for large arrays because checking all subarrays is slow. Instead, we look for ways to optimize. By observing that the problem is about contiguous subarrays and the number of distinct elements, we can use a sliding window technique to efficiently count subarrays with at most k
distinct elements.
The main insight is that the number of subarrays with exactly k
distinct elements equals the number of subarrays with at most k
distinct elements minus the number with at most k-1
distinct elements.
left
and right
) to maintain a window of elements. As you expand right
, keep track of the count of each number in the current window using a hash map (or dictionary).
k
by 1. If k
becomes negative, shrink the window from the left until you have at most k
distinct numbers again.
right
is right - left + 1
.
atMostK(nums, k) - atMostK(nums, k-1)
, which counts subarrays with exactly k
distinct elements.
atMostK(nums, k)
counts all subarrays with up to k
distinct elements. Subtracting atMostK(nums, k-1)
removes those with fewer than k
distinct elements, leaving only those with exactly k
.
Let's use nums = [1, 2, 1, 2, 3]
and k = 2
.
atMostK(nums, 2)
:
atMostK(nums, 1)
:
The solution efficiently counts valid subarrays by expanding and shrinking the window as needed, without checking all possible subarrays individually.
k
unique elements are tracked at any time.
This problem can be efficiently solved using a sliding window and hash map to count subarrays with at most k
and k-1
distinct elements. The key insight is that the difference between these two counts gives us the number of subarrays with exactly k
different integers. This approach is both efficient and elegant, transforming a potentially slow brute-force problem into a linear-time solution.