Subarrays with K Different Integers
Description:â
Given an integer array nums and an integer k, return the number of good subarrays of nums.
A good array is an array where the number of different integers in that array is exactly k.
- For example,
[1,2,3,1,2]has3different integers:1,2, and3.
A subarray is a contiguous part of an array.
Example 1:
Input: nums = [1,2,1,2,3], k = 2
Output: 7
Explanation: Subarrays formed with exactly 2 different integers: [1,2], [2,1], [1,2], [2,3], [1,2,1], [2,1,2], [1,2,1,2]
Example 2:
Input: nums = [1,2,1,3,4], k = 3
Output: 3
Explanation: Subarrays formed with exactly 3 different integers: [1,2,1,3], [2,1,3], [1,3,4].
Approaches:â
1. Sliding Windowâ
To find the number of subarrays with exactly different integers directly can be complex. Instead, we can use a clever sliding window technique: The number of subarrays with exactly different integers is equal to the number of subarrays with at most different integers minus the number of subarrays with at most different integers.
- Create a helper function
atMost(k)that calculates the number of subarrays with at mostkdistinct elements. - In the helper function, maintain a sliding window
[left, right]and a frequency map to keep track of the count of each element in the current window. - Expand the window by moving
rightand adding elements to the frequency map. - If the number of distinct elements exceeds
k, shrink the window from the left by movingleftand updating the frequency map until the number of distinct elements is valid again. - For every valid window ending at
right, the number of valid subarrays ending atrightisright - left + 1. Add this to the total count. - Finally, return the result of
atMost(k) - atMost(k - 1).
- Time Complexity: where is the number of elements in
nums. Both theleftandrightpointers traverse the array at most once in theatMosthelper function. - Space Complexity: in the worst-case scenario to store the frequencies of the elements in a hash map.
Solutions:â
C++
class Solution {
public:
int subarraysWithKDistinct(vector<int>& nums, int k) {
return atMost(nums, k) - atMost(nums, k - 1);
}
private:
int atMost(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--;
}
while (k < 0) {
if (--count[nums[left]] == 0) {
k++;
}
left++;
}
res += right - left + 1;
}
return res;
}
};
Java
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, res = 0;
for (int right = 0; right < nums.length; right++) {
if (count.getOrDefault(nums[right], 0) == 0) {
k--;
}
count.put(nums[right], count.getOrDefault(nums[right], 0) + 1);
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;
}
}
Python
class Solution:
def subarraysWithKDistinct(self, nums: List[int], k: int) -> int:
return self.atMost(nums, k) - self.atMost(nums, k - 1)
def atMost(self, nums: List[int], k: int) -> int:
count = collections.Counter()
left = 0
res = 0
for right in range(len(nums)):
if count[nums[right]] == 0:
k -= 1
count[nums[right]] += 1
while k < 0:
count[nums[left]] -= 1
if count[nums[left]] == 0:
k += 1
left += 1
res += right - left + 1
return res
JavaScript
/**
* @param {number[]} nums
* @param {number} k
* @return {number}
*/
const subarraysWithKDistinct = function(nums, k) {
const atMost = (k) => {
const count = new Map();
let left = 0;
let res = 0;
for (let right = 0; right < nums.length; right++) {
if (!count.has(nums[right]) || count.get(nums[right]) === 0) {
k--;
}
count.set(nums[right], (count.get(nums[right]) || 0) + 1);
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 atMost(k) - atMost(k - 1);
};
Completed working through this block? Sync progress to workspace.