next-greater-element-i
Difficulty: Easy · Topic: Stack · Practice it on parikshan: /practice/next-greater-element-i/start
The story
A trading-research team at Renaissance Technologies asks: given a watch-list of stock tickers (nums1) and a reference universe of tickers in their daily-volume order (nums2), report, for each ticker on the watch-list, the volume of the next ticker in the reference universe that traded a higher daily volume. If no such ticker exists, report -1. The watch-list and the universe are guaranteed to be a subset relationship: every watch-list ticker appears in the universe, all values are distinct.
That is next-greater-element-i. It is the easy version of the monotonic-stack family, with a tiny indirection: the answers are reported for a subset of values, but the computation happens on the full reference array.
What's actually being asked
Given two arrays nums1 (length n) and nums2 (length m) with n <= m, where nums1 is a subset of nums2 and elements within each are distinct, for each value x in nums1, find the first value to the right of x in nums2 that is strictly greater than x. If none exists, return -1. Print the answers for nums1, in order.
The naive approach
For each x in nums1, find x in nums2, then scan rightward for the first greater. O(n * m). For n = m = 10^5, that is 10 billion. Times out.
The key insight
Compute the "next greater" for every element of nums2 once, store it in a hash map from value to its next-greater (or to -1), and then look up each value of nums1 in O(1). The "next greater for every element" computation is the canonical monotonic-stack pattern.
Two clean ways to do the stack pass:
-
Left-to-right with a decreasing stack of values (since values are distinct, we can store values directly): as we visit
nums2[i], pop stack values that are< nums2[i]; each pop's "next greater" isnums2[i]. Pushnums2[i]. After the pass, any value still on the stack has next-greater = -1. -
Right-to-left with a decreasing stack of values: standard right-to-left "next greater". Same time complexity, mirror-image code.
Either way: O(m) to build the map, O(n) to answer. Total O(n + m).
Step-by-step approach
next_greater = {}(will map value to its next-greater value).stack = [](will hold values, since values are distinct).- For each
vinnums2:- While
stackis non-empty andstack[-1] < v:next_greater[stack.pop()] = v.
- Push
vontostack.
- While
- For any value still on
stack:next_greater[value] = -1for each. - For each
xinnums1, appendnext_greater[x]to the answer. - Print the answer.
Worked example
nums1 = [4, 1, 2]
nums2 = [1, 3, 4, 2]
Pass over nums2:
| i | v | stack before | pops (with next_greater) | stack after |
|---|---|---|---|---|
| 0 | 1 | [] | - | [1] |
| 1 | 3 | [1] | pop 1, next_greater[1]=3 | [3] |
| 2 | 4 | [3] | pop 3, next_greater[3]=4 | [4] |
| 3 | 2 | [4] | (4 > 2) | [4, 2] |
Cleanup: stack has [4, 2]. next_greater[4] = -1, next_greater[2] = -1.
Final map: {1:3, 3:4, 4:-1, 2:-1}.
Answer for nums1:
4-> -11-> 32-> -1
Output: -1 3 -1.
Complexity
- Time: O(n + m).
- Space: O(m) for the stack and map.
The brute force is O(n * m). The monotonic stack converts the inner search into amortised constant time.
Common pitfalls
- Iterating
nums1and rescanningnums2for each:O(n * m). The hash-map indirection is the optimisation. - Using a stack of indices when values are distinct: works but adds indirection. Since the spec promises distinct values, a stack of values is cleaner.
- Using
<=instead of<on the comparison:<=would pop on equal values, but the spec promises distinct, so it doesn't matter here. In the generalised version (next-greater-element-ii, where duplicates can appear in the circular array), the choice matters; pick<=if you want "strictly greater" and<if you want "greater or equal". - Forgetting the leftover-stack cleanup: values still on the stack at the end have no next greater. Assign them
-1. Many candidates write the loop and then forget this step. - Returning answers in the wrong order: the spec says answers are for
nums1in its order, not innums2's order.
Where this shows up in the enterprise
- Trading platforms (Renaissance, Citadel, Bloomberg): "next higher volume / price tick" lookups across reference universes.
- Search ranking (Google, Bing): "next more-relevant result" lookups across pre-ranked indices.
- Database query optimisers (Snowflake, BigQuery): "next higher-cardinality column" lookups during plan exploration.
- Spreadsheet auditing (Excel, Google Sheets): "next higher value in this column" queries for outlier detection.
- AdTech bid landscapes: "next higher CPM bidder" lookups across auction logs.
- GitHub repo analytics: "next more-starred sibling repo" lookups.
- CDN log analysis: "next higher response-time entry" lookups for tail-latency studies.
- Robotics path planning: "next obstacle of greater height" lookups along a profile.
The pattern is: lookup the closest-rightward element exceeding a value, applied across many queries. Precompute once with a stack, answer each query in O(1).
Variants you'll see elsewhere
next-greater-element-ii:nums2is circular (wrap-around). Same algorithm, walk the array twice.next-greater-element-iii: a misnomer; it is a permutation problem, not a stack problem.daily-temperatures: same pattern, return distances.online-stock-span: same pattern as a streaming online API.largest-rectangle-in-histogram: uses both next-smaller-right and next-smaller-left.132-pattern: monotonic stack on a more complex predicate.
How parikshan turns this into a learning loop
The dynamic private tests on parikshan cover:
nums1 == nums2(full reference universe).nums1is the first element ofnums2.nums1is the last element ofnums2(always -1).- A
nums2that is strictly increasing (every element has a next greater). - A
nums2that is strictly decreasing (every element except the last has no next greater). - Many queries (
nclose tom), forcing the hash-map indirection to be useful.
The integrity-scored AI sparring partner is the place, in practice mode, to verbalise the monotonic-stack invariant ("the stack holds values in strictly decreasing order; any value smaller than the current one is resolved by the current one") before writing the code in exam mode.
In the AI-integrated workspace
When an agent writes "next greater" lookups, your review checks:
- Is there a single linear pass over the reference array, or is the agent repeating the scan per query?
- Is the lookup structure a hash map keyed by value (correct, given distinct values) or by index (over-complicated)?
- Are leftover stack values assigned -1, not silently omitted?
- Does the algorithm handle the case where
nums1is empty? (The map is still built; the answer is just empty.)
The monotonic-stack reflex from daily-temperatures carries over directly. The only new wrinkle here is the subset-of-queries indirection through a hash map. Once you internalise "precompute next-greater for all, look up the subset", the variant becomes a natural composition.
next-greater-element-i is the lightest weight monotonic-stack problem in the cluster. Solve it on parikshan in under three minutes once you have done daily-temperatures, and you have the pattern locked in for the harder variants.