Array range queries for elements with frequency same as value

• Difficulty Level : Expert
• Last Updated : 24 May, 2021

Given an array of N numbers, the task is to answer Q queries of the following type:-

query(start, end) = Number of times a
number x occurs exactly x times in a
subarray from start to end

Examples:

Input : arr = {1, 2, 2, 3, 3, 3}
Query 1: start = 0, end = 1,
Query 2: start = 1, end = 1,
Query 3: start = 0, end = 2,
Query 4: start = 1, end = 3,
Query 5: start = 3, end = 5,
Query 6: start = 0, end = 5
Output : 1 0 2 1 1 3
Explanation
In Query 1, Element 1 occurs once in subarray [1, 2];
In Query 2, No Element satisfies the required condition is subarray ;
In Query 3, Element 1 occurs once and 2 occurs twice in subarray [1, 2, 2];
In Query 4, Element 2 occurs twice in subarray [2, 2, 3];
In Query 5, Element 3 occurs thrice in subarray [3, 3, 3];
In Query 6, Element 1 occurs once, 2 occurs twice and 3 occurs thrice in subarray [1, 2, 2, 3, 3, 3]

Method 1 (Brute Force)
Calculate frequency of every element in the subarray under each query. If any number x has frequency x in the subarray covered under each query, we increment the counter.

C++

 /* C++ Program to answer Q queries to   find number of times an element x   appears x times in a Query subarray */#include using namespace std; /* Returns the count of number x with   frequency x in the subarray from   start to end */int solveQuery(int start, int end, int arr[]){    // map for frequency of elements    unordered_map frequency;     // store frequency of each element    // in arr[start; end]    for (int i = start; i <= end; i++)        frequency[arr[i]]++;        // Count elements with same frequency    // as value    int count = 0;    for (auto x : frequency)        if (x.first == x.second)            count++;       return count;} int main(){    int A[] = { 1, 2, 2, 3, 3, 3 };    int n = sizeof(A) / sizeof(A);     // 2D array of queries with 2 columns    int queries[] = { { 0, 1 },                         { 1, 1 },                         { 0, 2 },                         { 1, 3 },                         { 3, 5 },                         { 0, 5 } };     // calculating number of queries    int q = sizeof(queries) / sizeof(queries);     for (int i = 0; i < q; i++) {        int start = queries[i];        int end = queries[i];        cout << "Answer for Query " << (i + 1)             << " = " << solveQuery(start,             end, A) << endl;    }     return 0;}

