DSA sheet · Stack · Monotonic stack pattern

Daily Temperatures

This is the third monotonic stack problem. Under a story about weather, it's the next greater element to the right again. The twist: we must answer "how many days later", not "which temperature". That forces one important change: the stack stores indices, not values. The teacher also shows that the same problem can be solved walking left to right, and explains exactly what changes when you do that.

Every part below follows the same order:
① the question in simple words → ② what the constraints tell us → ③ intuition → ④ building the logic from examples → ⑤ approach steps → ⑥ code → ⑦ code line by line → ⑧ dry run → ⑨ complexity & remember

Part 0 · Before starting

Stack basics

A stack is a pile you can only use from the top: LIFO (Last In, First Out). Python's list works as a stack:

actionPythonnote
push x on topst.append(x)O(1)
pop the topst.pop()O(1), crashes if empty
peek at the topst[-1]O(1), crashes if empty
is it empty?not stcheck this before pop / peek

Drawings on this page: left = bottom, right = top.

Monotonic stack in one paragraph

A monotonic stack keeps its items in sorted order from bottom to top. Before pushing a new item, we pop every item on top that would break the order. For "next greater" questions we pop the items that are not greater than the new one. A popped item is hidden behind a closer item that is at least as big, so it can never be the "first bigger one" for anything that comes later. Every item is pushed once and popped at most once, which is why the whole thing is O(n).

The 4 standard problems (the teacher lists them here)

If you know stacks, you know these four. Almost every monotonic-stack question is one of them in disguise:

namelooking forusual loop directionpop while top is…
next greater to the rightfirst bigger value after iright → left≤ current
next greater to the leftfirst bigger value before ileft → right≤ current
next smaller to the rightfirst smaller value after iright → left≥ current
next smaller to the leftfirst smaller value before ileft → right≥ current

Translating this question: "warmer" means greater. "Days you have to wait" means the future, so to the right. (If the question asked about a warmer day in the past, it would be next greater to the left.) So Daily Temperatures = next greater to the right, but report the distance.


Part A · Brute force: two loops

LeetCode 739

1The question in simple words

You get the temperature for each day. For every day i, return how many days you must wait until a strictly warmer day. If no warmer day ever comes, return 0 for that day.

day01234567
temp7374757169727673
wait11421100

Key observation: the wait is just the difference of indices, j − i, where j is the first warmer day after i.

2What the constraints tell us

3Intuition

Stand on day i. Walk forward day by day until it's warmer. Count the steps. That count is the answer.

4Building the logic

Doubt 1: why fill the answer with 0 at the start?
→ 0 is the answer when no warmer day exists. Pre-filling means we only overwrite when we find one. The last day never gets overwritten, and that's correct.
Doubt 2: j starts at i + 1, right?
→ Yes. A day can't be warmer than itself, and we only care about days after i.
Doubt 3: > or >=?
→ Strictly >. "Warmer" means hotter. The same temperature is not warmer.
Doubt 4: the answer goes into ans[i] or ans[j]?
→ ans[i]. We're searching on behalf of day i. Day j is just the day that ended the search.
Doubt 5: why stop i at the second-last day?
→ For the last day, j = i + 1 is already past the end, so there's nothing to check. Its 0 is already there. (The teacher notes that running i to the very end also works, because the inner loop just doesn't run.)

And once a warmer day is found, break. We want the first one, so going further would only risk overwriting it with a later, wrong day.

5Approach steps

  1. ans = [0] * n.
  2. For i from 0 to n−2, for j from i+1 to n−1:
  3. If temps[j] > temps[i]: ans[i] = j − i, break.
  4. Return ans.

6Code (Python)

Brute force, O(n²)
class Solution:
    def dailyTemperatures(self, temperatures):
        n = len(temperatures)
        ans = [0] * n                                # 0 = no warmer day
        for i in range(n - 1):
            for j in range(i + 1, n):                # only future days
                if temperatures[j] > temperatures[i]: # strictly warmer
                    ans[i] = j - i                   # days waited = index gap
                    break                            # first warmer day only
        return ans

7Code line by line

linewhat it means
ans = [0] * nDefault "never gets warmer".
for i in range(n - 1):The day we're answering for.
for j in range(i + 1, n):Scan the future, nearest day first.
if temperatures[j] > temperatures[i]:Found a strictly warmer day.
ans[i] = j - i breakStore the gap at i, and stop scanning.

8Dry run (the interesting row, i = 2)

jtemp[j]> 75?action
371nokeep going
469nokeep going
572nokeep going
676yesans[2] = 6 − 2 = 4, break

The other rows find their warmer day in one or two steps. Final [1, 1, 4, 2, 1, 1, 0, 0] ✓.

9Complexity & remember

Spot the patternFor every i, j runs forward just to find a greater value. The teacher's rule: whenever you go forward or backward again and again from each index to find a greater or smaller element, you can safely reach for a stack.

Part B · Optimal: stack of indices, walking from the right

1The question again

Same question. Target: O(n), with one loop and a stack.

2What the constraints tell us

n ≤ 10⁵ → O(n) is about 2·10⁵ stack operations, which is instant. O(n) extra space for the stack is allowed.

