<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Sabitha Paulraj's Tech Brainrot]]></title><description><![CDATA[This is Sabitha Paulraj. I document my tech journey, prepping for interviews, learning new skills etc, so that I dont lose track(or my mind)]]></description><link>https://sabithapaulraj.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Thu, 10 Sep 2026 23:59:20 GMT</lastBuildDate><atom:link href="https://sabithapaulraj.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[This One Pattern Can Help You Reduce Time Complexity from O(n²) to O(n) - Learning Monotonic Stacks]]></title><description><![CDATA[Originally published on Substack .
If you’ve been grinding LeetCode, you've probably stumbled upon this problem:
LEETCODE - 739”Given an array of daily temperatures, return an array where each element tells you how many days you have to wait until a ...]]></description><link>https://sabithapaulraj.hashnode.dev/this-one-pattern-can-help-you-reduce-time-complexity-from-on-to-on-learning-monotonic-stacks</link><guid isPermaLink="true">https://sabithapaulraj.hashnode.dev/this-one-pattern-can-help-you-reduce-time-complexity-from-on-to-on-learning-monotonic-stacks</guid><category><![CDATA[leetcode739]]></category><category><![CDATA[leetcode]]></category><category><![CDATA[leetcode-solution]]></category><category><![CDATA[monotonic-stack]]></category><dc:creator><![CDATA[Sabitha Paulraj]]></dc:creator><pubDate>Sun, 22 Jun 2025 08:05:14 GMT</pubDate><content:encoded><![CDATA[<p><em>Originally published on</em> <a target="_blank" href="https://sabithapaulraj.substack.com/p/this-one-pattern-can-help-you-reduce"><em>Substack</em></a> <em>.</em></p>
<p>If you’ve been grinding LeetCode, you've probably stumbled upon this problem:</p>
<p><strong><em>LEETCODE - 739</em></strong><br />”<strong><em>Given an array of daily temperatures, return an array where each element tells you how many days you have to wait until a warmer temperature. If there's no warmer day coming, just put 0.”</em></strong></p>
<p><strong>Example 1:</strong></p>
<pre><code class="lang-plaintext">Input: temperatures = [73,74,75,71,69,72,76,73]
Output: [1,1,4,2,1,1,0,0]
</code></pre>
<p>My brain immediately goes: "Easy! Just check each day against every future day until I find a warmer one."</p>
<p><strong>Spoiler Alert : I failed!!!</strong></p>
<h2 id="heading-the-brute-force-aka-first-attempt"><strong>The Brute Force (aka first attempt)</strong></h2>
<p>Like every confident (read: naive) developer, I dove straight into the nested loop approach:</p>
<pre><code class="lang-plaintext">java
</code></pre>
<pre><code class="lang-plaintext">class Solution {
    public int[] dailyTemperatures(int[] temperatures) {
        int[] answer = new int[temperatures.length];

        // For each day...
        for (int i = 0; i &lt; temperatures.length; i++) {
            // Check every future day until we find a warmer one
            for (int j = i + 1; j &lt; temperatures.length; j++) {
                if (temperatures[j] &gt; temperatures[i]) {
                    answer[i] = j - i;  // Found it! Record the wait time
                    break;              // Stop looking
                }
            }
            // If we never found a warmer day, answer[i] stays 0
        }
        return answer;
    }
}
</code></pre>
<p><strong>My thought process:</strong></p>
<ul>
<li><p>"Okay, for day 0, I'll scan days 1, 2, 3... until I find something warmer"</p>
</li>
<li><p>"Then for day 1, I'll scan days 2, 3, 4... until I find something warmer"</p>
</li>
<li><p>"This is basically asking 'what's the next greater element?' for each position"</p>
</li>
</ul>
<p>Here, we initialize a <code>result</code> array of zeros, then for each index <code>i</code>, we check each future day <code>j</code>. If we find <code>temperatures[j] &gt; temperatures[i]</code>, we record <code>j - i</code> and stop the inner loop. This logic is straightforward and guaranteed to find the answer.</p>
<p>But as we glance at the loop counts, alarm bells ring. In the worst case (e.g., a strictly decreasing sequence of temperatures), the inner loop runs <strong>nearly N times</strong> for each of the N days, leading to <strong>O(N²)</strong> comparisons. In short, brute force <em>works</em>, but it’s painfully slow for larger inputs.</p>
<p>To summarize the brute-force approach step-by-step:</p>
<ul>
<li><p>Initialize <code>result</code> array (all zeros).</p>
</li>
<li><p>For each day <code>i = 0 to n-1</code>:</p>
<ul>
<li><p>Look at each following day <code>j = i+1 ... n-1</code>.</p>
</li>
<li><p>If <code>temperatures[j] &gt; temperatures[i]</code>, set <code>result[i] = j - i</code> and <strong>break</strong> (stop searching further).</p>
</li>
<li><p>If you finish the loop without finding a warmer day, <code>result[i]</code> remains 0</p>
</li>
<li><p>⏱️ <strong>Time Complexity:</strong> O(n²) - In the worst case (like temperatures going [100, 99, 98, 97...]), I'm checking almost every pair of days</p>
</li>
<li><p>💾 <strong>Space Complexity:</strong> O(1) - At least I'm not using extra space... small victory?</p>
</li>
<li><p>💥 <strong>Performance:</strong> Works fine for small inputs, but feed it 10⁵ temperatures and it crumbles.</p>
</li>
</ul>
</li>
</ul>
<hr />
<p>I got slapped by a Time Limit Exceeded Error :(.</p>
<p>After getting a Time Limit Exceeded error, I started thinking differently. The problem wasn't just about finding the next warmer day - it was about finding it <em>efficiently</em>.</p>
<p>That's when I stumbled upon something called a <strong>Monotonic Stack</strong> in the discussions.</p>
<h2 id="heading-what-the-heck-is-a-monotonic-stack"><strong>🎯 What The Heck Is A Monotonic Stack?</strong></h2>
<p>Imagine you're organizing a stack of books by height. A <strong>monotonic stack</strong> is just a stack where we maintain a specific order - either increasing or decreasing.</p>
<p>When the elements in a stack are maintained in a increasing order , it’s called <strong><em>Monotonically Increasing Stack</em></strong>, and if maintained in decreasing order, it’s called <strong><em>Monotonically Decreasing Stack.</em></strong></p>
<p>For our temperature problem, we use a <strong>decreasing monotonic stack</strong> of indices. This means:</p>
<ul>
<li><p>The temperatures at those indices decrease as you go from bottom to top of the stack</p>
</li>
<li><p>We store <strong>indices</strong> (not the actual temperatures) because we need to calculate the distance between days</p>
</li>
</ul>
<h2 id="heading-quick-cheatsheet-when-to-use-what"><code>Quick CheatSheet: (When to use What)</code></h2>
<h4 id="heading-decreasing-stack-find-nextprevious-greater"><code>📉 Decreasing Stack → Find Next/Previous GREATER</code></h4>
<ul>
<li><p><code>Daily Temperatures (next warmer day)</code></p>
</li>
<li><p><code>Next Greater Element (next bigger number)</code></p>
</li>
<li><p><code>Stock Span (previous higher price)</code></p>
</li>
</ul>
<h4 id="heading-increasing-stack-find-nextprevious-smaller"><code>📈 Increasing Stack → Find Next/Previous SMALLER</code></h4>
<ul>
<li><p><code>Largest Rectangle in Histogram (next shorter bar)</code></p>
</li>
<li><p><code>Trapping Rain Water (next lower height)</code></p>
</li>
</ul>
<h2 id="heading-quick-decision"><code>🔍 Quick Decision:</code></h2>
<p><code>Ask: "Am I looking for something bigger or smaller?"</code></p>
<ul>
<li><p><code>Bigger → Use Decreasing Stack</code></p>
</li>
<li><p><code>Smaller → Use Increasing Stack</code></p>
</li>
</ul>
<h2 id="heading-memory-trick"><code>💡 Memory Trick:</code></h2>
<ul>
<li><p><code>Decreasing stack finds Greater elements (opposite directions)</code></p>
</li>
<li><p><code>Increasing stack finds Smaller elements (opposite directions)</code></p>
</li>
</ul>
<p><strong>Why does this work?</strong></p>
<p>Think of it like this: we're keeping a "waiting list" of days that haven't found their warmer day yet. When a really hot day comes along, it can "resolve" multiple waiting days at once!</p>
<p>Here's the key insight that made it click for me:</p>
<ul>
<li><p>If today is warmer than yesterday, then today is the answer for yesterday</p>
</li>
<li><p>If today is warmer than the day before yesterday too, then today is also the answer for that day</p>
</li>
<li><p>We can resolve multiple "waiting" days in one go!</p>
</li>
</ul>
<p>So, how does this help? Instead of scanning ahead for each day, we process each day <strong>once</strong> and use the stack to remember which days are still waiting for a warmer day. Here’s the key idea: <strong>when a new day is warmer than the day at the top of the stack, we have found the “next warmer day” for that top element</strong>. We can then pop it off and record the wait time. Repeat until the stack’s top is warmer than the current day, then push the current day onto the stack.</p>
<p>In more concrete terms:</p>
<ol>
<li><p>Create an empty stack to hold <em>indices</em> of days.</p>
</li>
<li><p>Loop <code>i</code> from 0 to <code>n-1</code> over the temperatures:</p>
<ul>
<li><p>While the stack is not empty <strong>and</strong> <code>temperatures[i] &gt; temperatures[stack.peek()]</code>, pop the top index <code>prev = stack.pop()</code>. That means day <code>i</code> is warmer than day <code>prev</code>, so set <code>result[prev] = i - prev</code>.</p>
</li>
<li><p>After popping, continue the while-loop because the current day might warm up multiple earlier days.</p>
</li>
<li><p>Push the current index <code>i</code> onto the stack. It now <em>waits</em> for a warmer future day.</p>
</li>
</ul>
</li>
<li><p>Any indices left in the stack by the end never found a warmer day, so their <code>result[]</code> stays 0 (we initialized it that way).</p>
</li>
</ol>
<p>This clever trick ensures <strong>each index goes onto the stack exactly once and is popped at most once</strong>. The while-loop doesn’t do quadratic work; it just processes each element a constant number of times, so the overall time becomes <strong>O(N)</strong>. In other words, the monotonic stack approach “operates in linear time” by resolving many comparisons in bulk.</p>
<p>A mental picture: scan each day one by one. For each day, toss it onto a stack of days that haven’t found warmer days yet. If a day comes along that’s warmer than some days in the stack, those earlier days have their answer right now — they get popped and their wait times set. It’s like a time machine that looks <em>forward</em> from each day and immediately goes back to fill in answers for everyone it passed along the way. Each day gets checked only a few times, making the solution hum along efficiently.</p>
<h2 id="heading-the-monotonic-stack-solution"><strong>The Monotonic Stack Solution</strong></h2>
<pre><code class="lang-plaintext">java
</code></pre>
<pre><code class="lang-plaintext">class Solution {
    public int[] dailyTemperatures(int[] temperatures) {
        int[] answer = new int[temperatures.length];
        Stack&lt;Integer&gt; stack = new Stack&lt;&gt;();  // Stack of indices

        for (int i = 0; i &lt; temperatures.length; i++) {
            // While stack isn't empty AND current temp is warmer than 
            // the temperature at the index on top of the stack
            while (!stack.isEmpty() &amp;&amp; 
                   temperatures[i] &gt; temperatures[stack.peek()]) {

                int prevIndex = stack.pop();  // Get the waiting day
                answer[prevIndex] = i - prevIndex;  // Calculate wait time
            }

            // Current day joins the waiting list
            stack.push(i);
        }

        return answer;
    }
}
</code></pre>
<p>Let’s break this down:</p>
<ul>
<li><p>We still have <code>result[]</code> initialized to 0’s.</p>
</li>
<li><p>We use <code>Stack&lt;Integer&gt; stack</code> to hold indices of days waiting for a warmer day.</p>
</li>
<li><p>We iterate <code>i</code> from 0 to <code>n-1</code>. For each day <code>i</code>:</p>
<ul>
<li><p><strong>While the stack isn’t empty and</strong> <code>temperatures[i]</code> <strong>is warmer than</strong> <code>temperatures[stack.peek()]</code>: pop the index <code>prevIndex</code>. Then we know day <code>i</code> is the next warmer day for <code>prevIndex</code>, so set <code>result[prevIndex] = i - prevIndex</code>.</p>
</li>
<li><p>After popping all colder days, we push <code>i</code> onto the stack (day <code>i</code> now waits for a future warmer day).</p>
</li>
</ul>
</li>
<li><p>The core <code>while</code> loop corresponds exactly to our earlier description: “if the current temperature is greater than the temperature at the index on top of the stack, we pop and set the waiting time”. This loop might pop one or many indices if the new day is much warmer.</p>
</li>
<li><p>Once we finish the loop, any indices still on the stack didn’t find a warmer day — but we already initialized those <code>result</code> entries to 0, so we’re done.</p>
</li>
</ul>
<p><strong>⏱️ Time Complexity:</strong> O(n) - Each index gets pushed and popped at most once <strong>💾 Space Complexity:</strong> O(n) - In worst case, all indices could be in the stack</p>
<h2 id="heading-walkthrough"><strong>🎬 Walkthrough!</strong></h2>
<p>Let me walk you through this with <code>temperatures = [73, 74, 75, 71, 69, 72, 76, 73]</code>:</p>
<p><strong>Day 0 (73°F):</strong></p>
<ul>
<li><p>Stack is empty, so just push index 0</p>
</li>
<li><p>Stack: [0] (representing temperatures [73])</p>
</li>
<li><p>Answer: [0,0,0,0,0,0,0,0]</p>
</li>
</ul>
<p><strong>Day 1 (74°F):</strong></p>
<ul>
<li><p>74 &gt; 73 (temp at stack.peek() which is index 0)</p>
</li>
<li><p>Pop index 0, set answer[0] = 1 - 0 = 1</p>
</li>
<li><p>Push index 1 onto stack</p>
</li>
<li><p>Stack: [1] (representing temperatures [74])</p>
</li>
<li><p>Answer: [1,0,0,0,0,0,0,0]</p>
</li>
</ul>
<p><strong>Day 2 (75°F):</strong></p>
<ul>
<li><p>75 &gt; 74 (temp at index 1)</p>
</li>
<li><p>Pop index 1, set answer[1] = 2 - 1 = 1</p>
</li>
<li><p>Push index 2</p>
</li>
<li><p>Stack: [2] (representing temperatures [75])</p>
</li>
<li><p>Answer: [1,1,0,0,0,0,0,0]</p>
</li>
</ul>
<p><strong>Day 3 (71°F):</strong></p>
<ul>
<li><p>71 &lt; 75 (temp at index 2), so no popping needed</p>
</li>
<li><p>Just push index 3</p>
</li>
<li><p>Stack: [2,3] (representing temperatures [75,71])</p>
</li>
<li><p>Answer: [1,1,0,0,0,0,0,0]</p>
</li>
</ul>
<p><strong>Day 4 (69°F):</strong></p>
<ul>
<li><p>69 &lt; 71 (temp at index 3), so no popping</p>
</li>
<li><p>Push index 4</p>
</li>
<li><p>Stack: [2,3,4] (representing temperatures [75,71,69])</p>
</li>
<li><p>Answer: [1,1,0,0,0,0,0,0]</p>
</li>
</ul>
<p><strong>Day 5 (72°F):</strong></p>
<ul>
<li><p>72 &gt; 69 (temp at index 4) → Pop 4, answer[4] = 5 - 4 = 1</p>
</li>
<li><p>72 &gt; 71 (temp at index 3) → Pop 3, answer[3] = 5 - 3 = 2</p>
</li>
<li><p>72 &lt; 75 (temp at index 2) → Stop popping, push 5</p>
</li>
<li><p>Stack: [2,5] (representing temperatures [75,72])</p>
</li>
<li><p>Answer: [1,1,0,2,1,0,0,0]</p>
</li>
</ul>
<p><strong>Day 6 (76°F) - The Big Moment:</strong></p>
<ul>
<li><p>76 &gt; 72 (temp at index 5) → Pop 5, answer[5] = 6 - 5 = 1</p>
</li>
<li><p>76 &gt; 75 (temp at index 2) → Pop 2, answer[2] = 6 - 2 = 4</p>
</li>
<li><p>Stack is empty, push 6</p>
</li>
<li><p>Stack: [6] (representing temperatures [76])</p>
</li>
<li><p>Answer: [1,1,4,2,1,1,0,0]</p>
</li>
</ul>
<p><strong>Day 7 (73°F):</strong></p>
<ul>
<li><p>73 &lt; 76 (temp at index 6), so just push 7</p>
</li>
<li><p>Stack: [6,7] (representing temperatures [76,73])</p>
</li>
<li><p>Final Answer: [1,1,4,2,1,1,0,0]</p>
</li>
</ul>
<p><strong>The Beauty:</strong> Notice how day 6 (76°F) resolved TWO waiting days at once! This is the power of the monotonic stack - it can handle multiple resolutions in a single iteration.</p>
<h2 id="heading-the-bug-that-haunted-me"><strong>The Bug That Haunted Me</strong></h2>
<p>I spent way too long debugging this mistake:</p>
<pre><code class="lang-plaintext">java
</code></pre>
<pre><code class="lang-plaintext">// ❌ WRONG - This will crash!
while (!stack.isEmpty() &amp;&amp; stack.peek() &lt; temperatures[i]) {
    // This compares an INDEX to a TEMPERATURE - makes no sense!
}

// ✅ CORRECT
while (!stack.isEmpty() &amp;&amp; temperatures[stack.peek()] &lt; temperatures[i]) {
    // This compares a TEMPERATURE to a TEMPERATURE - much better!
}
</code></pre>
<p><strong>The mistake:</strong> <code>stack.peek()</code> gives you an INDEX, not the temperature at that index. Always remember to use <code>temperatures[stack.peek()]</code> when you need the actual temperature value.</p>
<p>This bug gave me an <code>ArrayIndexOutOfBoundsException</code> that took me embarrassingly long to figure out. Don't be like past me - the stack stores indices, not values!</p>
<h2 id="heading-performance-comparison"><strong>🚀 Performance Comparison</strong></h2>
<p>Let me put this in perspective with some rough numbers:</p>
<p><strong>For n = 10,000 temperatures:</strong></p>
<ul>
<li><p>Brute Force: ~50,000,000 comparisons (n²/2)</p>
</li>
<li><p>Monotonic Stack: ~10,000 comparisons (each element pushed/popped once)</p>
</li>
</ul>
<p><strong>For n = 100,000 temperatures:</strong></p>
<ul>
<li><p>Brute Force: ~5,000,000,000 comparisons (good luck with that!)</p>
</li>
<li><p>Monotonic Stack: ~100,000 comparisons (still linear!)</p>
</li>
</ul>
<h2 id="heading-key-takeaways"><strong>🎯 Key Takeaways</strong></h2>
<ol>
<li><p><strong>Pattern Recognition is Everything:</strong> Once you see the "next greater element" pattern, monotonic stacks become your go-to tool.</p>
</li>
<li><p><strong>Think About What You're Storing:</strong> We store indices, not values, because we need to calculate distances.</p>
</li>
<li><p><strong>The While Loop is the Magic:</strong> That inner while loop can resolve multiple elements at once - that's where the efficiency comes from.</p>
</li>
<li><p><strong>Each Element Has a Simple Life Cycle:</strong> Push onto stack → Wait for resolution → Get popped when resolved. Each element goes through this exactly once.</p>
</li>
<li><p><strong>Visualization Helps:</strong> Draw out the stack states for small examples. It makes the pattern crystal clear.</p>
</li>
</ol>
<h2 id="heading-final-thoughts"><strong>Final Thoughts</strong></h2>
<p>When I first encountered this problem, I thought it was just about finding the next warmer day.</p>
<p>Instead of asking "For each day, what's the next warmer day?" (which leads to nested loops), we ask "For each day, which previous days is this the answer for?" (which leads to the monotonic stack).</p>
<p>This shift in perspective - from forward-looking to backward-resolving - is what transforms an O(n²) complexity into an O(n) complexity.</p>
]]></content:encoded></item></channel></rss>