Java

 /* Java Program to answer Q queries tofind number of times an element xappears x times in a Query subarray */import java.util.HashMap;import java.util.Map; class GFG{  /* Returns the count of number x withfrequency x in the subarray fromstart to end */static int solveQuery(int start, int end, int arr[]){    // map for frequency of elements    Map mp = new HashMap<>();     // store frequency of each element    // in arr[start; end]    for (int i = start; i <= end; i++)        mp.put(arr[i],mp.get(arr[i]) == null?1:mp.get(arr[i])+1);     // Count elements with same frequency    // as value    int count = 0;    for (Map.Entry entry : mp.entrySet())        if (entry.getKey() == entry.getValue())            count++;    return count;} // Driver codepublic static void main(String[] args){    int A[] = { 1, 2, 2, 3, 3, 3 };    int n = A.length;     // 2D array of queries with 2 columns    int [][]queries = { { 0, 1 },                        { 1, 1 },                        { 0, 2 },                        { 1, 3 },                        { 3, 5 },                        { 0, 5 } };     // calculating number of queries    int q = queries.length;     for (int i = 0; i < q; i++)    {        int start = queries[i];        int end = queries[i];        System.out.println("Answer for Query " + (i + 1)            + " = " + solveQuery(start,            end, A));    }}} // This code is contributed by Rajput-Ji

Python3

 # Python 3 Program to answer Q queries# to find number of times an element x# appears x times in a Query subarrayimport math as mt # Returns the count of number x with# frequency x in the subarray from# start to enddef solveQuery(start, end, arr):     # map for frequency of elements    frequency = dict()     # store frequency of each element    # in arr[start end]    for i in range(start, end + 1):          if arr[i] in frequency.keys():            frequency[arr[i]] += 1        else:            frequency[arr[i]] = 1                     # Count elements with same    # frequency as value    count = 0    for x in frequency:        if x == frequency[x]:            count += 1    return count # Driver codeA = [1, 2, 2, 3, 3, 3 ]n = len(A) # 2D array of queries with 2 columnsqueries = [[ 0, 1 ], [ 1, 1 ],           [ 0, 2 ], [ 1, 3 ],           [ 3, 5 ], [ 0, 5 ]] # calculating number of queriesq = len(queries) for i in range(q):    start = queries[i]    end = queries[i]    print("Answer for Query ", (i + 1),          " = ", solveQuery(start,end, A))           # This code is contributed# by Mohit kumar 29

C#

 // C# Program to answer Q queries to// find number of times an element x// appears x times in a Query subarrayusing System;using System.Collections.Generic; class GFG{    /* Returns the count of number x with    frequency x in the subarray from    start to end */    public static int solveQuery(int start,                                 int end,                                 int[] arr)    {         // map for frequency of elements        Dictionary mp = new Dictionary();         // store frequency of each element        // in arr[start; end]        for (int i = start; i <= end; i++)        {            if (mp.ContainsKey(arr[i]))                mp[arr[i]]++;            else                mp.Add(arr[i], 1);        }         // Count elements with same frequency        // as value        int count = 0;        foreach (KeyValuePair entry in mp)        {            if (entry.Key == entry.Value)                count++;        }        return count;    }     // Driver code    public static void Main(String[] args)    {        int[] A = { 1, 2, 2, 3, 3, 3 };        int n = A.Length;         // 2D array of queries with 2 columns        int[,] queries = {{ 0, 1 }, { 1, 1 },                          { 0, 2 }, { 1, 3 },                          { 3, 5 }, { 0, 5 }};         // calculating number of queries        int q = queries.Length;         for (int i = 0; i < q; i++)        {            int start = queries[i, 0];            int end = queries[i, 1];            Console.WriteLine("Answer for Query " + (i + 1) +                              " = " + solveQuery(start, end, A));        }    }} // This code is contributed by// sanjeev2552

Javascript


Output:
Answer for Query 1 = 1
Answer for Query 2 = 0
Answer for Query 3 = 2
Answer for Query 4 = 1
Answer for Query 5 = 1
Answer for Query 6 = 3

Time Complexity of this method is O(Q * N)
Method 2 (Efficient)
We can solve this problem using the MO’s Algorithm
We assign starting index, ending index and query number to each query, Each query takes the following form-

Starting Index(L): Starting Index of the subarray covered under the query;
Ending Index(R) : Ending Index of the subarray covered under the query;
Query Number(Index) : Since queries are sorted, this tells us original position of the query so that we answer the queries in the original order

Firstly, we divide the queries into blocks and sort the queries using a custom comparator.
Now we process the queries offline where we keep two pointers i.e. MO_RIGHT and MO_LEFT with each incoming query, we move these pointers forward and backward and insert and delete elements according to the starting and ending indices of the current query.
Let the current running answer be current_ans.
Whenever we insert an element we increment the frequency of the included element, if this frequency is equal to the element we just included, we increment the current_ans.If the frequency of this element becomes (current element + 1) this means that earlier this element was counted in the current_ans when it was equal to its frequency, thus we need to decrement current_ans in this case.
Whenever we delete/remove an element we decrement the frequency of the excluded element, if this frequency is equal to the element we just excluded, we increment the current_ans.If the frequency of this element becomes (current element – 1) this means that earlier this element was counted in the current_ans when it was equal to its frequency, thus we need to decrement current_ans in this case.

CPP

Output:
Answer for Query 1 = 1
Answer for Query 2 = 0
Answer for Query 3 = 2
Answer for Query 4 = 1
Answer for Query 5 = 1
Answer for Query 6 = 3

Time Complexity of this approach using MO’s Algorithm is O(Q * sqrt(N) * logA) where logA is the complexity to insert an element A into the unordered_map for each query.

My Personal Notes arrow_drop_up