Open In App

Maximum occurring element in a subarray range (Mode queries)

Improve
Improve
Like Article
Like
Save
Share
Report

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


Python3




# Python program for the above approach
 
def getMaxOccuringElement(arr, N, M, Q):
    # Iterate over all the queries
    for i in range(M):
        # Stores the frequency of each element in the current query range [l, r]
        freq = {}
 
        l = Q[i][0]
        r = Q[i][1]
 
        for j in range(l, r+1):
            if arr[j] in freq:
                freq[arr[j]] += 1
            else:
                freq[arr[j]] = 1
     
        max_freq_element = -1
        max_freq = -1
 
        # Iterate over the map and find the element having maximum frequency
        for key, value in freq.items():
            if value > max_freq:
                max_freq_element = key
                max_freq = value
            if value == max_freq:
                max_freq_element = max(max_freq_element,key)
         
        print(str(max_freq_element) + " Occurs " + str(max_freq) + " times")
 
# Driver Code
arr = [ 5, 7, 5, 5, 2, 7, 3, 2, 5, 2 ]
Q = [(0, 9), (3, 6), (4, 8), (1, 5)]
 
N = len(arr)
M = len(Q)
 
getMaxOccuringElement(arr, N, M, Q)


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


Javascript




// JavaScript program for the above approach
function getMaxOccuringElement(arr, N, M, Q) {
    // Iterate over all the queries
    for (let i = 0; i < M; i++) {
        // Stores the frequency of each element in the current query range [l, r]
        const freq = {};
 
        const l = Q[i][0];
        const r = Q[i][1];
 
        for (let j = l; j <= r; j++) {
            if (arr[j] in freq) {
                freq[arr[j]] += 1;
            } else {
                freq[arr[j]] = 1;
            }
        }
 
        let max_freq_element = -1;
        let max_freq = -1;
 
        // Iterate over the map and find the element having maximum frequency
        for (const [key, value] of Object.entries(freq)) {
            if (value > max_freq) {
                max_freq_element = key;
                max_freq = value;
            }
            if (value === max_freq) {
                max_freq_element = Math.max(max_freq_element, key);
            }
        }
 
        console.log(max_freq_element + " Occurs " + max_freq + " times");
    }
}
 
// Driver Code
const arr = [5, 7, 5, 5, 2, 7, 3, 2, 5, 2];
const Q = [
    [0, 9],
    [3, 6],
    [4, 8],
    [1, 5]
];
 
const N = arr.length;
const M = Q.length;
 
getMaxOccuringElement(arr, N, M, Q);


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) 

Approach: Hash Map with Subarray Frequency Counting

Here’s the approach in detail:

  1. Create a hash map to store the frequency of each element in the array.
  2. For each query {L, R}, initialize a new hash map to store the frequency of each element in the subarray arr[L…R].
  3. Iterate over the subarray arr[L…R] and update the frequency of each element in the subarray hash map.
  4. Find the element with a maximum frequency in the subarray hash map and its frequency.
  5. Print the element and its frequency.

C++




#include <iostream>
#include <unordered_map>
using namespace std;
 
int main() {
    int arr[] = {5, 7, 5, 5, 2, 7, 3, 2, 5, 2};
    int n = sizeof(arr)/sizeof(arr[0]);
     
    pair<int, int> queries[] = {{0, 9}, {3, 6}, {4, 8}, {1, 5}};
    int m = sizeof(queries)/sizeof(queries[0]);
     
    unordered_map<int, int> freq;
    for(int i=0; i<n; i++) {
        freq[arr[i]]++;
    }
     
    for(int i=0; i<m; i++) {
        int l = queries[i].first;
        int r = queries[i].second;
        unordered_map<int, int> sub_freq;
        int max_freq = 0, max_elem = -1;
        for(int j=l; j<=r; j++) {
            sub_freq[arr[j]]++;
            if(sub_freq[arr[j]] > max_freq || (sub_freq[arr[j]] == max_freq && arr[j] > max_elem)) {
                max_freq = sub_freq[arr[j]];
                max_elem = arr[j];
            }
        }
        cout << max_elem << " Occurs " << max_freq << " times\n";
    }
     
    return 0;
}


Java




import java.util.*;
 
public class Main {
 
