Skip to content

503. Next Greater Element II (Medium)

Problem

Given a circular integer array nums, return the next greater number for every element. In a circular array, the search wraps around to the beginning if no greater element is found before the end.

Return -1 if no greater element exists at all (only possible if all elements are equal).

Examples

  • [1,2,1][2,-1,2]
    • 1 at index 0: next greater is 2 (index 1)
    • 2 at index 1: no greater element in the full circular scan: -1
    • 1 at index 2: wraps around to find 2 (index 1)
  • [1,2,3,4,3][2,3,4,-1,4]
  • [5,4,3,2,1][-1,5,5,5,5]

LeetCode 503 · Link · Medium

Try it yourself

idle

Starter code: this editor begins with intentional TODOs. Fill the function, run the embedded tests, then compare your solution with the worked approaches below.

Click Run Python to execute. First run downloads Python (~10 MB, cached after that).

Approach 1: Brute force with circular wraparound

For each index, scan up to n steps forward (with wrap) looking for a strictly greater element.

def next_greater_elements(nums: list[int]) -> list[int]:
n = len(nums)
result = [-1] * n # L1: O(n)
for i in range(n): # L2: n iterations
for j in range(1, n): # L3: up to n-1 steps per i
k = (i + j) % n # L4: O(1) circular index
if nums[k] > nums[i]: # L5: O(1) compare
result[i] = nums[k]
break
return result

Complexity

  • Time: O(n2)O(n²), each of n elements scans up to n positions.
  • Space: O(1)O(1) extra.

Approach 2: Double traversal with monotonic index stack (optimal)

Simulate circularity by iterating indices 0 to 2n-1 and using i % n to wrap. The first pass fills answers for straightforward cases; the second pass fills wrap-around answers.

Use a monotonic decreasing stack that stores indices (not values). When the current value exceeds the value at the stack top, the stack top has found its next-greater answer.

def next_greater_elements(nums: list[int]) -> list[int]:
n = len(nums) # L1: O(1)
result = [-1] * n # L2: O(n) default -1
stack = [] # L3: O(1) stores indices
for i in range(2 * n): # L4: 2n iterations
while stack and nums[stack[-1]] < nums[i % n]: # L5: pop answered indices
result[stack.pop()] = nums[i % n] # L6: O(1) amortized
if i < n: # L7: only push original indices
stack.append(i) # L8: O(1) push index
return result

Where the time goes, line by line

Variables: n = len(nums).

LinePer-call costTimes executedContribution
L2 (init result)O(n)O(n)1O(n)O(n)
L4 (outer loop)O(1)O(1)2nO(n)O(n)
L5-L8 (stack ops)O(1)O(1) amortizedn total pushes/popsO(n)O(n) ← dominates

Each index is pushed once (guard i < n) and popped at most once. Total stack work across both passes is O(n)O(n).

Complexity

  • Time: O(n)O(n), the 2n loop with amortized O(1)O(1) stack work per step.
  • Space: O(n)O(n) for the result array and stack.

Try this approach:

idle
Click Run Python to execute. First run downloads Python (~10 MB, cached after that).

Circular traversal illustrated

nums = [1, 2, 1], n=3
result= [-1,-1,-1]
i=0 (1%3=0, val=1): stack empty, push 0. stack: [0]
i=1 (1%3=1, val=2): 2>nums[0]=1, pop 0, result[0]=2. push 1. stack: [1]
i=2 (2%3=2, val=1): 1<nums[1]=2, just push 2. stack: [1,2]
i=3 (3%3=0, val=1): i>=n, don't push. 1<nums[2]=1? no. stack: [1,2]
i=4 (4%3=1, val=2): i>=n, don't push. 2>nums[2]=1, pop 2, result[2]=2. stack: [1]
2>nums[1]=2? no. stack: [1]
i=5 (5%3=2, val=1): i>=n, don't push. 1<nums[1]=2? yes. stack: [1]
Remaining stack: [1], result[1] stays -1.
Final: [2, -1, 2]

Key takeaways

  • The “double array” trick (range(2*n) with i % n) is the standard way to simulate circularity for monotonic stack problems. No actual array duplication needed.
  • Store indices (not values) in the stack when you need to write back to a result array.
  • Only push during the first pass (i < n). The second pass only processes existing stack entries, not adds new ones. This keeps the total push count at n.
  • Elements left on the stack after both passes have no greater element anywhere in the circle: their default -1 stands.
  • Monotonic Stack, the ordered stack pattern for nearest greater, nearest smaller, and spans.
  • Array Scans, the linear pass habit of carrying just enough state while reading each item once.