Open In App

Count Subarrays With Exactly K Distinct Elements

Last Updated : 08 Jan, 2025
Summarize
Comments
Improve
Suggest changes
Share
Like Article
Like
Report

Given an array arr[] and an integer k, the task is to find the count of subarrays such that each subarray has exactly k distinct elements.

Examples:

Input: arr[] = [1, 2, 2, 3], k = 2 
Output:
Explanation: Subarrays with exactly 2 distinct elements are: [1, 2], [1, 2, 2] and [2, 3].

Input: arr[] = [3, 1, 2, 2, 3], k = 3 
Output: 4
Explanation: Subarrays with exactly 3 distinct elements are: [3, 1, 2], [3, 1, 2, 2], [3, 1, 2, 2, 3] and [1, 2, 2, 3].

Input: arr[] = [1, 1, 1, 1], k = 2
Output: 0
Explanation: There is no subarray having exactly 2 distinct integers.

[Naive Approach] Exploring all subarrays - O(n^2) Time and O(n) Space

The idea is to iterate over all possible subarrays while keeping the count of distinct integers using a hash set. For every subarray, check if the size of hash set is equal to k. If the size of hash set equals k, increment the result by 1. After iterating over all subarrays, return the result.

C++
// C++ Code to count the subarrays having exactly
// k distinct elements by exploring all subarrays

#include <iostream>
#include <unordered_set>
#include <vector>
using namespace std;

int exactlyK(vector<int> &arr, int k) {
    int n = arr.size();
    int res = 0;

    // Iterate over all subarrays arr[i...j]
    for (int i = 0; i < n; i++) {

        // hash set to count distinct elements
        unordered_set<int> st;

        for (int j = i; j < n; j++) {
            st.insert(arr[j]);

            // If count of distinct elements > k, then
            // don't extend the subarray further
            if (st.size() > k)
                break;
            if (st.size() == k)
                res += 1;
        }
    }
    return res;
}

int main() {
    vector<int> arr = {1, 2, 2, 3};
    int k = 2;
    cout << exactlyK(arr, k);
}
Java
// Java Code to count the subarrays having exactly
// k distinct elements by exploring all subarrays

import java.util.HashSet;

class GfG {
    static int exactlyK(int[] arr, int k) {
        int n = arr.length;
        int res = 0;

        // Iterate over all subarrays arr[i...j]
        for (int i = 0; i < n; i++) {

            // Hash set to count distinct elements
            HashSet<Integer> st = new HashSet<>();

            for (int j = i; j < n; j++) {
                st.add(arr[j]);

                // If count of distinct elements > k, then
                // don't extend the subarray further
                if (st.size() > k)
                    break;
                if (st.size() == k)
                    res += 1;
            }
        }
        return res;
    }

    public static void main(String[] args) {
        int[] arr = {1, 2, 2, 3};
        int k = 2;
        System.out.println(exactlyK(arr, k));
    }
}
Python
# Python Code to count the subarrays having exactly
# k distinct elements by exploring all subarrays

def exactlyK(arr, k):
    n = len(arr)
    res = 0

    # Iterate over all subarrays arr[i...j]
    for i in range(n):

        # Set to count distinct elements
        st = set()

        for j in range(i, n):
            st.add(arr[j])

            # If count of distinct elements > k, then
            # don't extend the subarray further
            if len(st) > k:
                break
            if len(st) == k:
                res += 1

    return res

if __name__ == "__main__":
	arr = [1, 2, 2, 3]
	k = 2
	print(exactlyK(arr, k))
C#
// C# Code to count the subarrays having exactly
// k distinct elements by exploring all subarrays

using System;
using System.Collections.Generic;

class GfG {
    static int ExactlyK(int[] arr, int k) {
        int n = arr.Length;
        int res = 0;

        // Iterate over all subarrays arr[i...j]
        for (int i = 0; i < n; i++) {

            // HashSet to count distinct elements
            HashSet<int> st = new HashSet<int>();

            for (int j = i; j < n; j++) {
                st.Add(arr[j]);

                // If count of distinct elements > k, then
                // don't extend the subarray further
                if (st.Count > k)
                    break;
                if (st.Count == k)
                    res += 1;
            }
        }
        return res;
    }