    // Driver Code
    public static void main(String[] args)
    {
        int[] arr = { 5, 7, 5, 5, 2, 7, 3, 2, 5, 2 };
        int n = arr.length;
 
        int[][] queries
            = { { 0, 9 }, { 3, 6 }, { 4, 8 }, { 1, 5 } };
        int m = queries.length;
 
        Map<Integer, Integer> freq = new HashMap<>();
        for (int i = 0; i < n; i++) {
            freq.put(arr[i],
                     freq.getOrDefault(arr[i], 0) + 1);
        }
 
        for (int i = 0; i < m; i++) {
            int l = queries[i][0];
            int r = queries[i][1];
            Map<Integer, Integer> subFreq = new HashMap<>();
            int maxFreq = 0;
            int maxElem = -1;
            for (int j = l; j <= r; j++) {
                subFreq.put(arr[j],
                            subFreq.getOrDefault(arr[j], 0)
                                + 1);
                if (subFreq.get(arr[j]) > maxFreq
                    || (subFreq.get(arr[j]) == maxFreq
                        && arr[j] > maxElem)) {
                    maxFreq = subFreq.get(arr[j]);
                    maxElem = arr[j];
                }
            }
            System.out.println(maxElem + " Occurs "
                               + maxFreq + " times");
        }
    }
}


Python3




from collections import defaultdict
 
arr = [5, 7, 5, 5, 2, 7, 3, 2, 5, 2]
n = len(arr)
 
queries = [(0, 9), (3, 6), (4, 8), (1, 5)]
m = len(queries)
 
freq = defaultdict(int)
for i in range(n):
    freq[arr[i]] += 1
 
for i in range(m):
    l, r = queries[i]
    sub_freq = defaultdict(int)
    max_freq, max_elem = 0, -1
    for j in range(l, r+1):
        sub_freq[arr[j]] += 1
        if sub_freq[arr[j]] > max_freq or (sub_freq[arr[j]] == max_freq and arr[j] > max_elem):
            max_freq = sub_freq[arr[j]]
            max_elem = arr[j]
    print(max_elem, "Occurs", max_freq, "times")


C#




using System;
using System.Collections.Generic;
 
class MainClass {
    public static void Main(string[] args) {
        int[] arr = {5, 7, 5, 5, 2, 7, 3, 2, 5, 2};
        int n = arr.Length;
 
        Tuple<int, int>[] queries = {Tuple.Create(0, 9), Tuple.Create(3, 6), Tuple.Create(4, 8), Tuple.Create(1, 5)};
        int m = queries.Length;
 
        Dictionary<int, int> freq = new Dictionary<int, int>();
        for(int i=0; i<n; i++) {
            if(freq.ContainsKey(arr[i]))
                freq[arr[i]]++;
            else
                freq[arr[i]] = 1;
        }
 
        for(int i=0; i<m; i++) {
            int l = queries[i].Item1;
            int r = queries[i].Item2;
            Dictionary<int, int> sub_freq = new Dictionary<int, int>();
            int max_freq = 0, max_elem = -1;
            for(int j=l; j<=r; j++) {
                if(sub_freq.ContainsKey(arr[j]))
                    sub_freq[arr[j]]++;
                else
                    sub_freq[arr[j]] = 1;
                 
                if(sub_freq[arr[j]] > max_freq || (sub_freq[arr[j]] == max_freq && arr[j] > max_elem)) {
                    max_freq = sub_freq[arr[j]];
                    max_elem = arr[j];
                }
            }
            Console.WriteLine(max_elem + " Occurs " + max_freq + " times");
        }
 
        Console.ReadLine();
    }
}


Javascript




let arr = [5, 7, 5, 5, 2, 7, 3, 2, 5, 2];
let n = arr.length;
 
let queries = [[0, 9], [3, 6], [4, 8], [1, 5]];
let m = queries.length;
 
let freq = new Map();
for (let i = 0; i < n; i++) {
  if (freq.has(arr[i]))
    freq.set(arr[i], freq.get(arr[i]) + 1);
  else
    freq.set(arr[i], 1);
}
 
for (let i = 0; i < m; i++) {
  let l = queries[i][0];
  let r = queries[i][1];
  let sub_freq = new Map();
  let max_freq = 0, max_elem = -1;
  for (let j = l; j <= r; j++) {
    if (sub_freq.has(arr[j]))
      sub_freq.set(arr[j], sub_freq.get(arr[j]) + 1);
    else
      sub_freq.set(arr[j], 1);
 
    if (sub_freq.get(arr[j]) > max_freq || (sub_freq.get(arr[j]) === max_freq && arr[j] > max_elem)) {
      max_freq = sub_freq.get(arr[j]);
      max_elem = arr[j];
    }
  }
  console.log(max_elem + " occurs " + max_freq + " times");
}


Output

5 Occurs 4 times
7 Occurs 1 times
2 Occurs 2 times
7 Occurs 2 times

Time Complexity: O(M*N) where M is the number of queries and N is the size of the array.
Auxiliary Space: O(N) 



Last Updated : 24 Jul, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads