Skip to content
Related Articles

Related Articles

Improve Article

Maximum occurring element in a subarray range (Mode queries)

  • Difficulty Level : Medium
  • Last Updated : 13 Aug, 2021

Given an array arr[] of N integers, and an array Q[] of M pairs, where a pair represents a query of the form {L, R}, the task is to find the maximum occurring element in the range [L, R] and its frequency for each query. If there are multiple elements with maximum frequency, then print the maximum element among them.

Examples:

Input: arr[] = {5, 7, 5, 5, 2, 7, 3, 2, 5, 2}, Q[] = {{0, 9}, {3, 6}, {4, 8}, {1, 5}}
Output: 5 Occurs 4 times
              3 Occurs 1 times
              2 Occurs 2 times
              7 Occurs 2 times
Explanation: 
The queries are performed as:

  1. Query(0, 9): The subarray over the range is {5, 7, 5, 5, 2, 7, 3, 2, 5, 2}. Elements 5, 7, 2, and 3 occur 4, 2, 3 and 1 times respectively. Therefore, print 5.
  2. Query(3, 6): The subarray over the range is {5, 2, 7, 3}. Every element occurs once. So print element 7.
  3. Query(4, 8): The subarray over the range is {2, 7, 3, 2, 5}. Element 2 occurs twice and the remaining all occurs once. Therefore, print 2.
  4. Query(1, 5): The subarray over the range is {7, 5, 5, 2, 7, 3}. Elements 7 and 5 occur twice and the remaining elements occur once. Therefore print 7.

Naive Approach: For each query, iterate over the given range [L, R] keep updating the frequency of every element in an auxiliary data structure (ex. map). After processing the entire range of the current query, iterate over all elements in the map, and find the element having the maximum frequency

Below is the implementation of the above approach:



C++




// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;
 
// Function to find the elements having
// maximum frequency for the query range
void getMaxOccuringElement(int arr[], int N, int M,
                           pair<int, int> Q[])
{
    // Iterate over all the queries
    for (int i = 0; i < M; ++i) {
 
        // Stores the frequency of each element
        // in the current query range [l, r]
        map<int, int> freq;
 
        int l = Q[i].first, r = Q[i].second;
 
        for (int j = l; j <= r; ++j)
            ++freq[arr[j]];
 
        int maxFreqElement = -1;
        int maxFreq = -1;
 
        // Iterate over the map and find the
        // element having maximum frequency
        for (auto it : freq) {
            if (it.second >= maxFreq) {
                maxFreqElement = it.first;
                maxFreq = it.second;
            }
        }
 
        // Print the answer for current query
        cout << maxFreqElement << " Occurs " << maxFreq
             << " times" << endl;
    }
}
 
// Driver Code
int main()
{
 
    int arr[] = { 5, 7, 5, 5, 2, 7, 3, 2, 5, 2 };
    pair<int, int> Q[]
        = { { 0, 9 }, { 3, 6 }, { 4, 8 }, { 1, 5 } };
 
    int N = sizeof(arr) / sizeof(arr[0]);
    int M = sizeof(Q) / sizeof(Q[0]);
 
    getMaxOccuringElement(arr, N, M, Q);
 
    return 0;
}

Java




// Java program for the above approach
 
import java.util.*;
 
class GFG{
 
    static class pair
    {
        int first, second;
        public pair(int first, int second) 
        {
            this.first = first;
            this.second = second;
        }   
    }
// Function to find the elements having
// maximum frequency for the query range
static void getMaxOccuringElement(int arr[], int N, int M,
                           pair Q[])
{
    // Iterate over all the queries
    for (int i = 0; i < M; ++i) {
 
        // Stores the frequency of each element
        // in the current query range [l, r]
        HashMap<Integer,Integer> freq = new HashMap<Integer,Integer>();
 
        int l = Q[i].first, r = Q[i].second;
 
        for (int j = l; j <= r; ++j) {
            if(freq.containsKey(arr[j]))
            freq.put(arr[j], freq.get(arr[j])+1);
            else
                freq.put(arr[j], 1);
                 
        }
 
        int maxFreqElement = -1;
        int maxFreq = -1;
 
        // Iterate over the map and find the
        // element having maximum frequency
        for (Map.Entry<Integer,Integer> it : freq.entrySet()) {
            if (it.getValue() >= maxFreq) {
                maxFreqElement = it.getKey();
                maxFreq = it.getValue();
            }
        }
 
        // Print the answer for current query
        System.out.print(maxFreqElement+ " Occurs " +  maxFreq
            + " times" +"\n");
    }
}
 
// Driver Code
public static void main(String[] args)
{
 
    int arr[] = { 5, 7, 5, 5, 2, 7, 3, 2, 5, 2 };
    pair Q[]
        = { new pair( 0, 9 ), new pair( 3, 6 ), new pair( 4, 8 ), new pair( 1, 5 ) };
 
    int N = arr.length;
    int M = Q.length;
 
    getMaxOccuringElement(arr, N, M, Q);
 
}
}
 
