
About the author
Mallikarjuna Mallisetty
General programming
Mallikarjuna shares practical programming tutorials and foundational concepts designed to help developers learn by building and experimenting.
View LinkedIn profile ↗from collections import defaultdict
def subarrays_with_k_distinct(nums, k):
def at_most_k(nums, k):
count = defaultdict(int)
left = 0
result = 0
distinct = 0
for right in range(len(nums)):
if count[nums[right]] == 0:
distinct += 1
count[nums[right]] += 1
while distinct > k:
count[nums[left]] -= 1
if count[nums[left]] == 0:
distinct -= 1
left += 1
result += right - left + 1
return result
return at_most_k(nums, k) - at_most_k(nums, k - 1)
# Example
nums = [1, 2, 1, 2, 3]
k = 2
print(subarrays_with_k_distinct(nums, k)) # Output: 7| Case | Time Complexity | Explanation |
|---|---|---|
| Best Case | O(n) | In the best case, each element is processed at most twice — once when the right pointer includes it in the window, and possibly once when the left pointer excludes it. Thus, the algorithm runs in linear time with respect to the number of elements. |
| Average Case | O(n) | On average, the sliding window advances both pointers across the array, and each element is added and removed from the frequency map at most once per distinct value of k. Hence, total work is proportional to n. |
| Worst Case | O(n) | Even in the worst case — when the number of distinct elements is close to n — each element is still added and removed from the frequency map in amortized constant time. Therefore, total time complexity remains O(n). |