Given an array arr[] of integers and a 2D array queries[][], where each queries[i] contains three integers: l, r, and x. For each query, determine how many times the element x appears in the subarray of arr[] from index l to r (both inclusive).
For each query, return the count of occurrences of x in the specified range.
Examples:
Input: arr []= [1, 2, 1, 3, 1, 2, 3], queries[][] = [[0, 4, 1], [2, 5, 2], [1, 6, 3], [0, 6, 5]]
Output: [3, 1, 2, 0]
Explanation:
query [0, 4, 1] → Subarray = [1, 2, 1, 3, 1], 1 appears 3 times
query [2, 5, 2] → Subarray = [1, 3, 1, 2], 2 appears 1 time
query [1, 6, 3] → Subarray = [2, 1, 3, 1, 2, 3] 3 appears 2 times
query [0, 6, 5] → Subarray = [1, 2, 1, 3, 1, 2, 3], 5 appears 0 timesInput: arr[] = [11, 21, 51, 101, 11, 51], queries[][] = [[0, 4, 11], [2, 5, 51]]
Output: [2, 2]
Explanation:
query [0, 4, 11] → Subarray = [11, 21, 51, 101, 11], 11 appears 2 times
query [2, 5, 51] → Subarray = [51, 101, 11, 51], 51 appears 2 times
Table of Content
[Naive Approach] Range Frequency Scan - O(n × q) Time and O(1) Space
The idea is to iterate over each query and scan the subarray from index l to r, counting how many times the element x appears. This is done using a simple linear loop for every query without any preprocessing.
#include <iostream>
#include <vector>
using namespace std;
vector<int> freqInRange(vector<int>& arr,
vector<vector<int>>& queries) {
vector<int> result;
// process each query
for (auto& q : queries) {
int l = q[0];
int r = q[1];
int x = q[2];
int count = 0;
// loop from l to r and count how many
// times x appears
for (int i = l; i <= r; ++i) {
if (arr[i] == x) {
count++;
}
}
// store the answer for this query
result.push_back(count);
}
return result;
}
int main() {
vector<int> arr = {1, 2, 1, 3, 1, 2, 3};
vector<vector<int>> queries = {
{0, 4, 1},
{2, 5, 2},
{1, 6, 3},
{0, 6, 5}
};
vector<int> ans = freqInRange(arr, queries);
for (int val : ans) {
cout << val << " ";
}
cout << endl;
return 0;
}
import java.util.ArrayList;
class GfG {
static ArrayList<Integer> freqInRange(int[] arr,
int[][] queries) {
ArrayList<Integer> result = new ArrayList<>();
// process each query
for (int[] q : queries) {
int l = q[0];
int r = q[1];
int x = q[2];
int count = 0;
// loop from l to r and count how many
// times x appears
for (int i = l; i <= r; ++i) {
if (arr[i] == x) {
count++;
}
}
// store the answer for this query
result.add(count);
}
return result;
}
public static void main(String[] args) {
int[] arr = {1, 2, 1, 3, 1, 2, 3};
int[][] queries = {
{0, 4, 1},
{2, 5, 2},
{1, 6, 3},
{0, 6, 5}
};
ArrayList<Integer> ans = freqInRange(arr, queries);
for (int val : ans) {
System.out.print(val + " ");
}
System.out.println();
}
}
def freqInRange(arr, queries):
result = []
# process each query
for q in queries:
l = q[0]
r = q[1]
x = q[2]
count = 0
# loop from l to r and count how many
# times x appears
for i in range(l, r + 1):
if arr[i] == x:
count += 1
# store the answer for this query
result.append(count)
return result
if __name__ == "__main__":
arr = [1, 2, 1, 3, 1, 2, 3]
queries = [
[0, 4, 1],
[2, 5, 2],
[1, 6, 3],
[0, 6, 5]
]
ans = freqInRange(arr, queries)
print(*ans)
using System;
using System.Collections.Generic;
class GfG {
static List<int> freqInRange(int[] arr,
List<int[]> queries) {
List<int> result = new List<int>();
// process each query
foreach (var q in queries) {
int l = q[0];
int r = q[1];
int x = q[2];
int count = 0;
// loop from l to r and count how many
// times x appears
for (int i = l; i <= r; ++i) {
if (arr[i] == x) {
count++;
}
}
// store the answer for this query
result.Add(count);
}
return result;
}
static void Main() {
int[] arr = {1, 2, 1, 3, 1, 2, 3};
List<int[]> queries = new List<int[]> {
new int[] {0, 4, 1},
new int[] {2, 5, 2},
new int[] {1, 6, 3},
new int[] {0, 6, 5}
};
List<int> ans = freqInRange(arr, queries);
foreach (int val in ans) {
Console.Write(val + " ");
}
Console.WriteLine();
}
}
function freqInRange(arr, queries) {
let result = [];
// process each query
for (let q of queries) {
let l = q[0];
let r = q[1];
let x = q[2];
let count = 0;
// loop from l to r and count how many
// times x appears
for (let i = l; i <= r; i++) {
if (arr[i] === x) {
count++;
}
}
// store the answer for this query
result.push(count);
}
return result;
}
// Driver Code
let arr = [1, 2, 1, 3, 1, 2, 3];
let queries = [
[0, 4, 1],
[2, 5, 2],
[1, 6, 3],
[0, 6, 5]
];
let ans = freqInRange(arr, queries);
console.log(ans.join(" "));
Output
3 1 2 0
[Expected Approach] Indexed Map and Binary Search
The idea is to precompute the positions of each element in the array and store them in a map. For each query, we find how many times x appears between indices l and r by applying lower_bound and upper_bound on the stored index list of x.
Step by Step Implementation:
- Build a map from each element value to a list of its indices. Loop through the array and for every value val, append its index i to indexMap[val].
- For each query [l, r, x]:
- If x is not present in the map, add 0 to the result and continue.
- Otherwise:
=> Retrieve the sorted list of indices for value x from the map.
=> Use binary search (lower_bound) to find the first index ≥ l.
=> Use binary search (upper_bound) to find the first index > r.
=> The number of occurrences of x in range [l, r] is right - left.
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
vector<int> freqInRange(vector<int>& arr,
vector<vector<int>>& queries) {
map<int, vector<int>> indexMap;
// store all indices of each value in the map
for (int i = 0; i < arr.size(); ++i) {
indexMap[arr[i]].push_back(i);
}
vector<int> result;
// process each query
for (auto& q : queries) {
int l = q[0];
int r = q[1];
int x = q[2];
// if x does not exist in map, frequency is 0
if (indexMap.find(x) == indexMap.end()) {
result.push_back(0);
continue;
}
// get index list of x
vector<int>& ind = indexMap[x];
// count occurrences between l and r
// using binary search
auto left =
lower_bound(ind.begin(), ind.end(), l);
auto right =
upper_bound(ind.begin(), ind.end(), r);
// number of occurrences is difference of bounds
result.push_back(right - left);
}
return result;
}
int main() {
vector<int> arr = {1, 2, 1, 3, 1, 2, 3};
vector<vector<int>> queries = {
{0, 4, 1},
{2, 5, 2},
{1, 6, 3},
{0, 6, 5}
};
vector<int> ans = freqInRange(arr, queries);
for (int val : ans) {
cout << val << " ";
}
cout << endl;
return 0;
}
import java.util.*;
class GfG {
// process frequency queries using map
// and binary search
public static ArrayList<Integer>
freqInRange(int[] arr, int[][] queries) {
Map<Integer, ArrayList<Integer>> indexMap =
new HashMap<>();
// store all indices of each value in the map
for (int i = 0; i < arr.length; i++) {
indexMap.putIfAbsent(arr[i], new ArrayList<>());
indexMap.get(arr[i]).add(i);
}
ArrayList<Integer> result = new ArrayList<>();
// process each query
for (int[] q : queries) {
int l = q[0];
int r = q[1];
int x = q[2];
// if x does not exist in map, frequency is 0
if (!indexMap.containsKey(x)) {
result.add(0);
continue;
}
ArrayList<Integer> ind = indexMap.get(x);
// count occurrences between l and r
// using binary search
int left =
Collections.binarySearch(ind, l);
int right =
Collections.binarySearch(ind, r + 1);
if (left < 0) left = -(left + 1);
if (right < 0) right = -(right + 1);
// number of occurrences is difference
// of bounds
result.add(right - left);
}
return result;
}
public static void main(String[] args) {
int[] arr = {1, 2, 1, 3, 1, 2, 3};
int[][] queries = {
{0, 4, 1},
{2, 5, 2},
{1, 6, 3},
{0, 6, 5}
};
ArrayList<Integer> ans = freqInRange(arr, queries);
for (int val : ans) {
System.out.print(val + " ");
}
System.out.println();
}
}
import bisect
def freqInRange(arr, queries):
indexMap = {}
# store all indices of each value in the map
for i, val in enumerate(arr):
if val not in indexMap:
indexMap[val] = []
indexMap[val].append(i)
result = []
# process each query
for q in queries:
l, r, x = q
# if x does not exist in map, frequency is 0
if x not in indexMap:
result.append(0)
continue
ind = indexMap[x]
# count occurrences between l and r
# using binary search
left = bisect.bisect_left(ind, l)
right = bisect.bisect_right(ind, r)
# number of occurrences is difference of bounds
result.append(right - left)
return result
if __name__ == "__main__":
arr = [1, 2, 1, 3, 1, 2, 3]
queries = [
[0, 4, 1],
[2, 5, 2],
[1, 6, 3],
[0, 6, 5]
]
ans = freqInRange(arr, queries)
print(*ans)
using System;
using System.Collections.Generic;
class GfG {
// process frequency queries using map and
// binary search
static List<int> freqInRange(int[] arr,
List<int[]> queries) {
Dictionary<int, List<int>> indexMap =
new Dictionary<int, List<int>>();
// store all indices of each value in the map
for (int i = 0; i < arr.Length; i++) {
if (!indexMap.ContainsKey(arr[i]))
indexMap[arr[i]] = new List<int>();
indexMap[arr[i]].Add(i);
}
List<int> result = new List<int>();
// process each query
foreach (var q in queries) {
int l = q[0];
int r = q[1];
int x = q[2];
// if x does not exist in map, frequency is 0
if (!indexMap.ContainsKey(x)) {
result.Add(0);
continue;
}
List<int> ind = indexMap[x];
// count occurrences between l and r
// using binary search
int left = ind.BinarySearch(l);
int right = ind.BinarySearch(r + 1);
if (left < 0) left = ~left;
if (right < 0) right = ~right;
// number of occurrences is difference
// of bounds
result.Add(right - left);
}
return result;
}
static void Main() {
int[] arr = {1, 2, 1, 3, 1, 2, 3};
List<int[]> queries = new List<int[]> {
new int[] {0, 4, 1},
new int[] {2, 5, 2},
new int[] {1, 6, 3},
new int[] {0, 6, 5}
};
List<int> ans = freqInRange(arr, queries);
foreach (int val in ans) Console.Write(val + " ");
Console.WriteLine();
}
}
// helper binary search functions
function lowerBound(arr, target) {
let low = 0, high = arr.length;
while (low < high) {
let mid = Math.floor((low + high) / 2);
if (arr[mid] < target) low = mid + 1;
else high = mid;
}
return low;
}
function upperBound(arr, target) {
let low = 0, high = arr.length;
while (low < high) {
let mid = Math.floor((low + high) / 2);
if (arr[mid] <= target) low = mid + 1;
else high = mid;
}
return low;
}
// function to process frequency queries using map
// and binary search
function freqInRange(arr, queries) {
let indexMap = new Map();
// store all indices of each value in the map
for (let i = 0; i < arr.length; i++) {
if (!indexMap.has(arr[i])) {
indexMap.set(arr[i], []);
}
indexMap.get(arr[i]).push(i);
}
let result = [];
// process each query
for (let q of queries) {
let l = q[0], r = q[1], x = q[2];
// if x does not exist in map, frequency is 0
if (!indexMap.has(x)) {
result.push(0);
continue;
}
let ind = indexMap.get(x);
// count occurrences between l and r using
// binary search
let left = lowerBound(ind, l);
let right = upperBound(ind, r);
// number of occurrences is difference
// of bounds
result.push(right - left);
}
return result;
}
// Driver Code
let arr = [1, 2, 1, 3, 1, 2, 3];
let queries = [
[0, 4, 1],
[2, 5, 2],
[1, 6, 3],
[0, 6, 5]
];
let ans = freqInRange(arr, queries);
console.log(ans.join(" "));
Output
3 1 2 0
Time Complexity: O(n × logn + q × log k), preprocessing the map takes O(n × log n) time, where n is the size of the array then for each of the q queries, we perform two binary searches on the index list of size k (number of times x appears), costing O(log k) per query.
Auxiliary Space: O(n), we use a map to store indices of each distinct element. In the worst case (all elements unique), the total space used across all vectors is proportional to the array size n.