Next Greater Element Using Stack in DSA C++ - Time & Space Complexity
We want to understand how the time needed to find the next greater element changes as the input size grows.
How does the number of steps grow when we check each element against others using a stack?
Analyze the time complexity of the following code snippet.
#include <iostream>
#include <stack>
#include <vector>
std::vector<int> nextGreaterElement(const std::vector<int>& nums) {
std::stack<int> s;
std::vector<int> result(nums.size(), -1);
for (int i = 0; i < (int)nums.size(); ++i) {
while (!s.empty() && nums[i] > nums[s.top()]) {
result[s.top()] = nums[i];
s.pop();
}
s.push(i);
}
return result;
}
This code finds the next greater element for each number in the list using a stack.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: A single loop through the array with a nested while loop that pops from the stack.
- How many times: Each element is pushed once and popped at most once from the stack.
As the input size grows, each element is processed a limited number of times.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 20 operations (push and pop combined) |
| 100 | About 200 operations |
| 1000 | About 2000 operations |
Pattern observation: The operations grow roughly in a straight line with input size, not faster.
Time Complexity: O(n)
This means the time to find the next greater element grows directly in proportion to the number of elements.
[X] Wrong: "The nested while loop makes this code O(n²) because it looks like two loops inside each other."
[OK] Correct: Each element is pushed and popped only once, so the total work inside the while loop across all iterations is at most n, keeping it linear.
Understanding this pattern shows you how to use stacks to solve problems efficiently, a skill that helps in many coding challenges and real projects.
"What if we changed the input to a linked list instead of an array? How would the time complexity change?"
Practice
Solution
Step 1: Understand the problem goal
The Next Greater Element problem aims to find, for each element, the first element to its right that is larger than it.Step 2: Identify the role of the stack
A stack helps track elements for which we haven't found a greater element yet, allowing efficient lookup of the next greater element.Final Answer:
The first greater element to the right of each element -> Option AQuick Check:
Next Greater Element = first bigger right element [OK]
- Confusing next greater with next smaller element
- Thinking it finds elements to the left
- Assuming it sums elements instead of finding one
Solution
Step 1: Recall correct stack declaration syntax in C++
The standard way to declare a stack of integers is std::stack<int> s; which creates an empty stack named s.Step 2: Identify incorrect syntax in other options
stack<int> s = new stack<int>(); uses 'new' which is not needed and incorrect here. std::stack s<int>; has wrong template syntax. stack<int> s(); declares a function, not a stack variable.Final Answer:
std::stack<int> s; -> Option DQuick Check:
std::stack<int> s; is correct stack declaration [OK]
- Using 'new' keyword incorrectly
- Wrong template syntax like s<int>
- Declaring stack as a function
std::vector<int> arr = {4, 5, 2, 25};
std::vector<int> nge(arr.size(), -1);
std::stack<int> s;
for (int i = 0; i < arr.size(); i++) {
while (!s.empty() && arr[i] > arr[s.top()]) {
nge[s.top()] = arr[i];
s.pop();
}
s.push(i);
}
for (int x : nge) std::cout << x << " ";Solution
Step 1: Trace the loop and stack operations
Start with empty stack and nge = [-1, -1, -1, -1]. - i=0: push 0 (value 4) - i=1: 5 > 4, so nge[0]=5, pop 0, push 1 - i=2: 2 < 5, push 2 - i=3: 25 > 2, nge[2]=25, pop 2; 25 > 5, nge[1]=25, pop 1; push 3Step 2: Final nge array after loop
nge = [5, 25, 25, -1]. Print outputs with spaces: "5 25 25 -1 "Final Answer:
5 25 25 -1 -> Option CQuick Check:
Next Greater Elements = 5 25 25 -1 [OK]
- Printing values instead of indices
- Not popping stack after updating nge
- Confusing greater with smaller elements
std::vector<int> arr = {2, 7, 3, 5, 4, 6, 8};
std::vector<int> nge(arr.size(), -1);
std::stack<int> s;
for (int i = arr.size() - 1; i >= 0; i--) {
while (!s.empty() && arr[i] > s.top()) {
s.pop();
}
if (!s.empty()) nge[i] = s.top();
s.push(arr[i]);
}Solution
Step 1: Analyze stack usage in code
The stack stores values (arr[i]) but comparisons and nge assignments expect indices to access arr elements correctly.Step 2: Explain why storing indices is needed
Storing indices allows referencing original array elements for comparison and updating nge. Storing values breaks logic when multiple same values exist.Final Answer:
Stack should store indices, not values -> Option AQuick Check:
Stack stores indices for correct comparisons [OK]
- Storing values instead of indices in stack
- Looping in wrong direction without adjusting logic
- Initializing nge with wrong default values
{13, 7, 6, 12}, how would you modify the Next Greater Element algorithm using a stack to find the Next Greater Element to the LEFT instead of the right?Solution
Step 1: Understand direction change for Next Greater to LEFT
To find the next greater element on the left, we must scan from left to right, so we see all elements before current.Step 2: Use stack to track candidates and pop smaller elements
While scanning, pop elements smaller than current from stack. The top of stack after popping is the next greater element to the left.Final Answer:
Traverse array from left to right, use stack to track elements, pop smaller elements, assign top as NGE to left. -> Option BQuick Check:
Left NGE needs left-to-right scan and pop smaller elements [OK]
- Scanning right to left for left NGE
- Popping greater elements instead of smaller
- Confusing next greater with next smaller element
Ready to prove it?
Pass the test and this pattern moves unknown
