TL;DR
Monotonic decreasing stack of unanswered indices, one pass β O(n) time, O(n) space (an O(1)-extra-space backward-jump variant exists).
Approach 1 β Brute force
For each day, scan forward until you find a strictly warmer day.
class Solution:
def dailyTemperatures(self, temperatures: list[int]) -> list[int]:
n = len(temperatures)
answer = [0] * n
for i in range(n):
for j in range(i + 1, n):
if temperatures[j] > temperatures[i]:
answer[i] = j - i
break
return answer
Complexity: O(n^2) time, O(1) extra space.
Why the constraints kill it: a long non-increasing input (e.g. 10^5 days of slowly falling temperatures) makes every inner scan run to the end β ~5Β·10^9 comparisons, far past any time limit.
Approach 2 β Monotonic decreasing stack
The insight: flip the question β instead of each day searching forward for its answer, let each new day deliver answers backward. Keep a stack of indices still waiting; their temperatures are necessarily strictly decreasing from bottom to top (anything warmer than the day below it would already have been answered). This is a monotonic stack: a stack maintained in sorted order by popping every element the newcomer beats. When day j arrives, it pops (answers) every waiting day colder than it, then joins the wait itself.
class Solution:
def dailyTemperatures(self, temperatures: list[int]) -> list[int]:
answer = [0] * len(temperatures)
stack: list[int] = [] # indices, temps decreasing
for j, temp in enumerate(temperatures):
while stack and temperatures[stack[-1]] < temp:
i = stack.pop()
answer[i] = j - i # day j answers day i
stack.append(j)
return answer # leftovers keep 0
Walkthrough on [73, 74, 75, 71, 69, 72, 76, 73]:
| j | temp | pops (index: answer) | stack after (indices) |
|---|
| 0 | 73 | β | 0 |
| 1 | 74 | 0 β 1 | 1 |
| 2 | 75 | 1 β 1 | 2 |
| 3 | 71 | β | 2 3 |
| 4 | 69 | β | 2 3 4 |
| 5 | 72 | 4 β 1, 3 β 2 | 2 5 |
| 6 | 76 | 5 β 1, 2 β 4 | 6 |
| 7 | 73 | β | 6 7 |
Indices 6 and 7 stay unanswered β 0. Result: [1, 1, 4, 2, 1, 1, 0, 0].
Complexity: O(n) time β every index is pushed once and popped at most once, so the while is amortized O(1). O(n) space for the stack.
Approach 3 β Backward pass with answer-array jumps
The insight: working right-to-left, day iβs warmer day lies at or beyond i + 1; and if day j isnβt warm enough, nothing between j and j + answer[j] can be either (theyβre all <= temperatures[j]) β so hop straight to j + answer[j]. The already-filled answer array doubles as a jump table, eliminating the stack.
class Solution:
def dailyTemperatures(self, temperatures: list[int]) -> list[int]:
n = len(temperatures)
answer = [0] * n
for i in range(n - 2, -1, -1):
j = i + 1
while j < n and temperatures[j] <= temperatures[i]:
if answer[j] == 0:
j = n # nothing warmer ever appears
else:
j += answer[j] # leapfrog day j's whole cold run
if j < n:
answer[i] = j - i
return answer
Walkthrough (same example), filling right to left: day 5 (72) checks day 6 (76 > 72) β 1. Day 3 (71) checks day 4 (69 β€ 71), hops by answer[4] = 1 to day 5 (72 > 71) β 2. Day 2 (75) checks day 3, hops +2 to day 5, hops +1 to day 6 (76 > 75) β 4. Final array matches: [1, 1, 4, 2, 1, 1, 0, 0].
Complexity: O(n) time amortized (each hop skips a run that is never re-examined at that level), O(1) extra space beyond the output.
Common pitfalls
- Storing temperatures on the stack instead of indices β you need
j - i to compute the wait, so the stack must hold indices.
< vs <= in the pop condition: βstrictly warmerβ means pop on temperatures[top] < temp; popping equal temperatures gives wrong answers for repeats like [73, 73, 74].
- Forgetting the leftovers: indices remaining on the stack correctly keep answer 0 only because the array was initialized to 0 β donβt βfinalizeβ them with anything else.
- In the jump variant, failing to treat
answer[j] == 0 as βgive upβ causes an infinite loop on plateaus.
Pattern takeaway
βNext greater elementβ questions are the canonical monotonic-stack pattern: keep a stack of unresolved indices in decreasing value order, and let each new element resolve everything it beats before enlisting. Whenever a problem asks, for each position, about the nearest later (or earlier) element passing a comparison, expect an O(n) monotonic-stack pass instead of the O(n^2) rescan.