Open in App
Not now

Introduction to Monotonic Queues

• Last Updated : 20 Mar, 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 ` `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` `    ``increasing_monotonic_queue(``int` `arr[], ``int` `n)` `    ``{`   `        ``Deque q = ``new` `LinkedList();` `        ``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 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 + ``" "``);` `});`

Output

`1 2 3 4 5 6 `

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 ` `#include ` `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 addded 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` `    ``decreasing_monotonic_queue(``int``[] arr)` `  ``{` `    ``Deque 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 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)`

Output

`6 5 4 3 2 1 `

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)