Introduction to Monotonic Queues
Last Updated :
05 May, 2023
A monotonic queue is a data structure that supports efficient insertion, deletion, and retrieval of elements in a specific order, typically in increasing or decreasing order.
The monotonic queue can be implemented using different data structures, such as a linked list, stack, or deque. The most common implementation is using a deque (double-ended queue) container. The deque container allows efficient insertion and deletion of elements from both the front and back of the queue, which is useful for implementing a monotonic queue.
There are two main types of monotonic queues:
- Increasing Monotonic Queue: It only keeps elements in increasing order, and any element that is smaller than the current minimum is removed.
- Decreasing Monotonic Queue: It only keeps elements in decreasing order, and any element that is larger than the current maximum is removed.
Implement the idea below to solve the Increasing Monotonic Queue problem:
- The function starts by initializing an empty deque called q.
- Then, it loops through the input array. For each element in the array, it checks if the deque is not empty and if the last element in the deque is greater than the current element in the array.
- If this condition is true, the last element in the deque is popped out. This is because we only want to keep elements in increasing order and any element that is smaller than the current minimum is removed.
- After that, the current element in the array is pushed into the deque.
- This process is repeated for all elements in the input array
- At the end of the function, the deque containing the increasing monotonic queue is returned.
Here's an example of an increasing monotonic queue implemented in C++:
C++
// C++ code for the above approach:
#include <bits/stdc++.h>
using namespace std;
// Function to solve Increasing
// Monotonic queue
deque<int> increasing_monotonic_queue(int arr[], int n)
{
deque<int> q;
for (int i = 0; i < n; i++) {
// If recently added element is
// greater current element
while (!q.empty() && q.back() > arr[i]) {
q.pop_back();
}
q.push_back(arr[i]);
}
return q;
}
// Driver code
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6 };
int n = sizeof(arr) / sizeof(arr[0]);
// Function call
deque<int> q = increasing_monotonic_queue(arr, n);
for (int i : q) {
cout << i << " ";
}
return 0;
}
Java
// Java code for the above approach:
import java.util.*;
class GFG {
// Function to solve Increasing
// Monotonic queue
static Deque<Integer>
increasing_monotonic_queue(int arr[], int n)
{
Deque<Integer> q = new LinkedList<Integer>();
for (int i = 0; i < n; i++) {
// If recently added element is
// greater current element
while (!q.isEmpty() && q.getLast() > arr[i]) {
q.removeLast();
}
q.addLast(arr[i]);
}
return q;
}
// Driver code
public static void main(String[] args)
{
int arr[] = { 1, 2, 3, 4, 5, 6 };
int n = arr.length;
// Function call
Deque<Integer> q
= increasing_monotonic_queue(arr, n);
Iterator it = q.iterator();
while (it.hasNext()) {
System.out.print(it.next() + " ");
}
}
}
Python3
from collections import deque
def increasing_monotonic_queue(arr, n):
q = deque()
for i in range(n):
while len(q) > 0 and q[-1] > arr[i]:
q.pop()
q.append(arr[i])
return q
arr = [1, 2, 3, 4, 5, 6]
n = len(arr)
q = increasing_monotonic_queue(arr, n)
for i in q:
print(i, end=' ')
C#
// C# code for the above approach:
using System;
using System.Collections.Generic;
public class GFG {
// Function to solve Increasing Monotonic queue
static Queue<int> IncreasingMonotonicQueue(int[] arr)
{
Queue<int> q = new Queue<int>();
for (int i = 0; i < arr.Length; i++) {
// If recently added element is greater than the
// current element
while (q.Count > 0 && q.Peek() > arr[i]) {
q.Dequeue();
}
q.Enqueue(arr[i]);
}
return q;
}
static public void Main()
{
// Code
int[] arr = { 1, 2, 3, 4, 5, 6 };
// Function call
Queue<int> q = IncreasingMonotonicQueue(arr);
foreach(int i in q) { Console.Write(i + " "); }
}
}
// This code is contributed by karthik.
JavaScript
// Function to solve Increasing
// Monotonic queue
function increasing_monotonic_queue(arr, n) {
const q = [];
for (let i = 0; i < n; i++) {
// If recently added element is greater than the current element
while (q.length > 0 && q[q.length - 1] > arr[i]) {
q.pop();
}
q.push(arr[i]);
}
return q;
}
// Driver code
const arr = [1, 2, 3, 4, 5, 6];
const n = arr.length;
const q = increasing_monotonic_queue(arr, n);
q.forEach((i) => {
process.stdout.write(i + " ");
});
Implement the idea below to solve the Decreasing Monotonic Queue problem:
- The function starts by initializing an empty deque called q.
- Then, it loops through the input array. For each element in the array, it checks if the deque is not empty and if the last element in the deque is smaller than the current element in the array.
- If this condition is true, the last element in the deque is popped out. This is because we only want to keep elements in decreasing order and any element that is larger than the current maximum is removed.
- After that, the current element in the array is pushed into the deque.
- This process is repeated for all elements in the input array
- At the end of the function, the deque containing the decreasing monotonic queue is returned.
Here is an example of a decreasing monotonic queue implemented in C++:
C++
// C++ code for the above approach
#include <deque>
#include <iostream>
using namespace std;
// Function to calculate Decreasing
// Monotonic queue
deque<int> decreasing_monotonic_queue(int arr[], int n)
{
deque<int> q;
for (int i = 0; i < n; i++) {
// If recently added element is
// smaller than current element
while (!q.empty() && q.back() < arr[i]) {
q.pop_back();
}
q.push_back(arr[i]);
}
return q;
}
// Driver Code
int main()
{
int arr[] = { 6, 5, 4, 3, 2, 1 };
int n = sizeof(arr) / sizeof(arr[0]);
// Function call
deque<int> q = decreasing_monotonic_queue(arr, n);
for (int i : q) {
cout << i << " ";
}
return 0;
}
Java
// Java code for the above approach
import java.io.*;
import java.util.*;
class GFG {
// Function to calculate Decreasing Monotonic queue
public static Deque<Integer>
decreasing_monotonic_queue(int[] arr)
{
Deque<Integer> q = new ArrayDeque<>();
int n = arr.length;
for (int i = 0; i < n; i++)
{
// If recently added element is smaller than
// current element
while (!q.isEmpty() && q.peekLast() < arr[i]) {
q.pollLast();
}
q.offerLast(arr[i]);
}
return q;
}
public static void main(String[] args)
{
int[] arr = { 6, 5, 4, 3, 2, 1 };
// Function call
Deque<Integer> q = decreasing_monotonic_queue(arr);
for (int i : q) {
System.out.print(i + " ");
}
}
}
// This code is contributed by sankar.
Python
from collections import deque
# Function to calculate Decreasing
# Monotonic queue
def decreasing_monotonic_queue(arr):
n = len(arr)
q = deque()
for i in range(n):
# If recently added element is
# smaller than current element
while q and q[-1] < arr[i]:
q.pop()
q.append(arr[i])
return q
# Driver Code
arr = [6, 5, 4, 3, 2, 1]
# Function call
q = decreasing_monotonic_queue(arr)
for i in q:
print(i)
C#
using System;
using System.Collections.Generic;
class Program
{
// Function to calculate Decreasing
// Monotonic queue
static LinkedList<int> decreasing_monotonic_queue(int[] arr, int n)
{
LinkedList<int> q = new LinkedList<int>();
for (int i = 0; i < n; i++)
{
// If recently added element is
// smaller than current element
while (q.Count > 0 && q.Last.Value < arr[i])
{
q.RemoveLast();
}
q.AddLast(arr[i]);
}
return q;
}
// Driver Code
static void Main()
{
int[] arr = { 6, 5, 4, 3, 2, 1 };
int n = arr.Length;
// Function call
LinkedList<int> q = decreasing_monotonic_queue(arr, n);
foreach (int i in q)
{
Console.Write(i + " ");
}
Console.WriteLine();
}
}
// This code is contributed by Prajwal Kandekar
JavaScript
// Function to calculate Decreasing
// Monotonic queue
function decreasingMonotonicQueue(arr) {
const n = arr.length;
const q = [];
for (let i = 0; i < n; i++) {
// If recently added element is
// smaller than current element
while (q.length && q[q.length - 1] < arr[i]) {
q.pop();
}
q.push(arr[i]);
}
return q;
}
// Driver Code
const arr = [6, 5, 4, 3, 2, 1];
// Function call
const q = decreasingMonotonicQueue(arr);
for (const i of q) {
process.stdout.write(i+' ');
}
Applications of monotonic queue include:
- Finding the maximum or minimum element in a sliding window
- Solving dynamic programming problems such as LIS (longest increasing subsequence) and LDS (longest decreasing subsequence)
Advantages of the monotonic queue:
- It is efficient in terms of both time and space complexity.
- It is easy to implement.
Disadvantages of the monotonic queue:
- It is not suitable for all types of problems, only those that involve finding the maximum or minimum element in a specific order
- It has limited functionality compared to more advanced data structures such as segment trees and Fenwick trees.
Similar Reads
Introduction to Queue Data Structure Queue is a linear data structure that follows FIFO (First In First Out) Principle, so the first element inserted is the first to be popped out. FIFO Principle in Queue:FIFO Principle states that the first element added to the Queue will be the first one to be removed or processed. So, Queue is like
5 min read
What is Priority Queue | Introduction to Priority Queue A priority queue is a type of queue that arranges elements based on their priority values. Each element has a priority associated. When we add an item, it is inserted in a position based on its priority.Elements with higher priority are typically retrieved or removed before elements with lower prior
6 min read
Queue Implementation in Python Queue is a linear data structure that stores items in a First In First Out (FIFO) manner. With a queue, the least recently added item is removed first. One can imagine a queue as a line of people waiting to receive something in sequential order which starts from the beginning of the line. It is an o
4 min read
Introduction to Monotonic Stack - Data Structure and Algorithm Tutorials A monotonic stack is a special data structure used in algorithmic problem-solving. Monotonic Stack maintaining elements in either increasing or decreasing order. It is commonly used to efficiently solve problems such as finding the next greater or smaller element in an array etc.Monotonic StackTable
12 min read
Monotonic Sequence Monotonic sequence is one of the simplest terms used in mathematics to refer to a number sequence that moves from a smaller value to a bigger value or vice versa; that is, it only increases or decreases. Different fields of study where this type of sequence is important include calculus, probability
8 min read
Priority Queue in Python A priority queue is like a regular queue, but each item has a priority. Instead of being served in the order they arrive, items with higher priority are served first. For example, In airlines, baggage labeled âBusinessâ or âFirst Classâ usually arrives before the rest. Key properties of priority que
3 min read