Algorithm

Next Greater Element II

Monotonic Stack Pattern

Next Greater Element II

Given a circular integer array nums (i.e., the next element of nums[nums.length - 1] is nums[0]), return the next greater number for every element in nums. The next greater number of a number x is the first greater number to its traversing-order next in the array, which means you could search circularly to find its next greater number. If it doesn't exist, return -1.

CONSTRAINTS
  • 1 <= nums.length <= 10⁴
  • -10⁹ <= nums[i] <= 10⁹
EXAMPLE 1
Input: nums = [1,2,1]
Output: [2,-1,2]
1's next greater is 2. 2 is the maximum. The second 1 wraps around to find index 1 (value 2).
EXAMPLE 2
Input: nums = [5,4,3,2,1]
Output: [-1,5,5,5,5]
5 has no greater neighbor. All other values wrap around to find 5.
Do we push elements during the second pass?
No. All elements are pushed during the first pass (i < N). The second pass is only used as a chance for those elements to find a 'Next Greater' neighbor from the start of the array.
Can we use this for 'Next Smaller'?
Absolutely. Just flip the comparison logic (current_val < nums[stack.peek()]) and maintain an Increasing Stack instead.

Same question as the plain next-greater problem — for each number, find the first larger number to its right — except the array is a circle: after the last element you wrap around to the front, so even the final element gets to look at everything before it. A number gets -1 only if nothing in the entire circle beats it.

The engine here is a monotonic stack: a normal stack (push/pop at one end) that we deliberately keep in decreasing order of value. The idea is that we hold the numbers still waiting for a bigger neighbor, and the moment a bigger number arrives it resolves them. Why does the stack stay decreasing? Because any waiting number is removed the instant something larger passes it, so a bigger newcomer can never sit on top of a smaller old-timer — it would have popped it first. We store indices, not values, since the answer is position-based and the array can contain duplicates.

To handle the wrap-around without actually copying the array, walk an index i from 0 to 2N - 1 and read nums[i % N], which replays the array twice. The two laps play different roles:
- First lap (i < N): business as usual — while the current value beats the value at the top index, that top index just found its next-greater; pop and record it. Then push the current index to wait.
- Second lap (i >= N): do not push anything new. Every index already had its turn as a waiter in the first lap; the replay exists only so leftover waiters from the tail can finally see the values sitting at the front of the array.

One extra lap is enough: after seeing every other element in the circle, a number that still hasn't been beaten genuinely has no next-greater, so it keeps its -1.

python
# Monotonic Stack over two laps (O(N) Time, O(N) Space)
n = len(nums)
res = [-1] * n
stack = []                       # holds indices; values kept decreasing

for i in range(2 * n):
    cur = nums[i % n]
    while stack and cur > nums[stack[-1]]:
        res[stack.pop()] = cur   # this waiting index found its next-greater
    if i < n:                    # only the first lap enrolls new waiters
        stack.append(i)

return res

Each index is pushed once and popped once over the 2N steps, so the whole thing is linear despite the inner loop.

Worked Example:[1, 2, 1]
- i=0 (val 1) → push index 0. Stack: [0]
- i=1 (val 2) → 2 > 1, so res[0]=2; pop 0, push 1. Stack: [1]
- i=2 (val 1) → 1 < 2, push index 2. Stack: [1, 2]
- i=3 (second lap, val 1) → not greater than top; no push.
- i=4 (second lap, val 2) → 2 > nums[2]=1, so res[2]=2; pop 2. Stack: [1]
- End → res = [2, -1, 2] (index 1 held the max, never beaten).

Flip the comparison to < and keep the stack increasing and the exact same machinery finds each element's next smaller number instead.

Interactive Strategy Visualization
CIRCULAR TRAVERSAL ENGINE

Next Greater Element II Strategy

Pass 1: Initial Scan
1
2
1
Stack
Next Greater
[0]: 1 →-
[1]: 2 →-
[2]: 1 →-

Mental Model

  • Circular Illusion: Iterate `2N` times with `% N` to wrap indices back.
  • Doubling Search: Pass 1 fills the stack with pending candidates; Pass 2 checks if start elements can satisfy them.
LOGICSTEP 1/8
Process circular [1, 2, 1]
HINT

Virtual Doubling

You don't need to copy the array. Just iterate `2 * N` times and use `i % N` to wrap indices back to the start. The logic is identical to the linear version!

O(N²) Brute Force
O(N) Double-Pass Monotonic Stack