Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
Next Greater Element in Circular Array in JavaScript
Circular Array
An array in which the next element of the last element is the first element of the array is often termed as circular. This concept allows us to treat arrays as if they wrap around, where after the last index, we continue from the first index.
Obviously, there exists no such mechanism to store data like this. Data will still be stored in continuous memory blocks, and circular arrays are more like a logical concept than physical reality.
Problem
We need to find the next greater element for each element in a circular array. The Next Greater Element is the first element greater than the current element when traversing to the right. If no greater element exists, we return -1.
Since the array is circular, after reaching the end, we continue searching from the beginning.
Example Input and Output
For example, if the input array is:
const arr = [7, 8, 7];
The expected output is:
[8, -1, 8]
Output Explanation
For the first 7 at index 0, the next greater element is 8 at index 1. For 8 at index 1, no greater element exists, so we return -1. For the second 7 at index 2, we continue circularly and find 8 at index 1 as the next greater element.
Algorithm Using Stack
We use a stack-based approach that processes the array twice to handle the circular nature:
const arr = [7, 8, 7];
const nextGreaterElement = (arr = []) => {
const res = new Array(arr.length).fill(-1);
const stack = [];
if (!arr || arr.length < 1) {
return [];
}
// Process array twice to handle circular nature
for (let i = 0; i < arr.length * 2; i++) {
const currentIndex = i % arr.length;
// Pop elements from stack that are smaller than current element
while (stack.length > 0 && arr[stack[stack.length - 1]] < arr[currentIndex]) {
const smallerIndex = stack.pop();
res[smallerIndex] = arr[currentIndex];
}
// Only push indices in first traversal
if (i < arr.length) {
stack.push(currentIndex);
}
}
return res;
};
console.log(nextGreaterElement(arr));
[8, -1, 8]
How It Works
The algorithm uses a stack to keep track of indices of elements for which we haven't found the next greater element yet:
- Initialize: Create a result array filled with -1 and an empty stack
- Double traversal: Process the array twice (2 * length iterations) using modulo to simulate circular behavior
- Stack operations: For each element, pop smaller elements from stack and set their next greater element
- Push indices: Only push indices during the first traversal to avoid duplicates
Step-by-Step Execution
// Tracing through [7, 8, 7]
const arr = [7, 8, 7];
console.log("Input:", arr);
// Step-by-step execution
let res = [-1, -1, -1];
let stack = [];
console.log("i=0: arr[0]=7, stack=[], push 0");
stack.push(0);
console.log("i=1: arr[1]=8 > arr[0]=7, pop 0, res[0]=8, push 1");
res[0] = 8;
stack = [1];
console.log("i=2: arr[2]=7 < arr[1]=8, push 2");
stack.push(2);
console.log("i=3: arr[0]=7 < arr[1]=8, no change");
console.log("i=4: arr[1]=8 > arr[2]=7, pop 2, res[2]=8");
res[2] = 8;
console.log("Final result:", res);
Input: [7, 8, 7] i=0: arr[0]=7, stack=[], push 0 i=1: arr[1]=8 > arr[0]=7, pop 0, res[0]=8, push 1 i=2: arr[2]=7 < arr[1]=8, push 2 i=3: arr[0]=7 < arr[1]=8, no change i=4: arr[1]=8 > arr[2]=7, pop 2, res[2]=8 Final result: [8, -1, 8]
Testing with Different Arrays
const nextGreaterElement = (arr = []) => {
const res = new Array(arr.length).fill(-1);
const stack = [];
if (!arr || arr.length < 1) {
return [];
}
for (let i = 0; i < arr.length * 2; i++) {
const currentIndex = i % arr.length;
while (stack.length > 0 && arr[stack[stack.length - 1]] < arr[currentIndex]) {
const smallerIndex = stack.pop();
res[smallerIndex] = arr[currentIndex];
}
if (i < arr.length) {
stack.push(currentIndex);
}
}
return res;
};
// Test cases
console.log("Test 1:", nextGreaterElement([7, 8, 7]));
console.log("Test 2:", nextGreaterElement([1, 2, 3, 4, 3]));
console.log("Test 3:", nextGreaterElement([5, 4, 3, 2, 1]));
console.log("Test 4:", nextGreaterElement([1]));
Test 1: [8, -1, 8] Test 2: [2, 3, 4, -1, 4] Test 3: [-1, -1, -1, -1, -1] Test 4: [-1]
Time and Space Complexity
Time Complexity: O(n) where n is the length of the array. Each element is pushed and popped at most once.
Space Complexity: O(n) for the stack and result array.
Conclusion
The stack-based approach efficiently finds the next greater element in a circular array by processing the array twice. This technique leverages the circular property while maintaining optimal time complexity.
