In competitive programming, a queue is a data structure that is often used to solve problems that involve tasks that need to be completed in a specific order. This article explores the queue data structure and identifies its role as a critical tool for overcoming coding challenges in competitive programming.
Table of Content
What is a Queue?
A Queue is a linear data structure that follows a First-In, First-Out (FIFO) order. This means that the first element added to the queue is the first element to be removed.
Why to use Queue?
Queues are a useful data structure for several reasons:
- FIFO Order: Queues ensure that elements are processed in the order they were added, which is crucial for situations where order matters.
- Dynamic Nature: Queues can grow or shrink dynamically, which can be useful when solving problems related to finding maximum/minimum in subarrays.
- Breadth-first search algorithm: The breadth-first search algorithm uses a queue to explore nodes in a graph level-by-level. The algorithm starts at a given node, adds its neighbors to the queue, and then processes each neighbor in turn.
Idea behind a Queue
The idea behind a queue is to maintain a sequence of elements where new elements are added at one end and elements are removed from the other end. This is similar to how a line of people waiting for service operates. The person who has been waiting the longest is at the front of the line (first to be served), and new people join the line at the back (last to be served).
Use Cases of Queue in Competitive Programming
1. Min/Max Queue:
Min/max queue is a modified queue which supports finding the minimum and maximum elements in the queue efficiently. In addition to the standard enqueue and dequeue operations, a min/max queue provides operations to retrieve the current minimum or maximum element in the queue in constant time (O(1)).
Method 1: Using Dequeue and Queue
The idea is to use Doubly Ended Queue to store in increasing order if the structure is to return the minimum element and store in decreasing order if the structure is to return the maximum element.
Method 2: Using Dequeue of pairs
This method is used when we want to remove elements without knowing which element we have to remove. This is done by storing element along with the index and keeping track of how many elements we have added or removed.
Implementation:
#include <bits/stdc++.h> using namespace std;
class MinQueue {
// Dequee to implement Min Queue
deque<pair< int , int >> q;
// Data members to store the count of elements added and removed so far
int added, removed;
public :
MinQueue() {
added = removed = 0;
}
// Method to return the min element present in the queue
int getMin() {
return q.front().first;
}
// Method to insert element in the queue
void enqueueElement( int ele) {
while (!q.empty() && q.back().first > ele)
q.pop_back();
q.push_back({ele, added++});
}
// Method to remove element from the queue
void dequeueElement() {
if (!q.empty() && q.front().second == removed)
q.pop_front();
removed++;
}
}; int main() {
MinQueue minQ;
minQ.enqueueElement(10);
minQ.enqueueElement(5);
cout << minQ.getMin() << "\n" ;
minQ.enqueueElement(3);
minQ.dequeueElement();
minQ.dequeueElement();
cout << minQ.getMin() << "\n" ;
return 0;
} |
import java.util.ArrayDeque;
import java.util.Deque;
class MinQueue {
// Deque to implement Min Queue
private Deque<Pair<Integer, Integer>> q;
// Data members to store the count of elements added and removed so far
private int added, removed;
public MinQueue() {
q = new ArrayDeque<>();
added = removed = 0 ;
}
// Method to return the min element present in the queue
public int getMin() {
return q.getFirst().getKey();
}
// Method to insert element in the queue
public void enqueueElement( int ele) {
while (!q.isEmpty() && q.getLast().getKey() > ele) {
q.removeLast();
}
q.addLast( new Pair<>(ele, added++));
}
// Method to remove element from the queue
public void dequeueElement() {
if (!q.isEmpty() && q.getFirst().getValue() == removed) {
q.removeFirst();
}
removed++;
}
public static void main(String[] args) {
MinQueue minQ = new MinQueue();
minQ.enqueueElement( 10 );
minQ.enqueueElement( 5 );
System.out.println(minQ.getMin());
minQ.enqueueElement( 3 );
minQ.dequeueElement();
minQ.dequeueElement();
System.out.println(minQ.getMin());
}
} class Pair<K, V> {
private K key;
private V value;
public Pair(K key, V value) {
this .key = key;
this .value = value;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
} |
# Python Implementation from collections import deque
class MinQueue:
def __init__( self ):
# Deque to implement Min Queue
self .q = deque()
# Data members to store the count of elements added and removed so far
self .added = 0
self .removed = 0
# Method to return the min element present in the queue
def get_min( self ):
return self .q[ 0 ][ 0 ]
# Method to insert element in the queue
def enqueue_element( self , ele):
while self .q and self .q[ - 1 ][ 0 ] > ele:
self .q.pop()
self .q.append((ele, self .added))
self .added + = 1
# Method to remove element from the queue
def dequeue_element( self ):
if self .q and self .q[ 0 ][ 1 ] = = self .removed:
self .q.popleft()
self .removed + = 1
if __name__ = = "__main__" :
min_q = MinQueue()
min_q.enqueue_element( 10 )
min_q.enqueue_element( 5 )
print (min_q.get_min())
min_q.enqueue_element( 3 )
min_q.dequeue_element()
min_q.dequeue_element()
print (min_q.get_min())
# This code is contributed by Tapessh(tapeshdua420) |
using System;
using System.Collections.Generic;
public class MinQueue
{ // Deque to implement Min Queue
private Queue<Tuple< int , int >> q = new Queue<Tuple< int , int >>();
// Data members to store the count of elements added and removed so far
private int added, removed;
public MinQueue()
{
added = removed = 0;
}
// Method to return the min element present in the queue
public int GetMin()
{
return q.Peek().Item1;
}
// Method to insert element in the queue
public void EnqueueElement( int ele)
{
while (q.Count > 0 && q.Peek().Item1 > ele)
q.Dequeue();
q.Enqueue(Tuple.Create(ele, added++));
}
// Method to remove element from the queue
public void DequeueElement()
{
if (q.Count > 0 && q.Peek().Item2 == removed)
q.Dequeue();
removed++;
}
} class Program
{ static void Main( string [] args)
{
MinQueue minQ = new MinQueue();
minQ.EnqueueElement(10);
minQ.EnqueueElement(5);
Console.WriteLine(minQ.GetMin());
minQ.EnqueueElement(3);
minQ.DequeueElement();
minQ.DequeueElement();
Console.WriteLine(minQ.GetMin());
}
} // This code is contributed by shivamgupta0987654321 |
// JS Implementation class MinQueue { constructor() {
// Deque to implement Min Queue
this .q = [];
// Data members to store the count of elements added and removed so far
this .added = 0;
this .removed = 0;
}
// Method to return the min element present in the queue
getMin() {
return this .q[0][0]; // The first element of the pair
}
// Method to insert element in the queue
enqueueElement(ele) {
while ( this .q.length > 0 && this .q[ this .q.length - 1][0] > ele) {
this .q.pop();
}
this .q.push([ele, this .added++]);
}
// Method to remove element from the queue
dequeueElement() {
if ( this .q.length > 0 && this .q[0][1] === this .removed) {
this .q.shift();
}
this .removed++;
}
} const minQ = new MinQueue();
minQ.enqueueElement(10); minQ.enqueueElement(5); console.log(minQ.getMin()); minQ.enqueueElement(3); minQ.dequeueElement(); minQ.dequeueElement(); console.log(minQ.getMin()); // This code is contributed by Sakshi |
5 3
Time Complexity: Since each element is added once and removed once, so both enqueue and dequeue have O(1) time complexity and we can find the min element by accessing the front of the queue so getMin() operation has O(1) time complexity as well.
Auxiliary Space: O(N) to store all elements in the queue.
2. Finding the minimum of all fixed-length subarrays:
If we are given an array of N numbers and we need to find the minimum/maximum of all subarrays of size K, then we can easily solve this my maintaining a min/max queue.
3. Shortest subarray with sum at least K (array can have negative integers as well):
If we are given an array of N integers (positive and negative) and we need to find the smallest length of a subarray whose sum >= K, then we can use a variation of min queue to get the smallest length. Refer this article to know more about using a deque to find the shortest subarray with sum at least K.
4. Graph Algorithms:
Queues are used in multiple graph algorithms like Breadth First Search, Topological Sort, Shortest Path Algorithms like Dijkstra’s Algorithm, etc.
5. To Calculate the longest Subarray with maximum absolute difference as K:
We can calculate the longest Subarray with maximum absolute difference using sliding window and two monotonic queues to keep track of the window max and window min.
Practice Problems on Queues for Competitive Programming:
Easy Level Problems on Queues:
Problem |
Problem Link |
---|---|
Medium Level Problems on Queues:
Problem |
Problem Link |
---|---|
Restricted Pacman |
|
Card Rotation |
|
Interleave the First Half of the Queue with Second Half |
Hard Level Problem on Queues:
Problem |
Problem Link |
---|---|
Longest subarray in which absolute difference between any two element is not greater than X |
Solve |
Shortest subarray with sum at least K (including negative numbers) |
Solve |