// This code contributed by Princi Singh

C#




// C# program for the above approach
using System;
using System.Collections.Generic;
 
public class GFG{
 
    class pair
    {
        public int first, second;
        public pair(int first, int second) 
        {
            this.first = first;
            this.second = second;
        }   
    }
   
// Function to find the elements having
// maximum frequency for the query range
static void getMaxOccuringElement(int []arr, int N, int M,
                           pair []Q)
{
   
    // Iterate over all the queries
    for (int i = 0; i < M; ++i) {
 
        // Stores the frequency of each element
        // in the current query range [l, r]
        Dictionary<int,int> freq = new Dictionary<int,int>();
 
        int l = Q[i].first, r = Q[i].second;
 
        for (int j = l; j <= r; ++j) {
            if(freq.ContainsKey(arr[j]))
            freq[arr[j]] = freq[arr[j]]+1;
            else
                freq.Add(arr[j], 1);
                 
        }
 
        int maxFreqElement = -1;
        int maxFreq = -1;
 
        // Iterate over the map and find the
        // element having maximum frequency
        foreach (KeyValuePair<int,int> it in freq) {
            if (it.Value >= maxFreq) {
                maxFreqElement = it.Key;
                maxFreq = it.Value;
            }
        }
 
        // Print the answer for current query
        Console.Write(maxFreqElement+ " Occurs " +  maxFreq
            + " times" +"\n");
    }
}
 
// Driver Code
public static void Main(String[] args)
{
 
    int []arr = { 5, 7, 5, 5, 2, 7, 3, 2, 5, 2 };
    pair []Q
        = { new pair( 0, 9 ), new pair( 3, 6 ), new pair( 4, 8 ), new pair( 1, 5 ) };
 
    int N = arr.Length;
    int M = Q.Length;
 
    getMaxOccuringElement(arr, N, M, Q);
 
}
}
 
// This code is contributed by 29AjayKumar
Output
5 Occurs 4 times
7 Occurs 1 times
2 Occurs 2 times
7 Occurs 2 times

Time Complexity: O(M * N) 
Auxiliary Space: O(N)

Efficient Approach: The above approach can be optimized by Mo’s Algorithm based on the concept of sqrt decomposition. Follow the steps below to solve the problem:

  • The queries are sorted in non-decreasing order of the blocks in which their left index falls. If two or more queries have their left indexes in the same block, then order them based on their right indexes.
  • Basically, compute the answer for all queries which have their left index in block 0, then block 1, and so on till the last block.
  • Maintain a map data structure (num_freq) which stores the count of occurrence of each element in the current query range.
  • Also, maintain a set data structure (freq_num), whose each element is a pair (the first element of the pair represents the count of occurrence of an element and the second element of the pair represents the element itself).
  • The set(freq_num) stores the elements in non-decreasing order. The ordering of elements in the set is based on the first item of the pair, which represents the frequency.
  • Thus, while answering the queries (i.e. the element having the maximum frequency), it can be done in O(1).

Below is the implementation of the above approach : 

C++




// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;
 
int BLOCK_SIZE;
 
// Structure to represent a query range
// and its index
struct query {
    int l, r, idx;
};
 
// Custom comparator
bool comparator(query a, query b)
{
    if ((a.l / BLOCK_SIZE) != (b.l / BLOCK_SIZE))
        return (a.l / BLOCK_SIZE) < (b.l / BLOCK_SIZE);
 
    return ((a.l / BLOCK_SIZE) & 1) ? (a.r < b.r)
                                    : (a.r > b.r);
}
 