3Intuition

Since the answer lives in the future (to the right), walk from the last day backwards, exactly like Next Greater Element. When we're at day i, every later day has already been seen and summarised in the stack: the stack holds the days that could still be "the next warmer day" for someone, with the nearest on top.

The one new idea: in Next Greater Element we pushed values. Here we need how far away the warmer day is, so we push the index of the day. From an index we can get both things we need:

4Building the logic from the example (as the teacher walks it)

Why a popped day never comes back as an answerDay k is popped while we stand at day i (i < k) because temp[k] ≤ temp[i]. Any day z we handle later is to the left of i. Walking forward from z, you reach i before k, and i is at least as warm. So whenever k would be warmer than z, so is i, and i comes first. Day k is permanently shadowed.
Doubt 1: why pop when the temperatures are equal?
→ An equal day is not warmer, so it can't answer day i. It's also shadowed for the days on the left: day i is just as warm and closer. So the condition is temperatures[st[-1]] <= t.
Doubt 2: isn't the while inside the for O(n²)? At day 2 we popped twice.
→ No. The pops are paid for once in total, not once per day. Each index is pushed exactly once and popped at most once over the whole run. The teacher's point: once a day is popped, it never comes back into the stack to be popped again. So all the while-loop runs together do at most n pops. See step 9.
Doubt 3: what does the stack look like, in terms of temperatures?
→ Reading the indices' temperatures from bottom to top, they are strictly decreasing, e.g. after day 2: [6, 2] → 76, 75. The top is the nearest future day, and each day lower down is further away and hotter.

5Approach steps

  1. ans = [0] * n, empty stack (of indices).
  2. For i from n−1 down to 0, with t = temperatures[i]:
  3. While the stack is not empty and temperatures[top] ≤ t → pop.
  4. If the stack is not empty → ans[i] = top − i.
  5. Push i.
  6. Return ans.

6Code (Python)

Optimal, from the right (stack of indices)
class Solution:
    def dailyTemperatures(self, temperatures):
        n = len(temperatures)
        ans = [0] * n
        st = []                                          # indices of future days, nearest on top
        for i in range(n - 1, -1, -1):
            t = temperatures[i]
            while st and temperatures[st[-1]] <= t:     # not warmer -> shadowed forever
                st.pop()
            if st:
                ans[i] = st[-1] - i                      # distance to the next warmer day
            st.append(i)                                 # push the INDEX, not the value
        return ans

7Code line by line

linewhat it means
st = []Holds indices. Their temperatures go down from bottom to top.
for i in range(n - 1, -1, -1):Walk from the last day to the first.
while st and temperatures[st[-1]] <= t: st.pop()Look up the top day's temperature through its index. If it's not warmer than today, drop it for good.
if st: ans[i] = st[-1] - iThe top is the first warmer future day. The answer is the index gap. If the stack is empty, keep 0.
st.append(i)Today is now the nearest future day for yesterday.

8Dry run: [73, 74, 75, 71, 69, 72, 76, 73]

Stack entries are written as index(temp) to make reading easy. The real stack holds only the index.

icurrentwhat we pop (and why)pushstack AFTER (bottom → top)answer so far
773nothing (empty) → 07[7(73)][0,0,0,0,0,0,0,0]
676pop 7(73): 73 ≤ 76 · empty → 06[6(76)][0,0,0,0,0,0,0,0]
572nothing: 76 > 72 → 6−5 = 15[6(76), 5(72)][0,0,0,0,0,1,0,0]
469nothing: 72 > 69 → 5−4 = 14[6(76), 5(72), 4(69)][0,0,0,0,1,1,0,0]
371pop 4(69): 69 ≤ 71 · 72 > 71 → 5−3 = 23[6(76), 5(72), 3(71)][0,0,0,2,1,1,0,0]
275pop 3(71), pop 5(72): both ≤ 75 · 76 > 75 → 6−2 = 42[6(76), 2(75)][0,0,4,2,1,1,0,0]
174nothing: 75 > 74 → 2−1 = 11[6(76), 2(75), 1(74)][0,1,4,2,1,1,0,0]
073nothing: 74 > 73 → 1−0 = 10[6(76), 2(75), 1(74), 0(73)][1,1,4,2,1,1,0,0]
i=2, before popping
6 (76)5 (72)3 (71) ≤ 75 → pop
after 2 pops: top answers
6 (76) → 6−2 = 4
end of the walk
6 (76)2 (75)1 (74)0 (73)

9Complexity & remember

RememberNext greater to the right, but push indices. Compare with temperatures[st[-1]], answer with st[-1] - i. Pop on <=.

Part C · The same stack walking from the left

1The question

The teacher answers a natural doubt: "Must we start from the right? Can't we go from the left?" We can. The code is almost the same, but where we write the answer changes.

2What the constraints tell us

Nothing new: still O(n) time and O(n) space, so both directions pass.

3Intuition: the stack becomes a waiting room

Walking from the left, when we stand on day i we don't know the future yet. So we can't answer day i right now. Instead we flip the roles:

