Next Greater Element I
The next greater element of some element x in an array is the first greater element that is to the right of x in the same array. You are given two distinct 0-indexed integer arrays nums1 and nums2, where nums1 is a subset of nums2. For each element of nums1, find the next greater element in nums2. Return an integer array ans such that ans[i] is the next greater element of nums1[i] in nums2, or -1 if it does not exist.
- 1 <= nums1.length <= nums2.length <= 1000
- 0 <= nums1[i], nums2[i] <= 10⁴
- All integers in nums1 and nums2 are unique
- nums1 is a subset of nums2
nums1 = [4,1,2], nums2 = [1,3,4,2][-1,3,-1]nums1 = [3,2,1,4], nums2 = [3,2,1,4][4,4,4,-1]Finding the first number to the right that is strictly larger than our current number is a classic search problem. A naive approach would be to scan forward from every number in nums1 across nums2 until we find a larger one. However, this repeats a massive amount of work, especially in a decreasing list, leading to O(N * M) time complexity.
# Brute Force (O(N * M) Time, O(1) Space)
res = []
for x in nums1:
# Find x in nums2
start_idx = nums2.index(x)
found = False
# Scan right for the first greater element
for j in range(start_idx + 1, len(nums2)):
if nums2[j] > x:
res.append(nums2[j])
found = True
break
if not found:
res.append(-1)
return resThe Monotonic Stack is the perfect structural fit for this challenge. It is designed specifically to find the "nearest neighbor" with a certain property in a single pass. By maintaining elements in a strict order (always increasing or decreasing), the stack acts as a "Waiting Room" where numbers stay until they are "resolved" by a future larger number. This eliminates redundant scans and ensures every element is processed exactly once.
The optimal strategy works as follows:
- Arrival: We scan the array from left to right. Every number we see is a potential "Challenger" to those already in the Waiting Room.
- Challenge: Before a new number sits down, it compares itself to the person at the head of the room (the top of the stack). If the new number is larger, it has found that person's "Next Greater" neighbor.
- Resolve: We record the result in a map, "pop" the resolved person out of the room, and the new number continues to challenge the next person in line.
- Wait: Once the new number finds someone larger than itself (or the room is empty), it finally sits down in the stack to wait for its own future challenger.
# Monotonic Stack (O(N + M) Time, O(M) Space)
stack = []
mapping = {}
for num in nums2:
# Current num challenges everyone in the stack
while stack and num > stack[-1]:
resolved_num = stack.pop()
mapping[resolved_num] = num
# New num enters the waiting room
stack.append(num)
# Answer the specific queries from nums1
return [mapping.get(x, -1) for x in nums1]Because every element enters the stack once and leaves once, the entire process takes strictly linear time. Any numbers left in the stack at the end simply never found a larger neighbor to their right.
Next Greater Element Strategy
Mental Model
- Stack as a Lobby: Elements wait in the stack until they meet someone "greater".
- Descending Order: Since we pop on larger elements, the stack stays sorted descending.
Pre-processing with Map
By using a Hash Map, we store results for every number in `nums2`. This makes getting results for `nums1` a simple O(1) lookup!