// Function to add elements to the current range
void expand(int idx, int* arr, map<int, int>& numFreq,
            set<pair<int, int> >& freqNum)
{
    // Remove current element from the set
    freqNum.erase({ numFreq[arr[idx]], arr[idx] });
 
    // Increment current element count in the
    // map
    ++numFreq[arr[idx]];
 
    // Insert current element into the set
    freqNum.insert({ numFreq[arr[idx]], arr[idx] });
}
 
// Function to remove elements from the current range
void shrink(int idx, int* arr, map<int, int>& numFreq,
            set<pair<int, int> >& freqNum)
{
    // Remove current element from the set
    freqNum.erase({ numFreq[arr[idx]], arr[idx] });
 
    // Decrement current element count in the
    // map
    --numFreq[arr[idx]];
 
    // Insert current element into the set
    freqNum.insert({ numFreq[arr[idx]], arr[idx] });
}
 
// Function for Mo's algorithm
pair<int, int>
sqrtDecomposition(int& L, int& R, int l, int r, int* arr,
                  set<pair<int, int> >& freqNum,
                  map<int, int>& numFreq)
{
    // Iterate until L is greater than l
    while (L > l) {
        --L;
        expand(L, arr, numFreq, freqNum);
    }
 
    // Iterate until R is less than r
    while (R < r) {
        ++R;
        expand(R, arr, numFreq, freqNum);
    }
 
    // Iterate until L is less than l
    while (L < l) {
        shrink(L, arr, numFreq, freqNum);
        ++L;
    }
 
    // Iterate until R is greater than r
    while (R > r) {
        shrink(R, arr, numFreq, freqNum);
        --R;
    }
 
    // Stores the answer for current query
    pair<int, int> last = *prev(freqNum.end());
 
    // Return the answer
    return last;
}
 
// Function to find the element having maximum
// frequency and its frequency for all the queries
void getMaxOccuringElement(int arr[], int N, int M,
                           pair<int, int> Q[])
{
 
    // Compute each block size
    BLOCK_SIZE = (int)sqrt(N + .0) + 1;
 
    // Stores the queries
    query queries[M];
 
    for (int i = 0; i < M; ++i) {
        queries[i].l = Q[i].first;
        queries[i].r = Q[i].second;
        queries[i].idx = i;
    }
 
    // Sort all the queries
    sort(queries, queries + M, comparator);
 
    // Initiali ranges of Mos
    int L = 0, R = -1;
 
    // Stores the answer
    pair<int, int> ans[M];
 
    set<pair<int, int> > freqNum;
    map<int, int> numFreq;
 
    // Traverse the query array
    for (int i = 0; i < M; ++i) {
 
        int l = queries[i].l;
        int r = queries[i].r;
 
        // Stores the answer for current
        // query
        ans[queries[i].idx] = sqrtDecomposition(
            L, R, l, r, arr, freqNum, numFreq);
    }
 
    // Print the answer
    for (int i = 0; i < M; ++i) {
        cout << ans[i].second << " Occurs " << ans[i].first
             << " times" << endl;
    }
}
 
// Driver Code
int main()
{
    int arr[] = { 5, 7, 5, 5, 2, 7, 3, 2, 5, 2 };
    pair<int, int> Q[]
        = { { 0, 9 }, { 3, 6 }, { 4, 8 }, { 1, 5 } };
 
    int N = sizeof(arr) / sizeof(arr[0]);
    int M = sizeof(Q) / sizeof(Q[0]);
 
    getMaxOccuringElement(arr, N, M, Q);
 
    return 0;
}
Output
5 Occurs 4 times
7 Occurs 1 times
2 Occurs 2 times
7 Occurs 2 times

Time Complexity: O((N+M) * log(N) * sqrt(N))
Auxiliary Space: O(N) 

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.  To complete your preparation from learning a language to DS Algo and many more,  please refer Complete Interview Preparation Course.

In case you wish to attend live classes with experts, please refer DSA Live Classes for Working Professionals and Competitive Programming Live for Students.




My Personal Notes arrow_drop_up
Recommended Articles
Page :