from the right (Part B)from the left (Part C)
the stack holdscandidates: future days that could be someone's answerquestions: past days still waiting for an answer
we pop whentop is not warmer than today (<=)today is warmer than the top (>)
a popped day meansshadowed forever, uselessanswered and done
answer written atans[i] = st[-1] - ians[top] = i - top
days left in the stack at the end(don't matter)never got warmer → keep 0

4Building the logic from the example

Doubt: why is it enough to compare today with the top only? Couldn't a day deeper in the stack also be colder than today?
→ The waiting room is ordered: going down from the top, temperatures never get colder. A day only stays below another if the newer day was not warmer than it. So if today isn't warmer than the top, it isn't warmer than anything below either. We can stop at the first failure.
Doubt: equal temperatures here?
→ Equal is not warmer, so we do not pop on equal (>, not >=). Both equal days wait together, and a later warmer day answers both.

5Approach steps

  1. ans = [0] * n, empty stack.
  2. For i from 0 to n−1, with t = temperatures[i]:
  3. While the stack is not empty and t > temperatures[top]: pop j, set ans[j] = i − j.
  4. Push i.
  5. Return ans (whatever is still waiting keeps 0).

6Code (Python)

Optimal, from the left (waiting days)
class Solution:
    def dailyTemperatures(self, temperatures):
        n = len(temperatures)
        ans = [0] * n
        st = []                                          # indices of days still waiting
        for i in range(n):
            t = temperatures[i]
            while st and t > temperatures[st[-1]]:      # today is warmer than the top waiter
                j = st.pop()
                ans[j] = i - j                           # answer goes to the POPPED day
            st.append(i)                                 # today starts waiting
        return ans

7Code line by line

linewhat it means
for i in range(n):Normal left-to-right walk.
while st and t > temperatures[st[-1]]:Does today end the wait of the top day? Strictly warmer only.
j = st.pop() ans[j] = i - jDay j has found its warmer day (today). Store the gap at j, not at i.
st.append(i)Today hasn't found its warmer day yet, so it waits.
return ansDays left in the stack never got an answer, so their 0 stays.

8Dry run

icurrentwhat we pop (and why)pushstack AFTERanswer so far
073nothing (empty)0[0(73)][0,0,0,0,0,0,0,0]
174pop 0: 74 > 73 → ans[0] = 11[1(74)][1,0,0,0,0,0,0,0]
275pop 1: 75 > 74 → ans[1] = 12[2(75)][1,1,0,0,0,0,0,0]
371nothing: 71 < 753[2(75), 3(71)]same
469nothing: 69 < 714[2(75), 3(71), 4(69)]same
572pop 4 → ans[4] = 1 · pop 3 → ans[3] = 2 · stop at 755[2(75), 5(72)][1,1,0,2,1,0,0,0]
676pop 5 → ans[5] = 1 · pop 2 → ans[2] = 46[6(76)][1,1,4,2,1,1,0,0]
773nothing: 73 < 767[6(76), 7(73)][1,1,4,2,1,1,0,0]
waiting room before day 5
2 (75)3 (71)4 (69)
after day 5
2 (75)5 (72)
end: never warmer → 0
6 (76)7 (73)

9Complexity & remember

Remember the differenceFrom the right: answer today from the top (ans[i] = st[-1] - i). From the left: today answers the popped days (ans[j] = i - j). Same stack, same O(n). Only the answer's address changes.

Part D · Revision page

Brute forceStack from rightStack from left
stack holdsno stackfuture days that could still be the answerpast days still waiting
pop when-temp[top] <= tt > temp[top]
writeans[i] = j - ians[i] = st[-1] - ians[j] = i - j for each popped j
time / spaceO(n²) / O(1)O(n) / O(n)O(n) / O(n)
Next Greater ElementDaily Temperatures
answerthe bigger valuethe distance to it
stack storesvaluesindices (value = temperatures[idx])
not found−10
If you remember only 5 lines 1. "Warmer" = greater, "wait" = future = right → next greater to the right.
2. We need distances → push indices.
3. From the right: pop while temp[top] <= t, then ans[i] = top − i, push i.
4. From the left: while today is warmer than the top, pop j and set ans[j] = i − j. Push i.
5. Each index is pushed once and popped once → O(n).
Mistakes to avoid ✗ pushing temperatures instead of indices (you lose the distance)
✗ writing ans[i] in the left-to-right version (it belongs to the popped day)
✗ using >= for "warmer" (equal is not warmer)
✗ comparing st[-1] (an index) directly with a temperature
✗ peeking at an empty stack
test it yourself (paste under any solution above)
s = Solution()
print(s.dailyTemperatures([73, 74, 75, 71, 69, 72, 76, 73]))  # [1, 1, 4, 2, 1, 1, 0, 0]
print(s.dailyTemperatures([30, 40, 50, 60]))                  # [1, 1, 1, 0]
print(s.dailyTemperatures([30, 60, 90]))                      # [1, 1, 0]
print(s.dailyTemperatures([70, 70, 70]))                      # [0, 0, 0]
print(s.dailyTemperatures([50]))                              # [0]

Based on this video: Daily Temperatures | Monotonic Stack