    static void Main() {
        int[] arr = { 1, 2, 2, 3 };
        int k = 2;
        Console.WriteLine(ExactlyK(arr, k));
    }
}
JavaScript
// JavaScript Code to count the subarrays having exactly
// k distinct elements by exploring all subarrays

function exactlyK(arr, k) {
    let n = arr.length;
    let res = 0;

    // Iterate over all subarrays arr[i...j]
    for (let i = 0; i < n; i++) {

        // Set to count distinct elements
        let st = new Set();

        for (let j = i; j < n; j++) {
            st.add(arr[j]);

            // If count of distinct elements > k, then
            // don't extend the subarray further
            if (st.size > k)
                break;
            if (st.size === k)
                res += 1;
        }
    }
    return res;
}

// Driver Code
let arr = [1, 2, 2, 3];
let k = 2;
console.log(exactlyK(arr, k));

Output
4

[Expected Approach] Using Sliding Window Technique - O(n) Time and O(n) Space

The idea is similar to the problem Count Subarrays With At Most K Distinct Elements. To find the number of subarrays with exactly k distinct elements, we can use the formula: exactly(k) = atMost(k) - atMost(k - 1).

Count of subarrays with at most k different elements can be easily calculated using sliding window technique. Initialize left = 0 and right = 0 to mark the boundaries of sliding window. Expand the right boundary until distinct element count exceeds k, then shrink the left boundary until the distinct element count becomes <= k. While expanding the window, for each right boundary keep counting the subarrays as (right - left + 1).

The intuition behind (right - left + 1) is that it counts all possible subarrays that end at right and start at any index between left and right. These are valid subarrays because they all contain at most k distinct elements.

C++
// C++ Code to count the subarrays having exactly
// k distinct elements by exploring all subarrays

#include <iostream>
#include <unordered_map>
#include <vector>
using namespace std;

int atMostK(vector<int> &arr, int k) {
    int n = arr.size();
    int res = 0;

    // pointers to mark the left and right boundary
    int left = 0, right = 0;

    // Frequency map
    unordered_map<int, int> freq;
    while (right < n) {
        freq[arr[right]] += 1;

        // If this is a new element in the window,
        // decrement k by 1
        if (freq[arr[right]] == 1)
            k -= 1;

        // Shrink the window until distinct element
        // count becomes <= k
        while (k < 0) {
            freq[arr[left]] -= 1;
            if (freq[arr[left]] == 0)
                k += 1;
            left += 1;
        }

        // add all possible subarrays to result
        res += (right - left + 1);
        right += 1;
    }
    return res;
}

int exactlyK(vector<int> &arr, int k) {
    return atMostK(arr, k) - atMostK(arr, k - 1);
}

int main() {
    vector<int> arr = {1, 2, 2, 3};
    int k = 2;
    cout << exactlyK(arr, k);
}
Java
// Java Code to count the subarrays having exactly
// k distinct elements by exploring all subarrays

import java.util.HashMap;
import java.util.Map;

class GfG {

    // Function to count subarrays having at most k distinct elements
    static int atMostK(int[] arr, int k) {
        int n = arr.length;
        int res = 0;

        // pointers to mark the left and right boundary
        int left = 0, right = 0;

        // Frequency map
        Map<Integer, Integer> freq = new HashMap<>();
        while (right < n) {
            freq.put(arr[right], freq.getOrDefault(arr[right], 0) + 1);

            // If this is a new element in the window, 
            // decrement k by 1
            if (freq.get(arr[right]) == 1)
                k -= 1;

            // Shrink the window until distinct element
            // count becomes <= k
            while (k < 0) {
                freq.put(arr[left], freq.get(arr[left]) - 1);
                if (freq.get(arr[left]) == 0)
                    k += 1;
                left += 1;
            }

            // add all possible subarrays to result
            res += (right - left + 1);
            right += 1;
        }
        return res;
    }

