Problem: Design a Data Structure a SpecialQueue which supports following operations enqueue, deque, getMin() or getMax() where getMin() operation takes O(1) time.
Example:
Let the data to be inserted in queue be -
4, 2, 1, 6
Operation Queue Output
push(4) 4 -
push(2) 4, 2 -
push(1) 4, 2, 1 -
getMin() 4, 2, 1 1
push(6) 4, 2, 1, 6 -
pop() 2, 1, 6 4
pop() 1, 6 2
pop() 6 1
getMin() 6 6
// Notice the getMin() function call
// It returns the minimum element
// of all the values present in the queue
Approach: 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. The operations of the Data Structure is defined as follows:
Enqueue
- Insert the element into the queue structure.
- If the size of the Deque structure is empty that is the size of the Deque is 0. Then, Insert the element from the back.
- Otherwise, If there are some elements in the Deque structure then pop the elements out from the Deque until the back of the Deque is greater than the current element and then finally insert the element from back.
Deque
- If the first element of the Deque is equal to the front element of the queue then pop the elements out from the Queue and the Deque at the same time.
- Otherwise, Pop the element from the front of the queue to maintain the order of the elements.
Get Minimum
Return the front element of the Deque to get the minimum element of the current element of the queue.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
template < typename T>
class MinMaxQueue {
public :
queue<T> Q;
deque<T> D;
void enque_element(T element)
{
if (Q.size() == 0) {
Q.push(element);
D.push_back(element);
}
else {
Q.push(element);
while (!D.empty() && D.back() > element) {
D.pop_back();
}
D.push_back(element);
}
}
void deque_element()
{
if (Q.front() == D.front()) {
Q.pop();
D.pop_front();
}
else {
Q.pop();
}
}
T getMin() { return D.front(); }
};
int main()
{
MinMaxQueue< int > k;
int example[3] = { 1, 2, 4 };
for ( int i = 0; i < 3; i++) {
k.enque_element(example[i]);
}
cout << k.getMin() << "\n" ;
k.deque_element();
cout << k.getMin() << "\n" ;
}
|
Java
import java.io.*;
import java.util.*;
class SpecialQueue {
Queue<Integer> q;
Deque<Integer> dq;
public SpecialQueue()
{
q = new LinkedList<>();
dq = new ArrayDeque<>();
}
void enque( int data)
{
while (!dq.isEmpty() && dq.getLast() > data) {
dq.removeLast();
}
dq.addLast(data);
q.add(data);
}
void deque()
{
if (dq.getFirst() == q.peek()) {
dq.removeFirst();
}
q.remove();
}
int getMin() throws Exception
{
if (q.isEmpty())
throw new Exception( "Queue is Empty" );
else
return dq.getFirst();
}
public static void main(String[] args) throws Exception
{
SpecialQueue arr = new SpecialQueue();
arr.enque( 1 );
arr.enque( 2 );
arr.enque( 4 );
System.out.println(arr.getMin());
arr.deque();
System.out.println(arr.getMin());
}
}
|
Python3
from collections import deque as dq
class MinMaxQueue:
def __init__( self ):
self .Q = dq([])
self .D = dq([])
def enque_element( self , element):
if ( len ( self .Q) = = 0 ):
self .Q.append(element)
self .D.append(element)
else :
self .Q.append(element)
while ( self .D and
self .D[ - 1 ] > element):
self .D.pop()
self .D.append(element)
def deque_element( self ,):
if ( self .Q[ 0 ] = = self .D[ 0 ]):
self .Q.popleft()
self .D.popleft()
else :
self .Q.popleft()
def getMin( self ,):
return self .D[ 0 ]
if __name__ = = '__main__' :
k = MinMaxQueue()
example = [ 1 , 2 , 4 ]
for i in range ( 3 ):
k.enque_element(example[i])
print (k.getMin())
k.deque_element()
print (k.getMin())
|
C#
using System;
using System.Collections.Generic;
class SpecialQueue {
Queue< int > q;
List< int > dq;
public SpecialQueue()
{
q = new Queue< int >();
dq = new List< int >();
}
void Enque( int data)
{
while (dq.Count > 0 && dq[dq.Count - 1] > data) {
dq.RemoveAt(dq.Count - 1);
}
dq.Add(data);
q.Enqueue(data);
}
void Deque()
{
if (dq[0] == q.Peek()) {
dq.RemoveAt(0);
}
q.Dequeue();
}
int GetMin()
{
if (q.Count == 0) {
throw new Exception( "Queue is Empty" );
}
else {
return dq[0];
}
}
public static void Main( string [] args)
{
SpecialQueue arr = new SpecialQueue();
arr.Enque(1);
arr.Enque(2);
arr.Enque(4);
Console.WriteLine(arr.GetMin());
arr.Deque();
Console.WriteLine(arr.GetMin());
}
}
|
Javascript
class MinMaxQueue {
constructor() {
this .Q = [];
this .D = [];
}
enqueElement(element) {
if ( this .Q.length === 0) {
this .Q.push(element);
this .D.push(element);
} else {
this .Q.push(element);
while ( this .D.length > 0 && this .D[ this .D.length - 1] > element) {
this .D.pop();
}
this .D.push(element);
}
}
dequeElement() {
if ( this .Q[0] === this .D[0]) {
this .Q.shift();
this .D.shift();
} else {
this .Q.shift();
}
}
getMin() {
return this .D[0];
}
}
function main() {
const k = new MinMaxQueue();
const example = [1, 2, 4];
for (let i = 0; i < 3; i++) {
k.enqueElement(example[i]);
}
console.log(k.getMin());
k.dequeElement();
console.log(k.getMin());
}
main();
|
Time and Space of Complexity of Each Function:
enque function:
- Time complexity: O(N), where N is the number of elements in the deque
- Auxiliary Space: O(N)
deque() method:
- Time complexity: O(1)
- Auxiliary Space: O(1)
getMin() method:
- Time complexity: O(1)
- Auxiliary Space: O(1)
Feeling lost in the world of random DSA topics, wasting time without progress? It's time for a change! Join our DSA course, where we'll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 geeks!
Last Updated :
01 Nov, 2023
Like Article
Save Article