Array range queries for searching an element
Last Updated :
11 Jul, 2025
Given an array of N elements and Q queries of the form L R X. For each query, you have to output if the element X exists in the array between the indices L and R(included).
Prerequisite : Mo's Algorithms
Examples :
Input : N = 5
arr = [1, 1, 5, 4, 5]
Q = 3
1 3 2
2 5 1
3 5 5
Output : No
Yes
Yes
Explanation :
For the first query, 2 does not exist between the indices 1 and 3.
For the second query, 1 exists between the indices 2 and 5.
For the third query, 5 exists between the indices 3 and 5.
Naive Approach :
The naive method would be to traverse the elements from L to R for each query, linearly searching for X. In the worst case, there can be N elements from L to R, hence the worst case time complexity for each query would be O(N). Therefore, for all the Q queries, the time complexity would turn out to be O(Q*N).
Using Union-Find Method :
This method checks only one element among all the consecutive equal values. If X is not equal to these values, then the algorithm skips all the other the other equal elements and continues traversal with the next different element. This algorithm is evidently useful only when there are consecutive equal elements in large amounts.
Algorithm :
- Merge all the consecutive equal elements in one group.
- While processing a query, start from R. Let index = R.
- Compare a[index] with X. If they are equal, then print "Yes" and break out of traversing the rest of the range. Else, skip all the consecutive elements belonging to the group of a[index]. Index becomes equal to one less than the index of the root of this group.
- Continue the above step either till X is found or till index becomes less than L.
- If index becomes less than L, print "No".
Below is the implementation of the above idea.
C++
// Program to determine if the element
// exists for different range queries
#include <bits/stdc++.h>
using namespace std;
// Structure to represent a query range
struct Query
{
int L, R, X;
};
const int maxn = 100;
int root[maxn];
// Find the root of the group containing
// the element at index x
int find(int x)
{
return x == root[x] ? x : root[x] =
find(root[x]);
}
// merge the two groups containing elements
// at indices x and y into one group
int uni(int x, int y)
{
int p = find(x), q = find(y);
if (p != q) {
root[p] = root[q];
}
}
void initialize(int a[], int n, Query q[], int m)
{
// make n subsets with every
// element as its root
for (int i = 0; i < n; i++)
root[i] = i;
// consecutive elements equal in value are
// merged into one single group
for (int i = 1; i < n; i++)
if (a[i] == a[i - 1])
uni(i, i - 1);
}
// Driver code
int main()
{
int a[] = { 1, 1, 5, 4, 5 };
int n = sizeof(a) / sizeof(a[0]);
Query q[] = { { 0, 2, 2 }, { 1, 4, 1 },
{ 2, 4, 5 } };
int m = sizeof(q) / sizeof(q[0]);
initialize(a, n, q, m);
for (int i = 0; i < m; i++)
{
int flag = 0;
int l = q[i].L, r = q[i].R, x = q[i].X;
int p = r;
while (p >= l)
{
// check if the current element in
// consideration is equal to x or not
// if it is equal, then x exists in the range
if (a[p] == x)
{
flag = 1;
break;
}
p = find(p) - 1;
}
// Print if x exists or not
if (flag != 0)
cout << x << " exists between [" << l
<< ", " << r << "] " << endl;
else
cout << x << " does not exist between ["
<< l << ", " << r << "] " << endl;
}
}
Java
// Java program to determine if the element
// exists for different range queries
import java.util.*;
class GFG
{
// Structure to represent a query range
static class Query
{
int L, R, X;
public Query(int L, int R, int X)
{
this.L = L;
this.R = R;
this.X = X;
}
};
static int maxn = 100;
static int []root = new int[maxn];
// Find the root of the group containing
// the element at index x
static int find(int x)
{
if(x == root[x])
return x;
else
return root[x] = find(root[x]);
}
// merge the two groups containing elements
// at indices x and y into one group
static void uni(int x, int y)
{
int p = find(x), q = find(y);
if (p != q)
{
root[p] = root[q];
}
}
static void initialize(int a[], int n,
Query q[], int m)
{
// make n subsets with every
// element as its root
for (int i = 0; i < n; i++)
root[i] = i;
// consecutive elements equal in value are
// merged into one single group
for (int i = 1; i < n; i++)
if (a[i] == a[i - 1])
uni(i, i - 1);
}
// Driver code
public static void main(String args[])
{
int a[] = { 1, 1, 5, 4, 5 };
int n = a.length;
Query q[] = { new Query(0, 2, 2 ),
new Query( 1, 4, 1 ),
new Query( 2, 4, 5 ) };
int m = q.length;
initialize(a, n, q, m);
for (int i = 0; i < m; i++)
{
int flag = 0;
int l = q[i].L, r = q[i].R, x = q[i].X;
int p = r;
while (p >= l)
{
// check if the current element in
// consideration is equal to x or not
// if it is equal, then x exists in the range
if (a[p] == x)
{
flag = 1;
break;
}
p = find(p) - 1;
}
// Print if x exists or not
if (flag != 0)
System.out.println(x + " exists between [" +
l + ", " + r + "] ");
else
System.out.println(x + " does not exist between [" +
l + ", " + r + "] ");
}
}
}
// This code is contributed by 29AjayKumar
Python3
# Python3 program to determine if the element
# exists for different range queries
# Structure to represent a query range
class Query:
def __init__(self, L, R, X):
self.L = L
self.R = R
self.X = X
maxn = 100
root = [0] * maxn
# Find the root of the group containing
# the element at index x
def find(x):
if x == root[x]:
return x
else:
root[x] = find(root[x])
return root[x]
# merge the two groups containing elements
# at indices x and y into one group
def uni(x, y):
p = find(x)
q = find(y)
if p != q:
root[p] = root[q]
def initialize(a, n, q, m):
# make n subsets with every
# element as its root
for i in range(n):
root[i] = i
# consecutive elements equal in value are
# merged into one single group
for i in range(1, n):
if a[i] == a[i - 1]:
uni(i, i - 1)
# Driver Code
if __name__ == "__main__":
a = [1, 1, 5, 4, 5]
n = len(a)
q = [Query(0, 2, 2),
Query(1, 4, 1),
Query(2, 4, 5)]
m = len(q)
initialize(a, n, q, m)
for i in range(m):
flag = False
l = q[i].L
r = q[i].R
x = q[i].X
p = r
while p >= l:
# check if the current element in
# consideration is equal to x or not
# if it is equal, then x exists in the range
if a[p] == x:
flag = True
break
p = find(p) - 1
# Print if x exists or not
if flag:
print("%d exists between [%d, %d]" % (x, l, r))
else:
print("%d does not exists between [%d, %d]" % (x, l, r))
# This code is contributed by
# sanjeev2552
C#
// C# program to determine if the element
// exists for different range queries
using System;
class GFG
{
// Structure to represent a query range
public class Query
{
public int L, R, X;
public Query(int L, int R, int X)
{
this.L = L;
this.R = R;
this.X = X;
}
};
static int maxn = 100;
static int []root = new int[maxn];
// Find the root of the group containing
// the element at index x
static int find(int x)
{
if(x == root[x])
return x;
else
return root[x] = find(root[x]);
}
// merge the two groups containing elements
// at indices x and y into one group
static void uni(int x, int y)
{
int p = find(x), q = find(y);
if (p != q)
{
root[p] = root[q];
}
}
static void initialize(int []a, int n,
Query []q, int m)
{
// make n subsets with every
// element as its root
for (int i = 0; i < n; i++)
root[i] = i;
// consecutive elements equal in value are
// merged into one single group
for (int i = 1; i < n; i++)
if (a[i] == a[i - 1])
uni(i, i - 1);
}
// Driver code
public static void Main(String []args)
{
int []a = { 1, 1, 5, 4, 5 };
int n = a.Length;
Query []q = {new Query(0, 2, 2),
new Query(1, 4, 1),
new Query(2, 4, 5)};
int m = q.Length;
initialize(a, n, q, m);
for (int i = 0; i < m; i++)
{
int flag = 0;
int l = q[i].L, r = q[i].R, x = q[i].X;
int p = r;
while (p >= l)
{
// check if the current element in
// consideration is equal to x or not
// if it is equal, then x exists in the range
if (a[p] == x)
{
flag = 1;
break;
}
p = find(p) - 1;
}
// Print if x exists or not
if (flag != 0)
Console.WriteLine(x + " exists between [" +
l + ", " + r + "] ");
else
Console.WriteLine(x + " does not exist between [" +
l + ", " + r + "] ");
}
}
}
// This code is contributed by PrinciRaj1992
JavaScript
<script>
// Javascript program to determine if the element
// exists for different range queries
// Structure to represent a query range
class Query
{
constructor(L, R, X)
{
this.L = L;
this.R = R;
this.X = X;
}
};
let maxn = 100;
let root = new Array(maxn);
// Find the root of the group containing
// the element at index x
function find(x)
{
if(x == root[x])
return x;
else
return root[x] = find(root[x]);
}
// merge the two groups containing elements
// at indices x and y into one group
function uni(x, y)
{
let p = find(x), q = find(y);
if (p != q)
{
root[p] = root[q];
}
}
function initialize(a, n, q, m)
{
// make n subsets with every
// element as its root
for (let i = 0; i < n; i++)
root[i] = i;
// consecutive elements equal in value are
// merged into one single group
for (let i = 1; i < n; i++)
if (a[i] == a[i - 1])
uni(i, i - 1);
}
// Driver code
let a = [ 1, 1, 5, 4, 5 ];
let n = a.length;
let q = [ new Query(0, 2, 2 ),
new Query( 1, 4, 1 ),
new Query( 2, 4, 5 ) ];
let m = q.length;
initialize(a, n, q, m);
for (let i = 0; i < m; i++)
{
let flag = 0;
let l = q[i].L, r = q[i].R, x = q[i].X;
let p = r;
while (p >= l)
{
// check if the current element in
// consideration is equal to x or not
// if it is equal, then x exists in the range
if (a[p] == x)
{
flag = 1;
break;
}
p = find(p) - 1;
}
// Print if x exists or not
if (flag != 0)
document.write(x + " exists between [" +
l + ", " + r + "] " + "<br>");
else
document.write(x + " does not exist between [" +
l + ", " + r + "] " + "<br>");
}
// This code is contributed by gfgking
</script>
Output2 does not exist between [0, 2]
1 exists between [1, 4]
5 exists between [2, 4]
Efficient Approach(Using Mo's Algorithm) :
Mo's algorithm is one of the finest applications for square root decomposition.
It is based on the basic idea of using the answer to the previous query to compute the answer for the current query. This is made possible because the Mo's algorithm is constructed in such a way that if F([L, R]) is known, then F([L + 1, R]), F([L - 1, R]), F([L, R + 1]) and F([L, R - 1]) can be computed easily, each in O(F) time.
Answering queries in the order they are asked, then the time complexity is not improved to what is needed to be. To reduce the time complexity considerably, the queries are divided into blocks and then sorted.
The exact algorithm to sort the queries is as follows :
- Denote BLOCK_SIZE = sqrt(N)
- All the queries with the same L/BLOCK_SIZE are put in the same block
- Within a block, the queries are sorted based on their R values
- The sort function thus compares two queries, Q1 and Q2 as follows:
Q1 must come before Q2 if: - L1/BLOCK_SIZE<L2/BLOCK_SIZE
- L1/BLOCK_SIZE=L2/BLOCK_SIZE and R1<R2
After sorting the queries, the next step is to compute the answer to the first query and consequently answer rest of the queries. To determine if a particular element exists or not, check the frequency of the element in that range. A non zero frequency confirms the existence of the element in that range.
To store the frequency of the elements, STL map has been used in the following code.
In the example given, first query after sorting the array of queries is {0, 2, 2}. Hash the frequencies of the elements in [0, 2] and then check the frequency of the element 2 from the map. Since, 2 occurs 0 times, print "No".
While processing the next query, which is {1, 4, 1} in this case, decrement the frequencies of the elements in the range [0, 1) and increment the frequencies of the elements in range [3, 4]. This step gives the frequencies of elements in [1, 4] and it can easily be seen from the map that 1 exists in this range.
Time complexity :
The pre-processing part, that is sorting the queries takes O(m Log m) time.
The index variable for R changes at most O(n * \sqrt{n}) times throughout the run and that for L changes its value at most O(m * \sqrt{n}) times. Hence, processing all queries takes O(n * \sqrt{n}) + O(m * \sqrt{n}) = O((m+n) * \sqrt{n}) time.
Space complexity:
The space complexity of the given program is O((m+n) * sqrt(n)) where n is the size of the input array a[] and m is the number of queries.
Below is the C++ implementation of the above idea :
C++
// CPP code to determine if the element
// exists for different range queries
#include <bits/stdc++.h>
using namespace std;
// Variable to represent block size.
// This is made global, so compare()
// of sort can use it.
int block;
// Structure to represent a query range
struct Query
{
int L, R, X;
};
// Function used to sort all queries so
// that all queries of same block are
// arranged together and within a block,
// queries are sorted in increasing order
// of R values.
bool compare(Query x, Query y)
{
// Different blocks, sort by block.
if (x.L / block != y.L / block)
return x.L / block < y.L / block;
// Same block, sort by R value
return x.R < y.R;
}
// Determines if the element is present for all
// query ranges. m is number of queries
// n is size of array a[].
void queryResults(int a[], int n, Query q[], int m)
{
// Find block size
block = (int)sqrt(n);
// Sort all queries so that queries of same
// blocks are arranged together.
sort(q, q + m, compare);
// Initialize current L, current R
int currL = 0, currR = 0;
// To store the frequencies of
// elements of the given range
map<int, int> mp;
// Traverse through all queries
for (int i = 0; i < m; i++) {
// L and R values of current range
int L = q[i].L, R = q[i].R, X = q[i].X;
// Decrement frequencies of extra elements
// of previous range. For example if previous
// range is [0, 3] and current range is [2, 5],
// then the frequencies of a[0] and a[1] are decremented
while (currL < L)
{
mp[a[currL]]--;
currL++;
}
// Increment frequencies of elements of current Range
while (currL > L)
{
mp[a[currL - 1]]++;
currL--;
}
while (currR <= R)
{
mp[a[currR]]++;
currR++;
}
// Decrement frequencies of elements of previous
// range. For example when previous range is [0, 10]
// and current range is [3, 8], then frequencies of
// a[9] and a[10] are decremented
while (currR > R + 1)
{
mp[a[currR - 1]]--;
currR--;
}
// Print if X exists or not
if (mp[X] != 0)
cout << X << " exists between [" << L
<< ", " << R << "] " << endl;
else
cout << X << " does not exist between ["
<< L << ", " << R << "] " << endl;
}
}
// Driver program
int main()
{
int a[] = { 1, 1, 5, 4, 5 };
int n = sizeof(a) / sizeof(a[0]);
Query q[] = { { 0, 2, 2 }, { 1, 4, 1 }, { 2, 4, 5 } };
int m = sizeof(q) / sizeof(q[0]);
queryResults(a, n, q, m);
return 0;
}
Java
// Java Program to compute sum of ranges for
// different range queries
import java.util.*;
// Class to represent a query range
class Query{
int L;
int R;
int x;
Query(int L, int R,int x){
this.L = L;
this.R = R;
this.x=x;
}
}
class Main{
// Prints sum of all query ranges. m is number of queries
// n is size of array a[].
static void queryResults(int a[], int n, ArrayList<Query> q, int m){
// Find block size
int block = (int) Math.sqrt(n);
// Sort all queries so that queries of same blocks
// are arranged together.
Collections.sort(q, new Comparator<Query>(){
// Function used to sort all queries so that all queries
// of the same block are arranged together and within a block,
// queries are sorted in increasing order of R values.
public int compare(Query x, Query y){
// Different blocks, sort by block.
if (x.L/block != y.L/block)
return (x.L < y.L ? -1 : 1);
// Same block, sort by R value
return (x.R < y.R ? -1 : 1);
}
});
// Initialize current L, current R and current sum
int currL = 0, currR = 0;
Map<Integer,Integer> mp=new HashMap<Integer,Integer>();
// Traverse through all queries
for (int i=0; i<m; i++)
{
// L and R values of current range
int L = q.get(i).L, R = q.get(i).R, X = q.get(i).x;
// Remove extra elements of previous range. For
// example if previous range is [0, 3] and current
// range is [2, 5], then a[0] and a[1] are subtracted
while (currL < L)
{
if(mp.containsKey(a[currL])){
mp.put(a[currL],mp.get(a[currL])-1);
}
else{
mp.put(a[currL],1);
}
//mp.put(a[currL], mp.get(a[currL] - 1));
currL++;
}
// Add Elements of current Range
while (currL > L)
{
if(mp.containsKey(a[currL-1])){
mp.put(a[currL-1],mp.get(a[currL-1])+1);
}
else{
mp.put(a[currL-1],1);
}
//mp.put(a[currL], mp.get(a[currL-1]+1));
currL--;
}
while (currR <= R)
{
if(mp.containsKey(a[currR])){
mp.put(a[currR],mp.get(a[currR])+1);
}
else{
mp.put(a[currR],1);
}
//mp.put(a[currR], mp.get(a[currR]+1));
currR++;
}
// Remove elements of previous range. For example
// when previous range is [0, 10] and current range
// is [3, 8], then a[9] and a[10] are subtracted
while (currR > R+1)
{
if(mp.containsKey(a[currR-1])){
mp.put(a[currR-1],mp.get(a[currR-1])-1);
}
else{
mp.put(a[currR-1],1);
//mp[a[currR-1]]--;
currR--;
}
}
if (mp.containsKey(X))
System.out.println(X + " exists between [" + L +
", " + R + "] ");
else
System.out.println(X + " does not exist between [" + L +
", " + R + "] ");
// Print sum of current range
}
}
// Driver program
public static void main(String argv[]){
ArrayList<Query> q = new ArrayList<Query>();
q.add(new Query(0,2,2));
q.add(new Query(1,4,1));
q.add(new Query(2,4,5));
int a[] = {1, 1, 5, 4, 5 };
queryResults(a, a.length, q, q.size());
}
}
// This code is contributed by Aarti_Rathi
Python3
from math import sqrt
# Function to determine if the element exists for different range queries
def query_results(a, n, q, m):
# Variable to represent block size
block = int(sqrt(n))
# Sort all queries so that queries of same blocks are arranged together
q = sorted(q, key=lambda x: (x[0] // block, x[1]))
# Initialize current L, current R
curr_l = 0
curr_r = 0
# To store the frequencies of elements of the given range
mp = {}
# Traverse through all queries
for i in range(m):
# L and R values of current range
l = q[i][0]
r = q[i][1]
x = q[i][2]
# Decrement frequencies of extra elements of previous range
while curr_l < l:
mp[a[curr_l]] -= 1
curr_l += 1
# Increment frequencies of elements of current Range
while curr_l > l:
mp[a[curr_l - 1]] = mp.get(a[curr_l - 1], 0) + 1
curr_l -= 1
while curr_r <= r:
mp[a[curr_r]] = mp.get(a[curr_r], 0) + 1
curr_r += 1
# Decrement frequencies of elements of previous range
while curr_r > r + 1:
mp[a[curr_r - 1]] -= 1
curr_r -= 1
# Print if X exists or not
if x in mp and mp[x] != 0:
print(f"{x} exists between [{l}, {r}]")
else:
print(f"{x} does not exist between [{l}, {r}]")
# Driver code
if __name__ == '__main__':
a = [1, 1, 5, 4, 5]
n = len(a)
q = [(0, 2, 2), (1, 4, 1), (2, 4, 5)]
m = len(q)
query_results(a, n, q, m)
C#
// C# Program to compute sum of ranges for
// different range queries
using System;
using System.Collections.Generic;
// Class to represent a query range
class Query {
public int L;
public int R;
public int x;
public Query(int L, int R, int x)
{
this.L = L;
this.R = R;
this.x = x;
}
}
class MainClass {
// Prints sum of all query ranges. m is number of
// queries n is size of array a[].
static void queryResults(int[] a, int n, List<Query> q,
int m)
{
// Find block size
int block = (int)Math.Sqrt(n);
// Sort all queries so that queries of same blocks
// are arranged together.
// Function used to sort all queries so that all
// queries of the same block are arranged together
// and within a block, queries are sorted in
// increasing order of R values.
q.Sort((x, y) => {
// Different blocks, sort by block.
if (x.L / block != y.L / block) {
return x.L / block - y.L / block;
}
// Same block, sort by R value
return x.R - y.R;
});
// Initialize current L, current R and current sum
int currL = 0, currR = -1;
Dictionary<int, int> mp
= new Dictionary<int, int>();
// Traverse through all queries
for (int i = 0; i < m; i++)
{
// L and R values of current range
int L = q[i].L, R = q[i].R, X = q[i].x;
// Add Elements of current Range
while (currL > L)
{
// mp.put(a[currL], mp.get(a[currL-1]+1));
currL--;
AddElement(mp, a[currL]);
}
while (currR < R)
{
// mp.put(a[currR], mp.get(a[currR]+1));
currR++;
AddElement(mp, a[currR]);
}
// Remove extra elements of previous range. For
// example if previous range is [0, 3] and
// current range is [2, 5], then a[0] and a[1]
// are subtracted
while (currL < L) {
RemoveElement(mp, a[currL]);
// mp.put(a[currL], mp.get(a[currL] - 1));
currL++;
}
// Remove elements of previous range. For
// example when previous range is [0, 10] and
// current range is [3, 8], then a[9] and a[10]
// are subtracted
while (currR > R) {
RemoveElement(mp, a[currR]);
// mp[a[currR-1]]--;
currR--;
}
if (mp.ContainsKey(X)) {
Console.WriteLine(X + " exists between ["
+ L + ", " + R + "]");
}
else {
Console.WriteLine(
X + " does not exist between [" + L
+ ", " + R + "]");
}
}
}
static void AddElement(Dictionary<int, int> mp, int key)
{
if (mp.ContainsKey(key)) {
mp[key]++;
}
else {
mp[key] = 1;
}
}
static void RemoveElement(Dictionary<int, int> mp,
int key)
{
if (mp.ContainsKey(key)) {
mp[key]--;
if (mp[key] == 0) {
mp.Remove(key);
}
}
}
// Driver Code
public static void Main()
{
List<Query> q = new List<Query>();
q.Add(new Query(0, 2, 2));
q.Add(new Query(1, 4, 1));
q.Add(new Query(2, 4, 5));
int[] a = { 1, 1, 5, 4, 5 };
queryResults(a, a.Length, q, q.Count);
}
}
// akashish__
JavaScript
// Variable to represent block size.
// This is made global, so compare()
// of sort can use it.
let block;
// Structure to represent a query range
class Query {
constructor(L, R, X) {
this.L = L;
this.R = R;
this.X = X;
}
}
// Function used to sort all queries so
// that all queries of same block are
// arranged together and within a block,
// queries are sorted in increasing order
// of R values.
function compare(x, y) {
// Different blocks, sort by block.
if (Math.floor(x.L / block) !== Math.floor(y.L / block)) {
return Math.floor(x.L / block) - Math.floor(y.L / block);
}
// Same block, sort by R value
return x.R - y.R;
}
// Determines if the element is present for all
// query ranges. m is number of queries
// n is size of array a[].
function queryResults(a, n, q, m) {
// Find block size
block = Math.floor(Math.sqrt(n));
// Sort all queries so that queries of same
// blocks are arranged together.
q.sort(compare);
// Initialize current L, current R
let currL = 0;
let currR = 0;
// To store the frequencies of
// elements of the given range
const mp = new Map();
// Traverse through all queries
for (let i = 0; i < m; i++) {
// L and R values of current range
const {
L,
R,
X
} = q[i];
// Decrement frequencies of extra elements
// of previous range. For example if previous
// range is [0, 3] and current range is [2, 5],
// then the frequencies of a[0] and a[1] are decremented
while (currL < L) {
const value = mp.get(a[currL]);
if (value === 1) {
mp.delete(a[currL]);
} else {
mp.set(a[currL], value - 1);
}
currL++;
}
// Increment frequencies of elements of current Range
while (currL > L) {
currL--;
const value = mp.get(a[currL]);
mp.set(a[currL], value ? value + 1 : 1);
}
while (currR <= R) {
const value = mp.get(a[currR]);
mp.set(a[currR], value ? value + 1 : 1);
currR++;
}
// Decrement frequencies of elements of previous
// range. For example when previous range is [0, 10]
// and current range is [3, 8], then frequencies of
// a[9] and a[10] are decremented
while (currR > R + 1) {
currR--;
const value = mp.get(a[currR]);
if (value) {
mp.set(a[currR], value - 1);
}
}
// Print if X exists or not.
if (mp.get(X) !== undefined && mp.get(X) > 0)
console.log(`${X} exists between [${L}, ${R}]`);
else
console.log(`${X} does not exist between [${L}, ${R}]`);
}
}
// Driver program
const a = [1, 1, 5, 4, 5];
const n = a.length;
let q = [new Query(0, 2, 2), new Query(1, 4, 1), new Query(2, 4, 5)];
let m = q.length;
queryResults(a, n, q, m);
Output2 does not exist between [0, 2]
1 exists between [1, 4]
5 exists between [2, 4]
Similar Reads
Basics & Prerequisites
Data Structures
Array Data StructureIn this article, we introduce array, implementation in different popular languages, its basic operations and commonly seen problems / interview questions. An array stores items (in case of C/C++ and Java Primitive Arrays) or their references (in case of Python, JS, Java Non-Primitive) at contiguous
3 min read
String in Data StructureA string is a sequence of characters. The following facts make string an interesting data structure.Small set of elements. Unlike normal array, strings typically have smaller set of items. For example, lowercase English alphabet has only 26 characters. ASCII has only 256 characters.Strings are immut
2 min read
Hashing in Data StructureHashing is a technique used in data structures that efficiently stores and retrieves data in a way that allows for quick access. Hashing involves mapping data to a specific index in a hash table (an array of items) using a hash function. It enables fast retrieval of information based on its key. The
2 min read
Linked List Data StructureA linked list is a fundamental data structure in computer science. It mainly allows efficient insertion and deletion operations compared to arrays. Like arrays, it is also used to implement other data structures like stack, queue and deque. Hereâs the comparison of Linked List vs Arrays Linked List:
2 min read
Stack Data StructureA Stack is a linear data structure that follows a particular order in which the operations are performed. The order may be LIFO(Last In First Out) or FILO(First In Last Out). LIFO implies that the element that is inserted last, comes out first and FILO implies that the element that is inserted first
2 min read
Queue Data StructureA Queue Data Structure is a fundamental concept in computer science used for storing and managing data in a specific order. It follows the principle of "First in, First out" (FIFO), where the first element added to the queue is the first one to be removed. It is used as a buffer in computer systems
2 min read
Tree Data StructureTree Data Structure is a non-linear data structure in which a collection of elements known as nodes are connected to each other via edges such that there exists exactly one path between any two nodes. Types of TreeBinary Tree : Every node has at most two childrenTernary Tree : Every node has at most
4 min read
Graph Data StructureGraph Data Structure is a collection of nodes connected by edges. It's used to represent relationships between different entities. If you are looking for topic-wise list of problems on different topics like DFS, BFS, Topological Sort, Shortest Path, etc., please refer to Graph Algorithms. Basics of
3 min read
Trie Data StructureThe Trie data structure is a tree-like structure used for storing a dynamic set of strings. It allows for efficient retrieval and storage of keys, making it highly effective in handling large datasets. Trie supports operations such as insertion, search, deletion of keys, and prefix searches. In this
15+ min read
Algorithms
Searching AlgorithmsSearching algorithms are essential tools in computer science used to locate specific items within a collection of data. In this tutorial, we are mainly going to focus upon searching in an array. When we search an item in an array, there are two most common algorithms used based on the type of input
2 min read
Sorting AlgorithmsA Sorting Algorithm is used to rearrange a given array or list of elements in an order. For example, a given array [10, 20, 5, 2] becomes [2, 5, 10, 20] after sorting in increasing order and becomes [20, 10, 5, 2] after sorting in decreasing order. There exist different sorting algorithms for differ
3 min read
Introduction to RecursionThe process in which a function calls itself directly or indirectly is called recursion and the corresponding function is called a recursive function. A recursive algorithm takes one step toward solution and then recursively call itself to further move. The algorithm stops once we reach the solution
14 min read
Greedy AlgorithmsGreedy algorithms are a class of algorithms that make locally optimal choices at each step with the hope of finding a global optimum solution. At every step of the algorithm, we make a choice that looks the best at the moment. To make the choice, we sometimes sort the array so that we can always get
3 min read
Graph AlgorithmsGraph is a non-linear data structure like tree data structure. The limitation of tree is, it can only represent hierarchical data. For situations where nodes or vertices are randomly connected with each other other, we use Graph. Example situations where we use graph data structure are, a social net
3 min read
Dynamic Programming or DPDynamic Programming is an algorithmic technique with the following properties.It is mainly an optimization over plain recursion. Wherever we see a recursive solution that has repeated calls for the same inputs, we can optimize it using Dynamic Programming. The idea is to simply store the results of
3 min read
Bitwise AlgorithmsBitwise algorithms in Data Structures and Algorithms (DSA) involve manipulating individual bits of binary representations of numbers to perform operations efficiently. These algorithms utilize bitwise operators like AND, OR, XOR, NOT, Left Shift, and Right Shift.BasicsIntroduction to Bitwise Algorit
4 min read
Advanced
Segment TreeSegment Tree is a data structure that allows efficient querying and updating of intervals or segments of an array. It is particularly useful for problems involving range queries, such as finding the sum, minimum, maximum, or any other operation over a specific range of elements in an array. The tree
3 min read
Pattern SearchingPattern searching algorithms are essential tools in computer science and data processing. These algorithms are designed to efficiently find a particular pattern within a larger set of data. Patten SearchingImportant Pattern Searching Algorithms:Naive String Matching : A Simple Algorithm that works i
2 min read
GeometryGeometry is a branch of mathematics that studies the properties, measurements, and relationships of points, lines, angles, surfaces, and solids. From basic lines and angles to complex structures, it helps us understand the world around us.Geometry for Students and BeginnersThis section covers key br
2 min read
Interview Preparation
Practice Problem