    // Function to count subarrays having exactly k distinct elements
    static int exactlyK(int[] arr, int k) {
        return atMostK(arr, k) - atMostK(arr, k - 1);
    }

    public static void main(String[] args) {
        int[] arr = {1, 2, 2, 3};
        int k = 2;
        System.out.println(exactlyK(arr, k));
    }
}
Python
# Python Code to count the subarrays having exactly
# k distinct elements by exploring all subarrays

from collections import defaultdict

def atMostK(arr, k):
    n = len(arr)
    res = 0

    # pointers to mark the left and right boundary
    left, right = 0, 0

    # Frequency map
    freq = defaultdict(int)
    while right < n:
        freq[arr[right]] += 1

        # If this is a new element in the window,
        # decrement k by 1
        if freq[arr[right]] == 1:
            k -= 1

        # Shrink the window until distinct element
        # count becomes <= k
        while k < 0:
            freq[arr[left]] -= 1
            if freq[arr[left]] == 0:
                k += 1
            left += 1

        # add all possible subarrays to result
        res += (right - left + 1)
        right += 1
    return res

# Function to count subarrays having exactly k distinct elements
def exactlyK(arr, k):
    return atMostK(arr, k) - atMostK(arr, k - 1)


if __name__ == "__main__":
    arr = [1, 2, 2, 3]
    k = 2
    print(exactlyK(arr, k))
C#
// C# Code to count the subarrays having exactly
// k distinct elements by exploring all subarrays

using System;
using System.Collections.Generic;

class GfG {
    static int atMostK(int[] arr, int k) {
        int n = arr.Length;
        int res = 0;

        // pointers to mark the left and right boundary
        int left = 0, right = 0;

        // Frequency map
        Dictionary<int, int> freq = new Dictionary<int, int>();
        while (right < n) {
            if (freq.ContainsKey(arr[right]))
                freq[arr[right]] += 1;
            else
                freq[arr[right]] = 1;

            // If this is a new element in the window,
            // decrement k by 1
            if (freq[arr[right]] == 1)
                k -= 1;

            // Shrink the window until distinct element
            // count becomes <= k
            while (k < 0) {
                freq[arr[left]] -= 1;
                if (freq[arr[left]] == 0)
                    k += 1;
                left += 1;
            }

            // add all possible subarrays to result
            res += (right - left + 1);
            right += 1;
        }
        return res;
    }

    // Function to count subarrays having exactly k distinct elements
    static int exactlyK(int[] arr, int k) {
        return atMostK(arr, k) - atMostK(arr, k - 1);
    }

    static void Main(string[] args) {
        int[] arr = { 1, 2, 2, 3 };
        int k = 2;
        Console.WriteLine(exactlyK(arr, k));
    }
}
JavaScript
// JavaScript Code to count the subarrays having exactly
// k distinct elements by exploring all subarrays

function atMostK(arr, k) {
    let n = arr.length;
    let res = 0;

    // pointers to mark the left and right boundary
    let left = 0, right = 0;

    // Frequency map
    let freq = new Map();
    while (right < n) {
        freq.set(arr[right], (freq.get(arr[right]) || 0) + 1);

        // If this is a new element in the window, 
        // decrement k by 1
        if (freq.get(arr[right]) === 1)
            k -= 1;

        // Shrink the window until distinct element
        // count becomes <= k
        while (k < 0) {
            freq.set(arr[left], freq.get(arr[left]) - 1);
            if (freq.get(arr[left]) === 0)
                k += 1;
            left += 1;
        }

        // add all possible subarrays to result
        res += (right - left + 1);
        right += 1;
    }
    return res;
}

// Function to count subarrays having exactly k distinct elements
function exactlyK(arr, k) {
    return atMostK(arr, k) - atMostK(arr, k - 1);
}

// Driver Code
let arr = [1, 2, 2, 3];
let k = 2;
console.log(exactlyK(arr, k));

Output
4



Count Subarrays With Exactly K Distinct Elements
Visit Course explore course icon
Article Tags :
Practice Tags :

Similar Reads