<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://robinali34.github.io/blog_leetcode_java/feed.xml" rel="self" type="application/atom+xml" /><link href="https://robinali34.github.io/blog_leetcode_java/" rel="alternate" type="text/html" /><updated>2026-06-25T04:19:40+00:00</updated><id>https://robinali34.github.io/blog_leetcode_java/feed.xml</id><title type="html">Robina Li</title><subtitle>Technical Blog - Exploring algorithms, data structures, and software engineering insights</subtitle><entry><title type="html">[Medium] 2571. Minimum Operations to Reduce an Integer to 0</title><link href="https://robinali34.github.io/blog_leetcode_java/2026/04/20/medium-2571-minimum-operations-to-reduce-an-integer-to-0/" rel="alternate" type="text/html" title="[Medium] 2571. Minimum Operations to Reduce an Integer to 0" /><published>2026-04-20T00:00:00+00:00</published><updated>2026-04-20T00:00:00+00:00</updated><id>https://robinali34.github.io/blog_leetcode_java/2026/04/20/medium-2571-minimum-operations-to-reduce-an-integer-to-0</id><content type="html" xml:base="https://robinali34.github.io/blog_leetcode_java/2026/04/20/medium-2571-minimum-operations-to-reduce-an-integer-to-0/"><![CDATA[<p>Given a positive integer <code class="language-plaintext highlighter-rouge">n</code>, you can add or subtract any power of 2 in one operation. Return the <strong>minimum number of operations</strong> to reduce <code class="language-plaintext highlighter-rouge">n</code> to <code class="language-plaintext highlighter-rouge">0</code>.</p>

<h2 id="examples">Examples</h2>

<p><strong>Example 1:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Input: n = 39
Output: 3

39 = 100111₂
  39 + 1 = 40 (101000₂)     op 1: +2⁰
  40 - 8 = 32 (100000₂)     op 2: -2³
  32 - 32 = 0               op 3: -2⁵
</code></pre></div></div>

<p><strong>Example 2:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Input: n = 54
Output: 3

54 = 110110₂
  54 + 2 = 56 (111000₂)     op 1: +2¹
  56 + 8 = 64 (1000000₂)    op 2: +2³
  64 - 64 = 0               op 3: -2⁶
</code></pre></div></div>

<h2 id="constraints">Constraints</h2>

<ul>
  <li><code class="language-plaintext highlighter-rouge">1 &lt;= n &lt;= 10^5</code></li>
</ul>

<h2 id="thinking-process">Thinking Process</h2>

<h3 id="binary-perspective">Binary Perspective</h3>

<p>Every number is already a sum of powers of 2 (its binary representation). Each <code class="language-plaintext highlighter-rouge">1</code> bit could be removed by subtracting that power – that’s the naive approach, costing <code class="language-plaintext highlighter-rouge">popcount(n)</code> operations.</p>

<p>But we can do <strong>better</strong> by adding a power of 2 to create carries that collapse consecutive <code class="language-plaintext highlighter-rouge">1</code>s.</p>

<h3 id="when-to-add-vs-subtract">When to Add vs Subtract</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>n = 7 = 111₂

Naive (subtract each bit): 4 + 2 + 1 → 3 ops
Smart: 7 + 1 = 8 (1000₂), then 8 - 8 = 0 → 2 ops
</code></pre></div></div>

<p>Adding <code class="language-plaintext highlighter-rouge">1</code> to a block of consecutive <code class="language-plaintext highlighter-rouge">1</code>s collapses them all into a single <code class="language-plaintext highlighter-rouge">1</code> at a higher position.</p>

<h3 id="the-greedy-rule">The Greedy Rule</h3>

<p>Scan from LSB to MSB:</p>
<ul>
  <li><strong>Bit is 0</strong> – shift right, nothing to do</li>
  <li><strong>Bit is 1:</strong>
    <ul>
      <li>If the next bit is also <code class="language-plaintext highlighter-rouge">1</code> (i.e., <code class="language-plaintext highlighter-rouge">n &amp; 3 == 3</code>) – <strong>add 1</strong> (carry forward to collapse the block)</li>
      <li>Otherwise (isolated <code class="language-plaintext highlighter-rouge">1</code>) – <strong>subtract 1</strong> (cheaper to just remove it)</li>
    </ul>
  </li>
</ul>

<p>Each add/subtract counts as one operation. Shifting doesn’t count (we’re just moving to the next bit position).</p>

<h2 id="solution-1-greedy-bit-manipulation--olog-n-time-o1-space">Solution 1: Greedy Bit Manipulation – $O(\log n)$ time, $O(1)$ space</h2>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">Solution</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kt">int</span> <span class="nf">minOperations</span><span class="o">(</span><span class="kt">int</span> <span class="n">n</span><span class="o">)</span> <span class="o">{</span>
        <span class="kt">int</span> <span class="n">ops</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
        <span class="k">while</span> <span class="o">(</span><span class="n">n</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
            <span class="k">if</span> <span class="o">((</span><span class="n">n</span> <span class="mi">1</span><span class="o">)</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
                <span class="n">n</span> <span class="o">&gt;&gt;=</span> <span class="mi">1</span><span class="o">;</span>
            <span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(</span><span class="n">n</span> <span class="o">==</span> <span class="mi">1</span><span class="o">)</span> <span class="o">{</span>
                <span class="k">return</span> <span class="n">ops</span> <span class="o">+</span> <span class="mi">1</span><span class="o">;</span>
            <span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">((</span><span class="n">n</span> <span class="mi">3</span><span class="o">)</span> <span class="o">==</span> <span class="mi">3</span><span class="o">)</span> <span class="o">{</span>
                <span class="n">n</span> <span class="o">+=</span> <span class="mi">1</span><span class="o">;</span>
                <span class="n">ops</span><span class="o">++;</span>
            <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
                <span class="n">n</span> <span class="o">-=</span> <span class="mi">1</span><span class="o">;</span>
                <span class="n">ops</span><span class="o">++;</span>
            <span class="o">}</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="n">ops</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<h3 id="walk-through-n--23-10111">Walk-through: <code class="language-plaintext highlighter-rouge">n = 23 (10111₂)</code></h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Step   n (binary)   Action     ops
─────  ───────────  ─────────  ───
  1    10111        n&amp;3=11 → +1   1
  2    11000        shift &gt;&gt;
  3    1100         shift &gt;&gt;
  4    110          shift &gt;&gt;
  5    11           n&amp;3=11 → +1   2
  6    100          shift &gt;&gt;
  7    10           shift &gt;&gt;
  8    1            n==1 → +1     3
</code></pre></div></div>

<p>Result: <strong>3 operations</strong> (not 6 – the earlier walkthrough in the problem had a bug; let’s verify: 23 + 1 = 24 = 11000₂, then 24 + 8 = 32 = 100000₂, then 32 - 32 = 0. That’s 3 ops.)</p>

<h3 id="walk-through-n--7-111">Walk-through: <code class="language-plaintext highlighter-rouge">n = 7 (111₂)</code></h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Step   n (binary)   Action     ops
─────  ───────────  ─────────  ───
  1    111          n&amp;3=11 → +1   1
  2    1000         shift &gt;&gt;
  3    100          shift &gt;&gt;
  4    10           shift &gt;&gt;
  5    1            n==1 → +1     2
</code></pre></div></div>

<p>Result: <strong>2 operations</strong> (7 + 1 = 8, 8 - 8 = 0)</p>

<h2 id="solution-2-bfs--on-log-n-time-on-space">Solution 2: BFS – $O(n \log n)$ time, $O(n)$ space</h2>

<p>BFS explores all reachable states layer by layer, guaranteeing the shortest path. From any value, try adding or subtracting every power of 2.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// import java.util.*;</span>
<span class="kd">class</span> <span class="nc">Solution</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kt">int</span> <span class="nf">minOperations</span><span class="o">(</span><span class="kt">int</span> <span class="n">n</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">n</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="k">return</span> <span class="mi">0</span><span class="o">;</span>

        <span class="nc">HashSet</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">&gt;</span> <span class="n">visited</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">HashSet</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">&gt;();</span>
        <span class="nc">Queue</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">&gt;</span> <span class="n">q</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">LinkedList</span><span class="o">&lt;&gt;();</span>
        <span class="n">q</span><span class="o">.</span><span class="na">push</span><span class="o">(</span><span class="n">n</span><span class="o">);</span>
        <span class="n">visited</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">n</span><span class="o">);</span>
        <span class="kt">int</span> <span class="n">ops</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>

        <span class="k">while</span> <span class="o">(!</span><span class="n">q</span><span class="o">.</span><span class="na">length</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
            <span class="kt">int</span> <span class="n">size</span> <span class="o">=</span> <span class="n">q</span><span class="o">.</span><span class="na">size</span><span class="o">();</span>
            <span class="n">ops</span><span class="o">++;</span>
            <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">size</span><span class="o">;</span> <span class="o">++</span><span class="n">i</span><span class="o">)</span> <span class="o">{</span>
                <span class="kt">int</span> <span class="n">cur</span> <span class="o">=</span> <span class="n">q</span><span class="o">.</span><span class="na">getFirst</span><span class="o">();</span>
                <span class="n">q</span><span class="o">.</span><span class="na">pop</span><span class="o">();</span>

                <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">p</span> <span class="o">=</span> <span class="mi">1</span><span class="o">;</span> <span class="n">p</span> <span class="o">&lt;=</span> <span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="mi">17</span><span class="o">;</span> <span class="n">p</span> <span class="o">&lt;&lt;=</span> <span class="mi">1</span><span class="o">)</span> <span class="o">{</span>
                    <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">next</span> <span class="o">:</span> <span class="o">{</span><span class="n">cur</span> <span class="o">+</span> <span class="n">p</span><span class="o">,</span> <span class="n">cur</span> <span class="o">-</span> <span class="n">p</span><span class="o">})</span> <span class="o">{</span>
                        <span class="k">if</span> <span class="o">(</span><span class="n">next</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="k">return</span> <span class="n">ops</span><span class="o">;</span>
                        <span class="k">if</span> <span class="o">(</span><span class="n">next</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">next</span> <span class="o">&lt;</span> <span class="o">(</span><span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="mi">18</span><span class="o">)</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">visited</span><span class="o">.</span><span class="na">count</span><span class="o">(</span><span class="n">next</span><span class="o">))</span> <span class="o">{</span>
                            <span class="n">visited</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">next</span><span class="o">);</span>
                            <span class="n">q</span><span class="o">.</span><span class="na">push</span><span class="o">(</span><span class="n">next</span><span class="o">);</span>
                        <span class="o">}</span>
                    <span class="o">}</span>
                <span class="o">}</span>
            <span class="o">}</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<h3 id="why-the-bound-1--18">Why the Bound <code class="language-plaintext highlighter-rouge">1 &lt;&lt; 18</code>?</h3>

<p>Since <code class="language-plaintext highlighter-rouge">n &lt;= 10^5 &lt; 2^17</code>, adding a power of 2 can at most double the value. We cap the search space at <code class="language-plaintext highlighter-rouge">2^18</code> to prevent exploring irrelevant large numbers. In practice BFS terminates very quickly since the greedy answer is at most $O(\log n)$ operations.</p>

<h2 id="comparison">Comparison</h2>

<table>
  <thead>
    <tr>
      <th>Aspect</th>
      <th>Greedy (Bit Manipulation)</th>
      <th>BFS</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Time</td>
      <td>$O(\log n)$</td>
      <td>$O(n \log n)$</td>
    </tr>
    <tr>
      <td>Space</td>
      <td>$O(1)$</td>
      <td>$O(n)$</td>
    </tr>
    <tr>
      <td>Correctness proof</td>
      <td>Requires greedy argument</td>
      <td>Guaranteed (shortest path)</td>
    </tr>
    <tr>
      <td>Interview value</td>
      <td>Shows deep bit intuition</td>
      <td>Shows BFS modeling skill</td>
    </tr>
    <tr>
      <td>Best for</td>
      <td>Production / follow-up optimization</td>
      <td>Proving correctness / verification</td>
    </tr>
  </tbody>
</table>

<p>BFS is useful as a <strong>verification tool</strong>: run it on small inputs to confirm the greedy produces optimal results. In interviews, mentioning BFS as a brute-force baseline before presenting the greedy shows strong problem-solving structure.</p>

<h2 id="why-the-greedy-is-optimal">Why the Greedy is Optimal</h2>

<p>Consider a block of $k$ consecutive <code class="language-plaintext highlighter-rouge">1</code>s:</p>

<table>
  <thead>
    <tr>
      <th>Strategy</th>
      <th>Operations</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Subtract each bit individually</td>
      <td>$k$</td>
    </tr>
    <tr>
      <td>Add 1 to collapse, then subtract the resulting bit</td>
      <td>$2$</td>
    </tr>
  </tbody>
</table>

<p>For $k \ge 3$, adding is strictly better. For $k = 2$ (like <code class="language-plaintext highlighter-rouge">11₂ = 3</code>), both cost 2 operations:</p>
<ul>
  <li>Add: $3 + 1 = 4$, $4 - 4 = 0$ (2 ops)</li>
  <li>Subtract: $3 - 1 = 2$, $2 - 2 = 0$ (2 ops)</li>
</ul>

<p>The greedy chooses to add for <code class="language-plaintext highlighter-rouge">k &gt;= 2</code>, which is safe since it never costs more.</p>

<h2 id="common-mistakes">Common Mistakes</h2>

<ul>
  <li><strong>Treating <code class="language-plaintext highlighter-rouge">n = 1</code> separately:</strong> After all shifts, <code class="language-plaintext highlighter-rouge">n == 1</code> is the base case (isolated single bit). Forgetting this causes infinite loops.</li>
  <li><strong>Using <code class="language-plaintext highlighter-rouge">n &amp; 1 == 1</code> instead of <code class="language-plaintext highlighter-rouge">n &amp; 3 == 3</code>:</strong> The decision depends on whether the <strong>next</strong> bit is also set, not just the current bit</li>
  <li><strong>Counting shifts as operations:</strong> Shifting is just moving to the next bit position, not an actual add/subtract operation</li>
  <li><strong>BFS without bounds:</strong> Without capping the search space, BFS explodes in memory</li>
</ul>

<h2 id="key-takeaways">Key Takeaways</h2>

<ul>
  <li><strong>Think in binary</strong> when the problem involves powers of 2</li>
  <li><strong>Consecutive <code class="language-plaintext highlighter-rouge">1</code>s can be collapsed</strong> by adding 1 – this is the core greedy insight</li>
  <li>Check <code class="language-plaintext highlighter-rouge">n &amp; 3 == 3</code> (two lowest bits both set) to decide add vs subtract</li>
  <li>BFS gives a provably optimal baseline; greedy gives $O(\log n)$ performance</li>
  <li>The pattern “add to create carry, then subtract” appears in many bit manipulation problems</li>
</ul>

<h2 id="related-problems">Related Problems</h2>

<ul>
  <li><a href="https://leetcode.com/problems/integer-replacement/">397. Integer Replacement</a> – similar greedy on even/odd with bit analysis</li>
  <li><a href="https://leetcode.com/problems/number-of-1-bits/">191. Number of 1 Bits</a> – popcount baseline</li>
  <li><a href="https://leetcode.com/problems/number-of-steps-to-reduce-a-number-to-zero/">1342. Number of Steps to Reduce a Number to Zero</a> – simpler version with only divide/subtract</li>
  <li><a href="https://leetcode.com/problems/single-number-iii/">260. Single Number III</a> – bit manipulation with XOR</li>
</ul>

<h2 id="template-reference">Template Reference</h2>

<ul>
  <li><a href="/blog_leetcode_java/posts/2025-11-24-leetcode-templates-math-bit-manipulation/">Math &amp; Bit Manipulation</a></li>
</ul>]]></content><author><name></name></author><category term="leetcode" /><category term="medium" /><category term="bit-manipulation" /><category term="leetcode" /><category term="medium" /><category term="bit-manipulation" /><category term="greedy" /><category term="bfs" /><category term="math" /><summary type="html"><![CDATA[Given a positive integer n, you can add or subtract any power of 2 in one operation. Return the minimum number of operations to reduce n to 0.]]></summary></entry><entry><title type="html">[Hard] 2539. Count the Number of Good Subsequences</title><link href="https://robinali34.github.io/blog_leetcode_java/2026/04/19/hard-2539-count-the-number-of-good-subsequences/" rel="alternate" type="text/html" title="[Hard] 2539. Count the Number of Good Subsequences" /><published>2026-04-19T00:00:00+00:00</published><updated>2026-04-19T00:00:00+00:00</updated><id>https://robinali34.github.io/blog_leetcode_java/2026/04/19/hard-2539-count-the-number-of-good-subsequences</id><content type="html" xml:base="https://robinali34.github.io/blog_leetcode_java/2026/04/19/hard-2539-count-the-number-of-good-subsequences/"><![CDATA[<p>Given a string <code class="language-plaintext highlighter-rouge">s</code>, return the number of <strong>non-empty good subsequences</strong> of <code class="language-plaintext highlighter-rouge">s</code>. A subsequence is <strong>good</strong> if every character in it appears the <strong>same number of times</strong>. Answer modulo $10^9 + 7$.</p>

<h2 id="examples">Examples</h2>

<p><strong>Example 1:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Input: s = "aabb"
Output: 11

Good subsequences:
  k=1: "a","a","b","b","ab","ab","ab","ab" → 8
  k=2: "aa","bb","aabb" → 3
  Total = 11
</code></pre></div></div>

<p><strong>Example 2:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Input: s = "leet"
Output: 7

freq: l=1, e=2, t=1
  k=1: "l","e","e","t","le","lt","et","le","lt","et" ...
  (counted via formula below)
</code></pre></div></div>

<h2 id="constraints">Constraints</h2>

<ul>
  <li><code class="language-plaintext highlighter-rouge">1 &lt;= s.length &lt;= 10^4</code></li>
  <li><code class="language-plaintext highlighter-rouge">s</code> consists of lowercase English letters only</li>
</ul>

<h2 id="thinking-process">Thinking Process</h2>

<h3 id="why-brute-force-fails">Why Brute Force Fails</h3>

<p>Enumerating all $2^n - 1$ non-empty subsequences and checking each one is exponential. We need a combinatorial approach.</p>

<h3 id="the-key-insight">The Key Insight</h3>

<p>Instead of generating subsequences, <strong>fix a target frequency <code class="language-plaintext highlighter-rouge">k</code></strong> and count how many subsequences have every chosen character appearing exactly <code class="language-plaintext highlighter-rouge">k</code> times.</p>

<p>For a fixed <code class="language-plaintext highlighter-rouge">k</code>:</p>
<ul>
  <li>For each character <code class="language-plaintext highlighter-rouge">c</code> with <code class="language-plaintext highlighter-rouge">freq[c] &gt;= k</code>, we can either <strong>include</strong> it (choose exactly <code class="language-plaintext highlighter-rouge">k</code> of its <code class="language-plaintext highlighter-rouge">freq[c]</code> occurrences: $\binom{freq[c]}{k}$ ways) or <strong>exclude</strong> it entirely (1 way)</li>
  <li>Characters with <code class="language-plaintext highlighter-rouge">freq[c] &lt; k</code> must be excluded</li>
</ul>

<p>So the total for a given <code class="language-plaintext highlighter-rouge">k</code>:</p>

\[\text{ways}(k) = \prod_{\text{all chars } c} \left(1 + \binom{freq[c]}{k} \cdot [freq[c] \ge k]\right) - 1\]

<p>The $-1$ removes the empty subsequence (where every character is excluded).</p>

<h3 id="final-answer">Final Answer</h3>

\[\text{answer} = \sum_{k=1}^{\max\_freq} \text{ways}(k)\]

<h3 id="efficient-combinations">Efficient Combinations</h3>

<p>We need $\binom{n}{k}$ for various $n, k$ up to $\max_freq$. Using a Pascal table would be $O(n^2)$ memory, which can blow up for large frequencies.</p>

<p>Instead, precompute factorials and use <strong>Fermat’s little theorem</strong> for modular inverse:</p>

\[\binom{n}{k} = \frac{n!}{k! \cdot (n-k)!} = n! \cdot (k!)^{-1} \cdot ((n-k)!)^{-1} \pmod{10^9+7}\]

<h2 id="solution-1-per-character-loop--otextmaxfreq-times-26-time">Solution 1: Per-Character Loop – $O(\text{maxFreq} \times 26)$ time</h2>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// import java.util.*;</span>
<span class="kd">class</span> <span class="nc">Solution</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">int</span> <span class="no">MOD</span> <span class="o">=</span> <span class="mi">1</span><span class="n">e9</span> <span class="o">+</span> <span class="mi">7</span><span class="o">;</span>

    <span class="kd">public</span> <span class="kt">long</span> <span class="nf">modPow</span><span class="o">(</span><span class="kt">long</span> <span class="n">a</span><span class="o">,</span> <span class="kt">long</span> <span class="n">b</span><span class="o">)</span> <span class="o">{</span>
        <span class="kt">long</span> <span class="n">res</span> <span class="o">=</span> <span class="mi">1</span><span class="o">;</span>
        <span class="k">while</span> <span class="o">(</span><span class="n">b</span><span class="o">)</span> <span class="o">{</span>
            <span class="k">if</span> <span class="o">(</span><span class="n">b</span> <span class="mi">1</span><span class="o">)</span> <span class="n">res</span> <span class="o">=</span> <span class="n">res</span> <span class="n">a</span> <span class="o">%</span> <span class="no">MOD</span><span class="o">;</span>
            <span class="n">a</span> <span class="o">=</span> <span class="n">a</span> <span class="n">a</span> <span class="o">%</span> <span class="no">MOD</span><span class="o">;</span>
            <span class="n">b</span> <span class="o">&gt;&gt;=</span> <span class="mi">1</span><span class="o">;</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="n">res</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="kt">int</span> <span class="nf">countGoodSubsequences</span><span class="o">(</span><span class="nc">String</span> <span class="n">s</span><span class="o">)</span> <span class="o">{</span>
        <span class="nc">HashMap</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">,</span> <span class="kt">int</span><span class="o">&gt;</span> <span class="n">freq</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">HashMap</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">,</span> <span class="kt">int</span><span class="o">&gt;();</span>
        <span class="k">for</span> <span class="o">(</span><span class="kt">char</span> <span class="n">c</span> <span class="o">:</span> <span class="n">s</span><span class="o">)</span> <span class="n">freq</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">c</span><span class="o">,</span> <span class="n">freq</span><span class="o">.</span><span class="na">getOrDefault</span><span class="o">(</span><span class="n">c</span><span class="o">,</span> <span class="mi">0</span><span class="o">)</span> <span class="o">+</span> <span class="mi">1</span><span class="o">);</span>

        <span class="kt">int</span> <span class="n">max_f</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
        <span class="k">for</span> <span class="o">(</span><span class="n">auto</span><span class="o">&amp;</span> <span class="o">[</span><span class="n">c</span><span class="o">,</span> <span class="n">f</span><span class="o">]</span> <span class="o">:</span> <span class="n">freq</span><span class="o">)</span> <span class="n">max_f</span> <span class="o">=</span> <span class="nc">Math</span><span class="o">.</span><span class="na">max</span><span class="o">(</span><span class="n">max_f</span><span class="o">,</span> <span class="n">f</span><span class="o">);</span>

        <span class="kt">long</span><span class="o">[]</span><span class="n">fact</span><span class="o">(</span><span class="n">max_f</span> <span class="o">+</span> <span class="mi">1</span><span class="o">,</span> <span class="mi">1</span><span class="o">),</span> <span class="n">invfact</span><span class="o">(</span><span class="n">max_f</span> <span class="o">+</span> <span class="mi">1</span><span class="o">,</span> <span class="mi">1</span><span class="o">);</span>
        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">max_f</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
            <span class="n">fact</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">i</span><span class="o">,</span> <span class="n">fact</span><span class="o">[</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="o">]</span> <span class="o">*</span> <span class="n">i</span> <span class="o">%</span> <span class="no">MOD</span><span class="o">);</span>
        <span class="o">}</span>
        <span class="n">invfact</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">max_f</span><span class="o">,</span> <span class="n">modPow</span><span class="o">(</span><span class="n">fact</span><span class="o">[</span><span class="n">max_f</span><span class="o">],</span> <span class="no">MOD</span> <span class="o">-</span> <span class="mi">2</span><span class="o">));</span>
        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">max_f</span> <span class="o">-</span> <span class="mi">1</span><span class="o">;</span> <span class="n">i</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span><span class="o">--)</span> <span class="o">{</span>
            <span class="n">invfact</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">i</span><span class="o">,</span> <span class="n">invfact</span><span class="o">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="o">]</span> <span class="o">*</span> <span class="o">(</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="o">)</span> <span class="o">%</span> <span class="no">MOD</span><span class="o">);</span>
        <span class="o">}</span>

        <span class="kt">var</span> <span class="n">comb</span> <span class="o">=</span> <span class="o">[&amp;](</span><span class="kt">int</span> <span class="n">n</span><span class="o">,</span> <span class="kt">int</span> <span class="n">k</span><span class="o">)</span> <span class="o">{</span>
            <span class="k">return</span> <span class="n">fact</span><span class="o">[</span><span class="n">n</span><span class="o">]</span> <span class="o">%</span> <span class="no">MOD</span> <span class="n">invfact</span><span class="o">[</span><span class="n">k</span><span class="o">]</span> <span class="o">%</span> <span class="no">MOD</span> <span class="n">invfact</span><span class="o">[</span><span class="n">n</span> <span class="o">-</span> <span class="n">k</span><span class="o">]</span> <span class="o">%</span> <span class="no">MOD</span><span class="o">;</span>
        <span class="o">}</span>
        <span class="kt">long</span> <span class="n">result</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">k</span> <span class="o">=</span> <span class="mi">1</span><span class="o">;</span> <span class="n">k</span> <span class="o">&lt;=</span> <span class="n">max_f</span><span class="o">;</span> <span class="n">k</span><span class="o">++)</span> <span class="o">{</span>
            <span class="kt">long</span> <span class="n">ways</span> <span class="o">=</span> <span class="mi">1</span><span class="o">;</span>
            <span class="k">for</span> <span class="o">(</span><span class="n">auto</span><span class="o">&amp;</span> <span class="o">[</span><span class="n">c</span><span class="o">,</span> <span class="n">f</span><span class="o">]</span> <span class="o">:</span> <span class="n">freq</span><span class="o">)</span> <span class="o">{</span>
                <span class="k">if</span> <span class="o">(</span><span class="n">f</span> <span class="o">&gt;=</span> <span class="n">k</span><span class="o">)</span> <span class="o">{</span>
                    <span class="n">ways</span> <span class="o">=</span> <span class="n">ways</span> <span class="o">*</span> <span class="o">(</span><span class="mi">1</span> <span class="o">+</span> <span class="n">comb</span><span class="o">(</span><span class="n">f</span><span class="o">,</span> <span class="n">k</span><span class="o">))</span> <span class="o">%</span> <span class="no">MOD</span><span class="o">;</span>
                <span class="o">}</span>
            <span class="o">}</span>
            <span class="n">ways</span> <span class="o">=</span> <span class="o">(</span><span class="n">ways</span> <span class="o">-</span> <span class="mi">1</span> <span class="o">+</span> <span class="no">MOD</span><span class="o">)</span> <span class="o">%</span> <span class="no">MOD</span><span class="o">;</span>
            <span class="n">result</span> <span class="o">=</span> <span class="o">(</span><span class="n">result</span> <span class="o">+</span> <span class="n">ways</span><span class="o">)</span> <span class="o">%</span> <span class="no">MOD</span><span class="o">;</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="n">result</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p><strong>Time:</strong> $O(\text{maxFreq} \times |\Sigma|)$ where $|\Sigma| \le 26$
<strong>Space:</strong> $O(\text{maxFreq})$ for factorial arrays</p>

<h2 id="solution-2-frequency-grouping--otextmaxfreq-times-d-time">Solution 2: Frequency Grouping – $O(\text{maxFreq} \times d)$ time</h2>

<p>When multiple characters share the same frequency, we can group them and use exponentiation instead of iterating each one individually.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// import java.util.*;</span>
<span class="kd">class</span> <span class="nc">Solution</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">int</span> <span class="no">MOD</span> <span class="o">=</span> <span class="mi">1</span><span class="n">e9</span> <span class="o">+</span> <span class="mi">7</span><span class="o">;</span>

    <span class="kd">public</span> <span class="kt">long</span> <span class="nf">modPow</span><span class="o">(</span><span class="kt">long</span> <span class="n">a</span><span class="o">,</span> <span class="kt">long</span> <span class="n">b</span><span class="o">)</span> <span class="o">{</span>
        <span class="kt">long</span> <span class="n">res</span> <span class="o">=</span> <span class="mi">1</span><span class="o">;</span>
        <span class="k">while</span> <span class="o">(</span><span class="n">b</span><span class="o">)</span> <span class="o">{</span>
            <span class="k">if</span> <span class="o">(</span><span class="n">b</span> <span class="mi">1</span><span class="o">)</span> <span class="n">res</span> <span class="o">=</span> <span class="n">res</span> <span class="n">a</span> <span class="o">%</span> <span class="no">MOD</span><span class="o">;</span>
            <span class="n">a</span> <span class="o">=</span> <span class="n">a</span> <span class="n">a</span> <span class="o">%</span> <span class="no">MOD</span><span class="o">;</span>
            <span class="n">b</span> <span class="o">&gt;&gt;=</span> <span class="mi">1</span><span class="o">;</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="n">res</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="kt">int</span> <span class="nf">countGoodSubsequences</span><span class="o">(</span><span class="nc">String</span> <span class="n">s</span><span class="o">)</span> <span class="o">{</span>
        <span class="nc">HashMap</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">,</span> <span class="kt">int</span><span class="o">&gt;</span> <span class="n">freq</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">HashMap</span><span class="o">&lt;</span><span class="kt">char</span><span class="o">,</span> <span class="kt">int</span><span class="o">&gt;();</span>
        <span class="k">for</span> <span class="o">(</span><span class="kt">char</span> <span class="n">c</span> <span class="o">:</span> <span class="n">s</span><span class="o">)</span> <span class="n">freq</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">c</span><span class="o">,</span> <span class="n">freq</span><span class="o">.</span><span class="na">getOrDefault</span><span class="o">(</span><span class="n">c</span><span class="o">,</span> <span class="mi">0</span><span class="o">)</span> <span class="o">+</span> <span class="mi">1</span><span class="o">);</span>

        <span class="nc">HashMap</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">,</span> <span class="nc">Integer</span><span class="o">&gt;</span> <span class="n">freqCount</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">HashMap</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">,</span> <span class="nc">Integer</span><span class="o">&gt;();</span>
        <span class="k">for</span> <span class="o">(</span><span class="n">auto</span><span class="o">&amp;</span> <span class="o">[</span><span class="n">c</span><span class="o">,</span> <span class="n">f</span><span class="o">]</span> <span class="o">:</span> <span class="n">freq</span><span class="o">)</span> <span class="n">freqCount</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">f</span><span class="o">,</span> <span class="n">freqCount</span><span class="o">.</span><span class="na">getOrDefault</span><span class="o">(</span><span class="n">f</span><span class="o">,</span> <span class="mi">0</span><span class="o">)</span> <span class="o">+</span> <span class="mi">1</span><span class="o">);</span>

        <span class="kt">int</span> <span class="n">max_f</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
        <span class="k">for</span> <span class="o">(</span><span class="n">auto</span><span class="o">&amp;</span> <span class="o">[</span><span class="n">f</span><span class="o">,</span> <span class="n">cnt</span><span class="o">]</span> <span class="o">:</span> <span class="n">freqCount</span><span class="o">)</span> <span class="n">max_f</span> <span class="o">=</span> <span class="nc">Math</span><span class="o">.</span><span class="na">max</span><span class="o">(</span><span class="n">max_f</span><span class="o">,</span> <span class="n">f</span><span class="o">);</span>

        <span class="kt">long</span><span class="o">[]</span><span class="n">fact</span><span class="o">(</span><span class="n">max_f</span> <span class="o">+</span> <span class="mi">1</span><span class="o">,</span> <span class="mi">1</span><span class="o">),</span> <span class="n">invfact</span><span class="o">(</span><span class="n">max_f</span> <span class="o">+</span> <span class="mi">1</span><span class="o">,</span> <span class="mi">1</span><span class="o">);</span>
        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">max_f</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
            <span class="n">fact</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">i</span><span class="o">,</span> <span class="n">fact</span><span class="o">[</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="o">]</span> <span class="o">*</span> <span class="n">i</span> <span class="o">%</span> <span class="no">MOD</span><span class="o">);</span>
        <span class="o">}</span>
        <span class="n">invfact</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">max_f</span><span class="o">,</span> <span class="n">modPow</span><span class="o">(</span><span class="n">fact</span><span class="o">[</span><span class="n">max_f</span><span class="o">],</span> <span class="no">MOD</span> <span class="o">-</span> <span class="mi">2</span><span class="o">));</span>
        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">max_f</span> <span class="o">-</span> <span class="mi">1</span><span class="o">;</span> <span class="n">i</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span><span class="o">--)</span> <span class="o">{</span>
            <span class="n">invfact</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">i</span><span class="o">,</span> <span class="n">invfact</span><span class="o">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="o">]</span> <span class="o">*</span> <span class="o">(</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="o">)</span> <span class="o">%</span> <span class="no">MOD</span><span class="o">);</span>
        <span class="o">}</span>

        <span class="kt">var</span> <span class="n">comb</span> <span class="o">=</span> <span class="o">[&amp;](</span><span class="kt">int</span> <span class="n">n</span><span class="o">,</span> <span class="kt">int</span> <span class="n">k</span><span class="o">)</span> <span class="o">{</span>
            <span class="k">return</span> <span class="n">fact</span><span class="o">[</span><span class="n">n</span><span class="o">]</span> <span class="o">%</span> <span class="no">MOD</span> <span class="n">invfact</span><span class="o">[</span><span class="n">k</span><span class="o">]</span> <span class="o">%</span> <span class="no">MOD</span> <span class="n">invfact</span><span class="o">[</span><span class="n">n</span> <span class="o">-</span> <span class="n">k</span><span class="o">]</span> <span class="o">%</span> <span class="no">MOD</span><span class="o">;</span>
        <span class="o">}</span>
        <span class="kt">long</span> <span class="n">result</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">k</span> <span class="o">=</span> <span class="mi">1</span><span class="o">;</span> <span class="n">k</span> <span class="o">&lt;=</span> <span class="n">max_f</span><span class="o">;</span> <span class="n">k</span><span class="o">++)</span> <span class="o">{</span>
            <span class="kt">long</span> <span class="n">ways</span> <span class="o">=</span> <span class="mi">1</span><span class="o">;</span>
            <span class="k">for</span> <span class="o">(</span><span class="n">auto</span><span class="o">&amp;</span> <span class="o">[</span><span class="n">f</span><span class="o">,</span> <span class="n">count</span><span class="o">]</span> <span class="o">:</span> <span class="n">freqCount</span><span class="o">)</span> <span class="o">{</span>
                <span class="k">if</span> <span class="o">(</span><span class="n">f</span> <span class="o">&gt;=</span> <span class="n">k</span><span class="o">)</span> <span class="o">{</span>
                    <span class="kt">long</span> <span class="n">val</span> <span class="o">=</span> <span class="o">(</span><span class="mi">1</span> <span class="o">+</span> <span class="n">comb</span><span class="o">(</span><span class="n">f</span><span class="o">,</span> <span class="n">k</span><span class="o">))</span> <span class="o">%</span> <span class="no">MOD</span><span class="o">;</span>
                    <span class="n">ways</span> <span class="o">=</span> <span class="n">ways</span> <span class="nf">modPow</span><span class="o">(</span><span class="n">val</span><span class="o">,</span> <span class="n">count</span><span class="o">)</span> <span class="o">%</span> <span class="no">MOD</span><span class="o">;</span>
                <span class="o">}</span>
            <span class="o">}</span>
            <span class="n">ways</span> <span class="o">=</span> <span class="o">(</span><span class="n">ways</span> <span class="o">-</span> <span class="mi">1</span> <span class="o">+</span> <span class="no">MOD</span><span class="o">)</span> <span class="o">%</span> <span class="no">MOD</span><span class="o">;</span>
            <span class="n">result</span> <span class="o">=</span> <span class="o">(</span><span class="n">result</span> <span class="o">+</span> <span class="n">ways</span><span class="o">)</span> <span class="o">%</span> <span class="no">MOD</span><span class="o">;</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="n">result</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p><strong>Time:</strong> $O(\text{maxFreq} \times d)$ where $d$ = number of distinct frequencies ($d \le 26$)
<strong>Space:</strong> $O(\text{maxFreq})$</p>

<h3 id="why-group-by-frequency">Why Group by Frequency?</h3>

<p>If 10 characters all have frequency 5, Solution 1 multiplies <code class="language-plaintext highlighter-rouge">(1 + C(5, k))</code> ten separate times. Solution 2 computes <code class="language-plaintext highlighter-rouge">(1 + C(5, k))^10</code> in one <code class="language-plaintext highlighter-rouge">modPow</code> call. With at most 26 letters, $d \le 26$, so this doesn’t change asymptotic complexity but reduces constant factor work, especially when many characters share frequencies (e.g., <code class="language-plaintext highlighter-rouge">"aabbccddee..."</code>).</p>

<h2 id="walk-through-s--aabb">Walk-through: <code class="language-plaintext highlighter-rouge">s = "aabb"</code></h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>freq: a=2, b=2
max_f = 2

k=1:
  char a: 1 + C(2,1) = 1 + 2 = 3
  char b: 1 + C(2,1) = 1 + 2 = 3
  ways = 3 × 3 - 1 = 8

k=2:
  char a: 1 + C(2,2) = 1 + 1 = 2
  char b: 1 + C(2,2) = 1 + 1 = 2
  ways = 2 × 2 - 1 = 3

result = 8 + 3 = 11  ✓
</code></pre></div></div>

<h2 id="why-not-pascals-triangle">Why Not Pascal’s Triangle?</h2>

<p>For inputs like <code class="language-plaintext highlighter-rouge">"jjjjjj..."</code> (single character, frequency $10^4$), a Pascal table would need $O(n^2)$ space – up to $10^8$ entries. The factorial + modular inverse approach uses only $O(n)$ space and computes each $\binom{n}{k}$ in $O(1)$.</p>

<table>
  <thead>
    <tr>
      <th>Approach</th>
      <th>Space</th>
      <th>Per-query</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Pascal’s triangle</td>
      <td>$O(n^2)$</td>
      <td>$O(1)$</td>
    </tr>
    <tr>
      <td>Factorial + mod inverse</td>
      <td>$O(n)$</td>
      <td>$O(1)$</td>
    </tr>
  </tbody>
</table>

<h2 id="common-mistakes">Common Mistakes</h2>

<ul>
  <li><strong>Forgetting the $-1$:</strong> The product includes the case where every character is excluded (empty subsequence), which must be subtracted</li>
  <li><strong>Not clamping combinations:</strong> Only characters with <code class="language-plaintext highlighter-rouge">freq[c] &gt;= k</code> contribute; others must be skipped (their factor is just 1)</li>
  <li><strong>Using Pascal table for large $n$:</strong> Causes MLE; always use factorial arrays with Fermat inverse</li>
  <li><strong>Missing modular arithmetic:</strong> Intermediate products can overflow without <code class="language-plaintext highlighter-rouge">% MOD</code> at each step</li>
</ul>

<h2 id="key-takeaways">Key Takeaways</h2>

<ul>
  <li><strong>“Fix a parameter and count”</strong> is a powerful combinatorial strategy – here we fix the target frequency <code class="language-plaintext highlighter-rouge">k</code></li>
  <li>For each character, the choice is binary: include (choose $k$ copies) or exclude – giving a product formula</li>
  <li><strong>Modular inverse via Fermat’s little theorem</strong> ($a^{-1} \equiv a^{p-2} \pmod{p}$) is essential for efficient $\binom{n}{k}$ under modulo</li>
  <li>Grouping by frequency is a clean optimization when characters share the same count</li>
</ul>

<h2 id="related-problems">Related Problems</h2>

<ul>
  <li><a href="https://leetcode.com/problems/number-of-ways-to-reorder-array-to-get-same-bst/">1569. Number of Ways to Reorder Array to Get Same BST</a> – combinatorics with modular inverse</li>
  <li><a href="https://leetcode.com/problems/unique-paths/">62. Unique Paths</a> – basic combinatorics $\binom{m+n-2}{m-1}$</li>
  <li><a href="https://leetcode.com/problems/number-of-good-pairs/">1512. Number of Good Pairs</a> – frequency counting</li>
  <li><a href="https://leetcode.com/problems/distinct-subsequences-ii/">940. Distinct Subsequences II</a> – subsequence counting with DP</li>
</ul>]]></content><author><name></name></author><category term="leetcode" /><category term="hard" /><category term="combinatorics" /><category term="leetcode" /><category term="hard" /><category term="combinatorics" /><category term="modular-arithmetic" /><category term="math" /><category term="string" /><summary type="html"><![CDATA[Given a string s, return the number of non-empty good subsequences of s. A subsequence is good if every character in it appears the same number of times. Answer modulo $10^9 + 7$.]]></summary></entry><entry><title type="html">[Hard] 329. Longest Increasing Path in a Matrix</title><link href="https://robinali34.github.io/blog_leetcode_java/2026/04/18/hard-329-longest-increasing-path-in-a-matrix/" rel="alternate" type="text/html" title="[Hard] 329. Longest Increasing Path in a Matrix" /><published>2026-04-18T00:00:00+00:00</published><updated>2026-04-18T00:00:00+00:00</updated><id>https://robinali34.github.io/blog_leetcode_java/2026/04/18/hard-329-longest-increasing-path-in-a-matrix</id><content type="html" xml:base="https://robinali34.github.io/blog_leetcode_java/2026/04/18/hard-329-longest-increasing-path-in-a-matrix/"><![CDATA[<p>Given an <code class="language-plaintext highlighter-rouge">m x n</code> integers matrix, return the length of the <strong>longest strictly increasing path</strong>.</p>

<p>From each cell, you can move in four directions: up, down, left, or right. You may not move diagonally or outside the boundary.</p>

<h2 id="examples">Examples</h2>

<p><strong>Example 1:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Input:
  9  9  4
  6  6  8
  2  1  1

Output: 4

One longest path: 1 → 2 → 6 → 9
</code></pre></div></div>

<p><strong>Example 2:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Input:
  3  4  5
  3  2  6
  2  2  1

Output: 4

One longest path: 3 → 4 → 5 → 6
</code></pre></div></div>

<h2 id="constraints">Constraints</h2>

<ul>
  <li><code class="language-plaintext highlighter-rouge">m == matrix.length</code></li>
  <li><code class="language-plaintext highlighter-rouge">n == matrix[i].length</code></li>
  <li><code class="language-plaintext highlighter-rouge">1 &lt;= m, n &lt;= 200</code></li>
  <li><code class="language-plaintext highlighter-rouge">0 &lt;= matrix[i][j] &lt;= 2^31 - 1</code></li>
</ul>

<h2 id="thinking-process">Thinking Process</h2>

<h3 id="why-brute-force-fails">Why Brute Force Fails</h3>

<p>Starting DFS from every cell without caching repeats enormous amounts of work. A cell deep in the matrix gets re-explored from every path that leads to it.</p>

<h3 id="dfs--memoization">DFS + Memoization</h3>

<p>Define <code class="language-plaintext highlighter-rouge">dp[i][j]</code> = length of the longest increasing path <strong>starting from</strong> <code class="language-plaintext highlighter-rouge">(i, j)</code>.</p>

<p>From <code class="language-plaintext highlighter-rouge">(i, j)</code>, try all 4 neighbors <code class="language-plaintext highlighter-rouge">(nr, nc)</code> where <code class="language-plaintext highlighter-rouge">matrix[nr][nc] &gt; matrix[i][j]</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dp[i][j] = 1 + max(dp[nr][nc]) for all valid strictly-greater neighbors
</code></pre></div></div>

<p>If no neighbor is strictly greater, <code class="language-plaintext highlighter-rouge">dp[i][j] = 1</code>.</p>

<p>Since values are <strong>strictly increasing</strong>, there are no cycles. Each cell is computed exactly once, then cached.</p>

<h3 id="alternative-topological-sort-bfs">Alternative: Topological Sort (BFS)</h3>

<p>Think of the grid as a <strong>DAG</strong>: draw an edge <code class="language-plaintext highlighter-rouge">u → v</code> whenever <code class="language-plaintext highlighter-rouge">matrix[v] &gt; matrix[u]</code>. Then the longest increasing path = longest path in this DAG, which we can find via topological sort (Kahn’s algorithm):</p>

<ol>
  <li>Compute <strong>indegree</strong> of each cell (number of strictly-smaller neighbors)</li>
  <li>Start BFS from all cells with indegree 0 (local minima)</li>
  <li>Process layer by layer; each layer = one step in the path</li>
  <li>Number of BFS layers = answer</li>
</ol>

<h2 id="solution-1-dfs--memoization--omn-time-omn-space">Solution 1: DFS + Memoization – $O(mn)$ time, $O(mn)$ space</h2>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">Solution</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kt">int</span> <span class="nf">longestIncreasingPath</span><span class="o">(</span><span class="kt">int</span><span class="o">[][]&amp;</span> <span class="n">matrix</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">matrix</span><span class="o">.</span><span class="na">length</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="k">return</span> <span class="mi">0</span><span class="o">;</span>
        <span class="kt">int</span> <span class="n">rows</span> <span class="o">=</span> <span class="n">matrix</span><span class="o">.</span><span class="na">size</span><span class="o">();</span>
        <span class="kt">int</span> <span class="n">cols</span> <span class="o">=</span> <span class="n">matrix</span><span class="o">[</span><span class="mi">0</span><span class="o">].</span><span class="na">length</span><span class="o">;</span>
        <span class="kt">int</span><span class="o">[][]</span> <span class="n">dp</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">int</span><span class="o">[</span><span class="n">rows</span><span class="o">][</span><span class="n">cols</span><span class="o">];</span>
        <span class="kt">int</span> <span class="n">result</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>

        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">rows</span><span class="o">;</span> <span class="o">++</span><span class="n">i</span><span class="o">)</span> <span class="o">{</span>
            <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">cols</span><span class="o">;</span> <span class="o">++</span><span class="n">j</span><span class="o">)</span> <span class="o">{</span>
                <span class="n">result</span> <span class="o">=</span> <span class="nc">Math</span><span class="o">.</span><span class="na">max</span><span class="o">(</span><span class="n">result</span><span class="o">,</span> <span class="n">dfs</span><span class="o">(</span><span class="n">matrix</span><span class="o">,</span> <span class="n">dp</span><span class="o">,</span> <span class="n">i</span><span class="o">,</span> <span class="n">j</span><span class="o">));</span>
            <span class="o">}</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="n">result</span><span class="o">;</span>
    <span class="o">}</span>
    <span class="kt">int</span> <span class="n">dirs</span><span class="o">[</span><span class="mi">4</span><span class="o">][</span><span class="mi">2</span><span class="o">]</span> <span class="o">=</span> <span class="o">{{</span><span class="mi">0</span><span class="o">,</span> <span class="mi">1</span><span class="o">},</span> <span class="o">{</span><span class="mi">1</span><span class="o">,</span> <span class="mi">0</span><span class="o">},</span> <span class="o">{</span><span class="mi">0</span><span class="o">,</span> <span class="o">-</span><span class="mi">1</span><span class="o">},</span> <span class="o">{-</span><span class="mi">1</span><span class="o">,</span> <span class="mi">0</span><span class="o">}}</span>
    <span class="kt">int</span> <span class="nf">dfs</span><span class="o">(</span><span class="kt">int</span><span class="o">[][]&amp;</span> <span class="n">matrix</span><span class="o">,</span> <span class="kt">int</span><span class="o">[][]&amp;</span> <span class="n">dp</span><span class="o">,</span> <span class="kt">int</span> <span class="n">r</span><span class="o">,</span> <span class="kt">int</span> <span class="n">c</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">dp</span><span class="o">[</span><span class="n">r</span><span class="o">][</span><span class="n">c</span><span class="o">]</span> <span class="o">!)</span> <span class="k">return</span> <span class="n">dp</span><span class="o">[</span><span class="n">r</span><span class="o">][</span><span class="n">c</span><span class="o">];</span>
        <span class="kt">int</span> <span class="n">rows</span> <span class="o">=</span> <span class="n">matrix</span><span class="o">.</span><span class="na">size</span><span class="o">();</span>
        <span class="kt">int</span> <span class="n">cols</span> <span class="o">=</span> <span class="n">matrix</span><span class="o">[</span><span class="mi">0</span><span class="o">].</span><span class="na">length</span><span class="o">;</span>
        <span class="kt">int</span> <span class="n">maxLen</span> <span class="o">=</span> <span class="mi">1</span><span class="o">;</span>

        <span class="k">for</span> <span class="o">(</span><span class="n">auto</span> <span class="n">d</span> <span class="o">:</span> <span class="n">dirs</span><span class="o">)</span> <span class="o">{</span>
            <span class="kt">int</span> <span class="n">nr</span> <span class="o">=</span> <span class="n">r</span> <span class="o">+</span> <span class="n">d</span><span class="o">[</span><span class="mi">0</span><span class="o">];</span>
            <span class="kt">int</span> <span class="n">nc</span> <span class="o">=</span> <span class="n">c</span> <span class="o">+</span> <span class="n">d</span><span class="o">[</span><span class="mi">1</span><span class="o">];</span>
            <span class="k">if</span> <span class="o">(</span><span class="n">nr</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">nr</span> <span class="o">&lt;</span> <span class="n">rows</span> <span class="o">&amp;&amp;</span> <span class="n">nc</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">nc</span> <span class="o">&lt;</span> <span class="n">cols</span> <span class="o">&amp;&amp;</span>
                <span class="n">matrix</span><span class="o">[</span><span class="n">nr</span><span class="o">][</span><span class="n">nc</span><span class="o">]</span> <span class="o">&gt;</span> <span class="n">matrix</span><span class="o">[</span><span class="n">r</span><span class="o">][</span><span class="n">c</span><span class="o">])</span> <span class="o">{</span>
                <span class="n">maxLen</span> <span class="o">=</span> <span class="nc">Math</span><span class="o">.</span><span class="na">max</span><span class="o">(</span><span class="n">maxLen</span><span class="o">,</span> <span class="mi">1</span> <span class="o">+</span> <span class="n">dfs</span><span class="o">(</span><span class="n">matrix</span><span class="o">,</span> <span class="n">dp</span><span class="o">,</span> <span class="n">nr</span><span class="o">,</span> <span class="n">nc</span><span class="o">));</span>
            <span class="o">}</span>
        <span class="o">}</span>
        <span class="n">dp</span><span class="o">[</span><span class="n">r</span><span class="o">][</span><span class="n">c</span><span class="o">]</span> <span class="o">=</span> <span class="n">maxLen</span><span class="o">;</span>
        <span class="k">return</span> <span class="n">maxLen</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<h3 id="why-no-visited-array">Why No Visited Array?</h3>

<p>Unlike typical grid DFS, we don’t need a <code class="language-plaintext highlighter-rouge">visited</code> set. The <strong>strictly increasing</strong> constraint guarantees no cycles – you can never return to a cell you’ve already visited on the current path since its value would have to be both smaller and larger.</p>

<h3 id="why-memoization-works">Why Memoization Works</h3>

<p>Once <code class="language-plaintext highlighter-rouge">dp[r][c]</code> is computed, every future call that reaches <code class="language-plaintext highlighter-rouge">(r, c)</code> returns immediately. Each cell is fully explored exactly once, so total work across all DFS calls is $O(mn)$.</p>

<h2 id="solution-2-topological-sort-bfs--omn-time-omn-space">Solution 2: Topological Sort (BFS) – $O(mn)$ time, $O(mn)$ space</h2>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">Solution</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kt">int</span> <span class="nf">longestIncreasingPath</span><span class="o">(</span><span class="kt">int</span><span class="o">[][]&amp;</span> <span class="n">matrix</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">matrix</span><span class="o">.</span><span class="na">length</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="k">return</span> <span class="mi">0</span><span class="o">;</span>
        <span class="kt">int</span> <span class="n">rows</span> <span class="o">=</span> <span class="n">matrix</span><span class="o">.</span><span class="na">size</span><span class="o">();</span>
        <span class="kt">int</span> <span class="n">cols</span> <span class="o">=</span> <span class="n">matrix</span><span class="o">[</span><span class="mi">0</span><span class="o">].</span><span class="na">length</span><span class="o">;</span>

        <span class="kt">int</span><span class="o">[][]</span> <span class="n">indegree</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">int</span><span class="o">[</span><span class="n">rows</span><span class="o">][</span><span class="n">cols</span><span class="o">];</span>
        <span class="kt">int</span> <span class="n">dirs</span><span class="o">[</span><span class="mi">4</span><span class="o">][</span><span class="mi">2</span><span class="o">]</span> <span class="o">=</span> <span class="o">{{</span><span class="mi">1</span><span class="o">,</span> <span class="mi">0</span><span class="o">},</span> <span class="o">{-</span><span class="mi">1</span><span class="o">,</span> <span class="mi">0</span><span class="o">},</span> <span class="o">{</span><span class="mi">0</span><span class="o">,</span> <span class="mi">1</span><span class="o">},</span> <span class="o">{</span><span class="mi">0</span><span class="o">,</span> <span class="o">-</span><span class="mi">1</span><span class="o">}}</span>
        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">r</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">r</span> <span class="o">&lt;</span> <span class="n">rows</span><span class="o">;</span> <span class="o">++</span><span class="n">r</span><span class="o">)</span> <span class="o">{</span>
            <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">c</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">c</span> <span class="o">&lt;</span> <span class="n">cols</span><span class="o">;</span> <span class="o">++</span><span class="n">c</span><span class="o">)</span> <span class="o">{</span>
                <span class="k">for</span> <span class="o">(</span><span class="n">auto</span> <span class="n">d</span> <span class="o">:</span> <span class="n">dirs</span><span class="o">)</span> <span class="o">{</span>
                    <span class="kt">int</span> <span class="n">nr</span> <span class="o">=</span> <span class="n">r</span> <span class="o">+</span> <span class="n">d</span><span class="o">[</span><span class="mi">0</span><span class="o">];</span>
                    <span class="kt">int</span> <span class="n">nc</span> <span class="o">=</span> <span class="n">c</span> <span class="o">+</span> <span class="n">d</span><span class="o">[</span><span class="mi">1</span><span class="o">];</span>
                    <span class="k">if</span> <span class="o">(</span><span class="n">nr</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">nr</span> <span class="o">&lt;</span> <span class="n">rows</span> <span class="o">&amp;&amp;</span> <span class="n">nc</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">nc</span> <span class="o">&lt;</span> <span class="n">cols</span> <span class="o">&amp;&amp;</span>
                        <span class="n">matrix</span><span class="o">[</span><span class="n">nr</span><span class="o">][</span><span class="n">nc</span><span class="o">]</span> <span class="o">&lt;</span> <span class="n">matrix</span><span class="o">[</span><span class="n">r</span><span class="o">][</span><span class="n">c</span><span class="o">])</span> <span class="o">{</span>
                        <span class="n">indegree</span><span class="o">[</span><span class="n">r</span><span class="o">][</span><span class="n">c</span><span class="o">]++;</span>
                    <span class="o">}</span>
                <span class="o">}</span>
            <span class="o">}</span>
        <span class="o">}</span>

        <span class="n">queue</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">[]&gt;</span> <span class="n">q</span><span class="o">;</span>
        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">r</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">r</span> <span class="o">&lt;</span> <span class="n">rows</span><span class="o">;</span> <span class="o">++</span><span class="n">r</span><span class="o">)</span> <span class="o">{</span>
            <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">c</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">c</span> <span class="o">&lt;</span> <span class="n">cols</span><span class="o">;</span> <span class="o">++</span><span class="n">c</span><span class="o">)</span> <span class="o">{</span>
                <span class="k">if</span> <span class="o">(</span><span class="n">indegree</span><span class="o">[</span><span class="n">r</span><span class="o">][</span><span class="n">c</span><span class="o">]</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
                    <span class="n">q</span><span class="o">.</span><span class="na">push</span><span class="o">({</span><span class="n">r</span><span class="o">,</span> <span class="n">c</span><span class="o">});</span>
                <span class="o">}</span>
            <span class="o">}</span>
        <span class="o">}</span>

        <span class="kt">int</span> <span class="n">pathLen</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
        <span class="k">while</span> <span class="o">(!</span><span class="n">q</span><span class="o">.</span><span class="na">length</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
            <span class="kt">int</span> <span class="n">size</span> <span class="o">=</span> <span class="n">q</span><span class="o">.</span><span class="na">size</span><span class="o">();</span>
            <span class="n">pathLen</span><span class="o">++;</span>
            <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">size</span><span class="o">;</span> <span class="o">++</span><span class="n">i</span><span class="o">)</span> <span class="o">{</span>
                <span class="n">auto</span> <span class="o">[</span><span class="n">r</span><span class="o">,</span> <span class="n">c</span><span class="o">]</span> <span class="o">=</span> <span class="n">q</span><span class="o">.</span><span class="na">getFirst</span><span class="o">();</span>
                <span class="n">q</span><span class="o">.</span><span class="na">pop</span><span class="o">();</span>
                <span class="k">for</span> <span class="o">(</span><span class="n">auto</span> <span class="n">d</span> <span class="o">:</span> <span class="n">dirs</span><span class="o">)</span> <span class="o">{</span>
                    <span class="kt">int</span> <span class="n">nr</span> <span class="o">=</span> <span class="n">r</span> <span class="o">+</span> <span class="n">d</span><span class="o">[</span><span class="mi">0</span><span class="o">];</span>
                    <span class="kt">int</span> <span class="n">nc</span> <span class="o">=</span> <span class="n">c</span> <span class="o">+</span> <span class="n">d</span><span class="o">[</span><span class="mi">1</span><span class="o">];</span>
                    <span class="k">if</span> <span class="o">(</span><span class="n">nr</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">nr</span> <span class="o">&lt;</span> <span class="n">rows</span> <span class="o">&amp;&amp;</span> <span class="n">nc</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">nc</span> <span class="o">&lt;</span> <span class="n">cols</span> <span class="o">&amp;&amp;</span>
                        <span class="n">matrix</span><span class="o">[</span><span class="n">nr</span><span class="o">][</span><span class="n">nc</span><span class="o">]</span> <span class="o">&gt;</span> <span class="n">matrix</span><span class="o">[</span><span class="n">r</span><span class="o">][</span><span class="n">c</span><span class="o">])</span> <span class="o">{</span>
                        <span class="k">if</span> <span class="o">(--</span><span class="n">indegree</span><span class="o">[</span><span class="n">nr</span><span class="o">][</span><span class="n">nc</span><span class="o">]</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
                            <span class="n">q</span><span class="o">.</span><span class="na">push</span><span class="o">({</span><span class="n">nr</span><span class="o">,</span> <span class="n">nc</span><span class="o">});</span>
                        <span class="o">}</span>
                    <span class="o">}</span>
                <span class="o">}</span>
            <span class="o">}</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="n">pathLen</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<h3 id="walk-through">Walk-through</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Matrix:
  9  9  4
  6  6  8
  2  1  1

Indegree (# of strictly smaller neighbors):
  2  2  1
  1  1  2
  0  0  0

Layer 0 (indegree=0): (2,0)=2, (2,1)=1, (2,2)=1   pathLen=1
  Process: decrement neighbors' indegrees

Layer 1: (1,0)=6, (1,1)=6, (0,2)=4                  pathLen=2

Layer 2: (0,0)=9, (0,1)=9, (1,2)=8                  pathLen=3

Layer 3: (nothing new? let's trace...)
  Actually: after layer 1, (1,2)=8 gets indegree 0
  After layer 2, nothing remains

pathLen = 4  ✓
</code></pre></div></div>

<h2 id="comparison">Comparison</h2>

<table>
  <thead>
    <tr>
      <th>Aspect</th>
      <th>DFS + Memoization</th>
      <th>Topological Sort (BFS)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Approach</td>
      <td>Top-down recursion with cache</td>
      <td>Bottom-up layer-by-layer</td>
    </tr>
    <tr>
      <td>Recursion</td>
      <td>Yes (stack depth up to $mn$)</td>
      <td>No (iterative)</td>
    </tr>
    <tr>
      <td>Space</td>
      <td>$O(mn)$ dp + recursion stack</td>
      <td>$O(mn)$ indegree + queue</td>
    </tr>
    <tr>
      <td>When to prefer</td>
      <td>Simpler to write, natural for path problems</td>
      <td>Avoids stack overflow on large inputs</td>
    </tr>
    <tr>
      <td>Key insight</td>
      <td>Strictly increasing = no cycles = safe to memo</td>
      <td>Grid as DAG, longest path via topo sort</td>
    </tr>
  </tbody>
</table>

<h2 id="common-mistakes">Common Mistakes</h2>

<ul>
  <li><strong>Forgetting the strictly-greater check:</strong> Using <code class="language-plaintext highlighter-rouge">&gt;=</code> instead of <code class="language-plaintext highlighter-rouge">&gt;</code> creates cycles and infinite recursion</li>
  <li><strong>Using a visited array:</strong> Unnecessary here and would actually prevent correct memoization (a cell should be reachable from multiple starting points)</li>
  <li><strong>Returning 0 for base case:</strong> A single cell is a path of length <strong>1</strong>, not 0</li>
</ul>

<h2 id="key-takeaways">Key Takeaways</h2>

<ul>
  <li><strong>DFS + memoization on grid</strong> is a core pattern: define <code class="language-plaintext highlighter-rouge">dp[i][j]</code> as the answer starting from <code class="language-plaintext highlighter-rouge">(i, j)</code>, recurse on valid neighbors, cache results</li>
  <li><strong>Strictly increasing</strong> guarantees a DAG – no cycles means memoization is safe and topological sort applies</li>
  <li>The BFS approach reveals the problem’s structure: it’s just <strong>longest path in a DAG</strong> disguised as a grid problem</li>
  <li>Both solutions are $O(mn)$ – choose based on whether you prefer recursive or iterative style</li>
</ul>

<h2 id="related-problems">Related Problems</h2>

<ul>
  <li><a href="https://leetcode.com/problems/number-of-islands/">200. Number of Islands</a> – grid DFS without memoization</li>
  <li><a href="https://leetcode.com/problems/pacific-atlantic-water-flow/">417. Pacific Atlantic Water Flow</a> – grid DFS with multi-source</li>
  <li><a href="https://leetcode.com/problems/shortest-path-in-binary-matrix/">1091. Shortest Path in Binary Matrix</a> – grid BFS</li>
  <li><a href="https://leetcode.com/problems/maximal-square/">221. Maximal Square</a> – grid DP with neighbor transitions</li>
  <li><a href="https://leetcode.com/problems/course-schedule/">207. Course Schedule</a> – topological sort on explicit DAG</li>
</ul>

<h2 id="template-reference">Template Reference</h2>

<ul>
  <li><a href="/blog_leetcode_java/posts/2025-11-24-leetcode-templates-dfs/">DFS</a></li>
  <li><a href="/blog_leetcode_java/posts/2025-10-29-leetcode-templates-dp/">Dynamic Programming</a></li>
</ul>]]></content><author><name></name></author><category term="leetcode" /><category term="hard" /><category term="dynamic-programming" /><category term="dfs" /><category term="leetcode" /><category term="hard" /><category term="dfs" /><category term="memoization" /><category term="topological-sort" /><category term="bfs" /><category term="matrix" /><summary type="html"><![CDATA[Given an m x n integers matrix, return the length of the longest strictly increasing path.]]></summary></entry><entry><title type="html">[Medium] 221. Maximal Square</title><link href="https://robinali34.github.io/blog_leetcode_java/2026/04/18/medium-221-maximal-square/" rel="alternate" type="text/html" title="[Medium] 221. Maximal Square" /><published>2026-04-18T00:00:00+00:00</published><updated>2026-04-18T00:00:00+00:00</updated><id>https://robinali34.github.io/blog_leetcode_java/2026/04/18/medium-221-maximal-square</id><content type="html" xml:base="https://robinali34.github.io/blog_leetcode_java/2026/04/18/medium-221-maximal-square/"><![CDATA[<p>Given an <code class="language-plaintext highlighter-rouge">m x n</code> binary matrix filled with <code class="language-plaintext highlighter-rouge">'0'</code>s and <code class="language-plaintext highlighter-rouge">'1'</code>s, find the largest square containing only <code class="language-plaintext highlighter-rouge">'1'</code>s and return its area.</p>

<h2 id="examples">Examples</h2>

<p><strong>Example 1:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Input:
  1 0 1 0 0
  1 0 1 1 1
  1 1 1 1 1
  1 0 0 1 0

Output: 4   (a 2x2 square)
</code></pre></div></div>

<p><strong>Example 2:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Input:
  0 1
  1 0

Output: 1   (a 1x1 square)
</code></pre></div></div>

<p><strong>Example 3:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Input:
  0

Output: 0
</code></pre></div></div>

<h2 id="constraints">Constraints</h2>

<ul>
  <li><code class="language-plaintext highlighter-rouge">m == matrix.length</code></li>
  <li><code class="language-plaintext highlighter-rouge">n == matrix[i].length</code></li>
  <li><code class="language-plaintext highlighter-rouge">1 &lt;= m, n &lt;= 300</code></li>
  <li><code class="language-plaintext highlighter-rouge">matrix[i][j]</code> is <code class="language-plaintext highlighter-rouge">'0'</code> or <code class="language-plaintext highlighter-rouge">'1'</code></li>
</ul>

<h2 id="thinking-process">Thinking Process</h2>

<h3 id="the-dp-definition">The DP Definition</h3>

<p>Define <code class="language-plaintext highlighter-rouge">dp[i][j]</code> = <strong>side length</strong> of the largest square whose bottom-right corner is at <code class="language-plaintext highlighter-rouge">(i, j)</code>.</p>

<h3 id="the-transition">The Transition</h3>

<p>A square at <code class="language-plaintext highlighter-rouge">(i, j)</code> can only be as large as the smallest of its three neighbors plus one:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dp[i][j] = 1 + min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1])
</code></pre></div></div>

<p>Why? A square of side <code class="language-plaintext highlighter-rouge">k</code> at <code class="language-plaintext highlighter-rouge">(i, j)</code> requires:</p>
<ul>
  <li>A square of side <code class="language-plaintext highlighter-rouge">k-1</code> ending at <code class="language-plaintext highlighter-rouge">(i-1, j)</code> (top)</li>
  <li>A square of side <code class="language-plaintext highlighter-rouge">k-1</code> ending at <code class="language-plaintext highlighter-rouge">(i, j-1)</code> (left)</li>
  <li>A square of side <code class="language-plaintext highlighter-rouge">k-1</code> ending at <code class="language-plaintext highlighter-rouge">(i-1, j-1)</code> (diagonal)</li>
</ul>

<p>If any of these is smaller, it becomes the bottleneck.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  ┌──────────┐
  │ diag  top│
  │ left  cur│
  └──────────┘

dp[i-1][j-1]  dp[i-1][j]
dp[i][j-1]    dp[i][j] = 1 + min(top, left, diag)
</code></pre></div></div>

<h3 id="complete-walk-through">Complete Walk-through</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Matrix:                    DP table:
1 0 1 0 0                 1 0 1 0 0
1 0 1 1 1                 1 0 1 1 1
1 1 1 1 1                 1 1 1 2 2
1 0 0 1 0                 1 0 0 1 0
</code></pre></div></div>

<p>Key cells:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">dp[2][3]</code>: <code class="language-plaintext highlighter-rouge">min(top=1, left=1, diag=1) + 1 = 2</code> – a 2x2 square forms</li>
  <li><code class="language-plaintext highlighter-rouge">dp[2][4]</code>: <code class="language-plaintext highlighter-rouge">min(top=1, left=2, diag=1) + 1 = 2</code> – another 2x2 square</li>
  <li><code class="language-plaintext highlighter-rouge">dp[3][3]</code>: <code class="language-plaintext highlighter-rouge">min(top=2, left=0, diag=1) + 1 = 1</code> – left is 0, so only 1x1</li>
</ul>

<p>Max value = 2, so answer = $2^2 = 4$.</p>

<h2 id="solution-1-2d-dp--omn-time-omn-space">Solution 1: 2D DP – $O(mn)$ time, $O(mn)$ space</h2>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">Solution</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kt">int</span> <span class="nf">maximalSquare</span><span class="o">(</span><span class="kt">char</span><span class="o">[][]&amp;</span> <span class="n">matrix</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">matrix</span><span class="o">.</span><span class="na">length</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="k">return</span> <span class="mi">0</span><span class="o">;</span>
        <span class="kt">int</span> <span class="n">rows</span> <span class="o">=</span> <span class="n">matrix</span><span class="o">.</span><span class="na">size</span><span class="o">();</span>
        <span class="kt">int</span> <span class="n">cols</span> <span class="o">=</span> <span class="n">matrix</span><span class="o">[</span><span class="mi">0</span><span class="o">].</span><span class="na">length</span><span class="o">;</span>

        <span class="kt">int</span><span class="o">[][]</span> <span class="n">dp</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">int</span><span class="o">[</span><span class="n">rows</span><span class="o">][</span><span class="n">cols</span><span class="o">];</span>
        <span class="kt">int</span> <span class="n">maxSide</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>

        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">rows</span><span class="o">;</span> <span class="o">++</span><span class="n">i</span><span class="o">)</span> <span class="o">{</span>
            <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">cols</span><span class="o">;</span> <span class="o">++</span><span class="n">j</span><span class="o">)</span> <span class="o">{</span>
                <span class="k">if</span> <span class="o">(</span><span class="n">matrix</span><span class="o">[</span><span class="n">i</span><span class="o">][</span><span class="n">j</span><span class="o">]</span> <span class="o">==</span> <span class="sc">'1'</span><span class="o">)</span> <span class="o">{</span>
                    <span class="k">if</span> <span class="o">(</span><span class="n">i</span> <span class="o">==</span> <span class="mi">0</span> <span class="o">||</span> <span class="n">j</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
                        <span class="n">dp</span><span class="o">[</span><span class="n">i</span><span class="o">][</span><span class="n">j</span><span class="o">]</span> <span class="o">=</span> <span class="mi">1</span><span class="o">;</span>
                    <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
                        <span class="n">dp</span><span class="o">[</span><span class="n">i</span><span class="o">][</span><span class="n">j</span><span class="o">]</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">+</span> <span class="nc">Math</span><span class="o">.</span><span class="na">min</span><span class="o">({</span>
                            <span class="n">dp</span><span class="o">[</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="o">][</span><span class="n">j</span><span class="o">],</span>
                            <span class="n">dp</span><span class="o">[</span><span class="n">i</span><span class="o">][</span><span class="n">j</span> <span class="o">-</span> <span class="mi">1</span><span class="o">],</span>
                            <span class="n">dp</span><span class="o">[</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="o">][</span><span class="n">j</span> <span class="o">-</span> <span class="mi">1</span><span class="o">]</span>
                        <span class="o">});</span>
                    <span class="o">}</span>
                    <span class="n">maxSide</span> <span class="o">=</span> <span class="nc">Math</span><span class="o">.</span><span class="na">max</span><span class="o">(</span><span class="n">maxSide</span><span class="o">,</span> <span class="n">dp</span><span class="o">[</span><span class="n">i</span><span class="o">][</span><span class="n">j</span><span class="o">]);</span>
                <span class="o">}</span>
            <span class="o">}</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="n">maxSide</span> <span class="n">maxSide</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>The first row and first column are base cases: if <code class="language-plaintext highlighter-rouge">matrix[i][j] == '1'</code>, then <code class="language-plaintext highlighter-rouge">dp[i][j] = 1</code> (a 1x1 square at most).</p>

<h2 id="solution-2-space-optimized-1d-dp--omn-time-on-space">Solution 2: Space-Optimized 1D DP – $O(mn)$ time, $O(n)$ space</h2>

<p>Since each row only depends on the current and previous row, we can use a single 1D array.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">Solution</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kt">int</span> <span class="nf">maximalSquare</span><span class="o">(</span><span class="kt">char</span><span class="o">[][]&amp;</span> <span class="n">matrix</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">matrix</span><span class="o">.</span><span class="na">length</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="k">return</span> <span class="mi">0</span><span class="o">;</span>
        <span class="kt">int</span> <span class="n">rows</span> <span class="o">=</span> <span class="n">matrix</span><span class="o">.</span><span class="na">size</span><span class="o">();</span>
        <span class="kt">int</span> <span class="n">cols</span> <span class="o">=</span> <span class="n">matrix</span><span class="o">[</span><span class="mi">0</span><span class="o">].</span><span class="na">length</span><span class="o">;</span>

        <span class="kt">int</span><span class="o">[]</span> <span class="n">dp</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">int</span><span class="o">[</span><span class="n">cols</span><span class="o">];</span>
        <span class="kt">int</span> <span class="n">maxSide</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
        <span class="kt">int</span> <span class="n">prev</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>

        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">rows</span><span class="o">;</span> <span class="o">++</span><span class="n">i</span><span class="o">)</span> <span class="o">{</span>
            <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">cols</span><span class="o">;</span> <span class="o">++</span><span class="n">j</span><span class="o">)</span> <span class="o">{</span>
                <span class="kt">int</span> <span class="n">temp</span> <span class="o">=</span> <span class="n">dp</span><span class="o">[</span><span class="n">j</span><span class="o">];</span>
                <span class="k">if</span> <span class="o">(</span><span class="n">matrix</span><span class="o">[</span><span class="n">i</span><span class="o">][</span><span class="n">j</span><span class="o">]</span> <span class="o">==</span> <span class="sc">'1'</span><span class="o">)</span> <span class="o">{</span>
                    <span class="k">if</span> <span class="o">(</span><span class="n">i</span> <span class="o">==</span> <span class="mi">0</span> <span class="o">||</span> <span class="n">j</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
                        <span class="n">dp</span><span class="o">[</span><span class="n">j</span><span class="o">]</span> <span class="o">=</span> <span class="mi">1</span><span class="o">;</span>
                    <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
                        <span class="n">dp</span><span class="o">[</span><span class="n">j</span><span class="o">]</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">+</span> <span class="nc">Math</span><span class="o">.</span><span class="na">min</span><span class="o">({</span><span class="n">dp</span><span class="o">[</span><span class="n">j</span><span class="o">],</span> <span class="n">dp</span><span class="o">[</span><span class="n">j</span> <span class="o">-</span> <span class="mi">1</span><span class="o">],</span> <span class="n">prev</span><span class="o">});</span>
                    <span class="o">}</span>
                    <span class="n">maxSide</span> <span class="o">=</span> <span class="nc">Math</span><span class="o">.</span><span class="na">max</span><span class="o">(</span><span class="n">maxSide</span><span class="o">,</span> <span class="n">dp</span><span class="o">[</span><span class="n">j</span><span class="o">]);</span>
                <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
                    <span class="n">dp</span><span class="o">[</span><span class="n">j</span><span class="o">]</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
                <span class="o">}</span>
                <span class="n">prev</span> <span class="o">=</span> <span class="n">temp</span><span class="o">;</span>
            <span class="o">}</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="n">maxSide</span> <span class="n">maxSide</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<h3 id="variable-mapping">Variable Mapping</h3>

<table>
  <thead>
    <tr>
      <th>1D variable</th>
      <th>Equivalent in 2D</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">dp[j]</code> (before update)</td>
      <td><code class="language-plaintext highlighter-rouge">dp[i-1][j]</code> (top)</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">dp[j-1]</code> (already updated)</td>
      <td><code class="language-plaintext highlighter-rouge">dp[i][j-1]</code> (left)</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">prev</code> (saved before overwriting)</td>
      <td><code class="language-plaintext highlighter-rouge">dp[i-1][j-1]</code> (diagonal)</td>
    </tr>
  </tbody>
</table>

<p>The trick is saving <code class="language-plaintext highlighter-rouge">dp[j]</code> into <code class="language-plaintext highlighter-rouge">prev</code> <strong>before</strong> overwriting it, so the diagonal value from the previous row isn’t lost.</p>

<h2 id="why-min-of-three-neighbors">Why <code class="language-plaintext highlighter-rouge">min</code> of Three Neighbors?</h2>

<p>Consider why we can’t just check one or two neighbors:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Case: top=3, left=3, diag=1

    . . . .
    . 1 1 .
    . 1 1 .      ← diag is the bottleneck
    . . 1 ?

Even though top and left support a 3x3,
the diagonal gap limits us to a 2x2.
</code></pre></div></div>

<p>All three must agree for a larger square to exist. The minimum captures the tightest constraint.</p>

<h2 id="common-mistakes">Common Mistakes</h2>

<ul>
  <li><strong>Returning <code class="language-plaintext highlighter-rouge">maxSide</code> instead of <code class="language-plaintext highlighter-rouge">maxSide * maxSide</code>:</strong> The problem asks for <strong>area</strong>, not side length</li>
  <li><strong>Treating <code class="language-plaintext highlighter-rouge">matrix[i][j]</code> as int:</strong> The matrix contains <code class="language-plaintext highlighter-rouge">char</code> values (<code class="language-plaintext highlighter-rouge">'0'</code>/<code class="language-plaintext highlighter-rouge">'1'</code>), not integers</li>
  <li><strong>Forgetting to reset <code class="language-plaintext highlighter-rouge">dp[j] = 0</code> in 1D version:</strong> When <code class="language-plaintext highlighter-rouge">matrix[i][j] == '0'</code>, the cell must be explicitly zeroed</li>
</ul>

<h2 id="key-takeaways">Key Takeaways</h2>

<ul>
  <li>Classic 2D DP pattern: define state at each cell, derive from neighbors</li>
  <li>The <code class="language-plaintext highlighter-rouge">min</code> of three neighbors is the core insight – a square is only as large as its weakest constraint</li>
  <li>Space optimization from 2D to 1D is a standard technique: save the diagonal before overwriting</li>
  <li>Answer is $\text{maxSide}^2$ (area, not side length)</li>
</ul>

<h2 id="related-problems">Related Problems</h2>

<ul>
  <li><a href="https://leetcode.com/problems/maximal-rectangle/">85. Maximal Rectangle</a> – harder generalization using histogram approach</li>
  <li><a href="https://leetcode.com/problems/count-square-submatrices-with-all-ones/">1277. Count Square Submatrices with All Ones</a> – same DP, sum all <code class="language-plaintext highlighter-rouge">dp[i][j]</code> values</li>
  <li><a href="https://leetcode.com/problems/unique-paths/">62. Unique Paths</a> – similar 2D DP grid pattern</li>
  <li><a href="https://leetcode.com/problems/minimum-path-sum/">64. Minimum Path Sum</a> – 2D DP with neighbor transitions</li>
</ul>

<h2 id="template-reference">Template Reference</h2>

<ul>
  <li><a href="/blog_leetcode_java/posts/2025-10-29-leetcode-templates-dp/">Dynamic Programming</a></li>
</ul>]]></content><author><name></name></author><category term="leetcode" /><category term="medium" /><category term="dynamic-programming" /><category term="leetcode" /><category term="medium" /><category term="dynamic-programming" /><category term="matrix" /><category term="dp" /><summary type="html"><![CDATA[Given an m x n binary matrix filled with '0's and '1's, find the largest square containing only '1's and return its area.]]></summary></entry><entry><title type="html">[Medium] 274. H-Index</title><link href="https://robinali34.github.io/blog_leetcode_java/2026/04/17/medium-274-h-index/" rel="alternate" type="text/html" title="[Medium] 274. H-Index" /><published>2026-04-17T00:00:00+00:00</published><updated>2026-04-17T00:00:00+00:00</updated><id>https://robinali34.github.io/blog_leetcode_java/2026/04/17/medium-274-h-index</id><content type="html" xml:base="https://robinali34.github.io/blog_leetcode_java/2026/04/17/medium-274-h-index/"><![CDATA[<p>Given an array of integers <code class="language-plaintext highlighter-rouge">citations</code> where <code class="language-plaintext highlighter-rouge">citations[i]</code> is the number of citations a researcher received for their <code class="language-plaintext highlighter-rouge">i</code>-th paper, return the researcher’s <strong>h-index</strong>.</p>

<p>The h-index is defined as: the maximum value of <code class="language-plaintext highlighter-rouge">h</code> such that the researcher has published at least <code class="language-plaintext highlighter-rouge">h</code> papers that have each been cited at least <code class="language-plaintext highlighter-rouge">h</code> times.</p>

<h2 id="examples">Examples</h2>

<p><strong>Example 1:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Input: citations = [3, 0, 6, 1, 5]
Output: 3

Sort descending: [6, 5, 3, 1, 0]

  i (papers seen)   citations[i]   &gt;= i+1 ?
  1                 6              &gt;= 1  YES
  2                 5              &gt;= 2  YES
  3                 3              &gt;= 3  YES
  4                 1              &gt;= 4  NO   ← stop

Answer = 3 (3 papers with &gt;= 3 citations each)
</code></pre></div></div>

<p><strong>Example 2:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Input: citations = [1, 3, 1]
Output: 1
</code></pre></div></div>

<h2 id="constraints">Constraints</h2>

<ul>
  <li><code class="language-plaintext highlighter-rouge">n == citations.length</code></li>
  <li><code class="language-plaintext highlighter-rouge">1 &lt;= n &lt;= 5000</code></li>
  <li><code class="language-plaintext highlighter-rouge">0 &lt;= citations[i] &lt;= 1000</code></li>
</ul>

<h2 id="thinking-process">Thinking Process</h2>

<h3 id="what-are-we-really-looking-for">What Are We Really Looking For?</h3>

<p>This is <strong>not</strong> about total citations. It’s about finding a <strong>balance point</strong>: the largest <code class="language-plaintext highlighter-rouge">h</code> where at least <code class="language-plaintext highlighter-rouge">h</code> papers have <code class="language-plaintext highlighter-rouge">&gt;= h</code> citations.</p>

<h3 id="why-sorting-works">Why Sorting Works</h3>

<p>After sorting in descending order:</p>
<ul>
  <li><strong>Position <code class="language-plaintext highlighter-rouge">i+1</code></strong> = number of papers we’ve seen so far</li>
  <li><strong>Value <code class="language-plaintext highlighter-rouge">citations[i]</code></strong> = the citation count of the current paper</li>
</ul>

<p>At each position, we’re asking: “Does this paper have enough citations to support the current count of papers?”</p>

<p>The moment <code class="language-plaintext highlighter-rouge">citations[i] &lt; i + 1</code>, the balance breaks and we’ve found our answer.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Sorted: [6, 5, 3, 1, 0]

Index 0: 6 &gt;= 1  →  at least 1 paper with &gt;= 1 citations  ✓
Index 1: 5 &gt;= 2  →  at least 2 papers with &gt;= 2 citations ✓
Index 2: 3 &gt;= 3  →  at least 3 papers with &gt;= 3 citations ✓
Index 3: 1 &gt;= 4  →  at least 4 papers with &gt;= 4 citations ✗  ← STOP

h = 3
</code></pre></div></div>

<h3 id="can-we-do-better-than-on-log-n">Can We Do Better Than $O(n \log n)$?</h3>

<p>Yes – since <code class="language-plaintext highlighter-rouge">h</code> can be at most <code class="language-plaintext highlighter-rouge">n</code>, we can use counting sort to get $O(n)$.</p>

<h2 id="solution-1-sort-descending--on-log-n-time-o1-space">Solution 1: Sort Descending – $O(n \log n)$ time, $O(1)$ space</h2>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">Solution</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kt">int</span> <span class="nf">hIndex</span><span class="o">(</span><span class="kt">int</span><span class="o">[]</span> <span class="n">citations</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">sort</span><span class="o">(</span><span class="n">citations</span> <span class="cm">/* elements of citations */</span><span class="o">,</span> <span class="n">greater</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;());</span>
        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">citations</span><span class="o">.</span><span class="na">size</span><span class="o">();</span> <span class="o">++</span><span class="n">i</span><span class="o">)</span> <span class="o">{</span>
            <span class="k">if</span> <span class="o">(</span><span class="n">citations</span><span class="o">[</span><span class="n">i</span><span class="o">]</span> <span class="o">&lt;</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="o">)</span> <span class="k">return</span> <span class="n">i</span><span class="o">;</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="n">citations</span><span class="o">.</span><span class="na">size</span><span class="o">();</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>If every paper has enough citations, the loop finishes without returning, and <code class="language-plaintext highlighter-rouge">h = n</code>.</p>

<h2 id="solution-2-counting-sort--on-time-on-space">Solution 2: Counting Sort – $O(n)$ time, $O(n)$ space</h2>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">Solution</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kt">int</span> <span class="nf">hIndex</span><span class="o">(</span><span class="kt">int</span><span class="o">[]</span> <span class="n">citations</span><span class="o">)</span> <span class="o">{</span>
        <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="n">citations</span><span class="o">.</span><span class="na">size</span><span class="o">();</span>
        <span class="kt">int</span><span class="o">[]</span> <span class="n">count</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">int</span><span class="o">[</span><span class="n">n</span> <span class="o">+</span> <span class="mi">1</span><span class="o">];</span>

        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">c</span> <span class="o">:</span> <span class="n">citations</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">count</span><span class="o">[</span><span class="nc">Math</span><span class="o">.</span><span class="na">min</span><span class="o">(</span><span class="n">c</span><span class="o">,</span> <span class="n">n</span><span class="o">)]++;</span>
        <span class="o">}</span>

        <span class="kt">int</span> <span class="n">total</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">h</span> <span class="o">=</span> <span class="n">n</span><span class="o">;</span> <span class="n">h</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="o">;</span> <span class="o">--</span><span class="n">h</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">total</span> <span class="o">+=</span> <span class="n">count</span><span class="o">[</span><span class="n">h</span><span class="o">];</span>
            <span class="k">if</span> <span class="o">(</span><span class="n">total</span> <span class="o">&gt;=</span> <span class="n">h</span><span class="o">)</span> <span class="k">return</span> <span class="n">h</span><span class="o">;</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="mi">0</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<h3 id="how-it-works">How It Works</h3>

<ol>
  <li>
    <p><strong>Build a frequency array</strong> <code class="language-plaintext highlighter-rouge">count[i]</code> = number of papers with exactly <code class="language-plaintext highlighter-rouge">i</code> citations. Papers with <code class="language-plaintext highlighter-rouge">&gt;= n</code> citations are bucketed into <code class="language-plaintext highlighter-rouge">count[n]</code> since <code class="language-plaintext highlighter-rouge">h</code> can never exceed <code class="language-plaintext highlighter-rouge">n</code>.</p>
  </li>
  <li>
    <p><strong>Scan from <code class="language-plaintext highlighter-rouge">h = n</code> down to 0</strong>, accumulating the total number of papers with <code class="language-plaintext highlighter-rouge">&gt;= h</code> citations. The first <code class="language-plaintext highlighter-rouge">h</code> where <code class="language-plaintext highlighter-rouge">total &gt;= h</code> is the answer.</p>
  </li>
</ol>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>citations = [3, 0, 6, 1, 5],  n = 5

count:  index  0  1  2  3  4  5
        value  1  1  0  1  0  2   (6 and 5 both go into bucket 5)

Scan from h=5:  total=2, 2 &gt;= 5?  no
      h=4:  total=2, 2 &gt;= 4?  no
      h=3:  total=3, 3 &gt;= 3?  YES → return 3
</code></pre></div></div>

<h2 id="comparison">Comparison</h2>

<table>
  <thead>
    <tr>
      <th>Aspect</th>
      <th>Sorting</th>
      <th>Counting Sort</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Time</td>
      <td>$O(n \log n)$</td>
      <td>$O(n)$</td>
    </tr>
    <tr>
      <td>Space</td>
      <td>$O(1)$ (in-place sort)</td>
      <td>$O(n)$ (frequency array)</td>
    </tr>
    <tr>
      <td>Interview preference</td>
      <td>Most common, easy to explain</td>
      <td>Good follow-up for optimization</td>
    </tr>
    <tr>
      <td>Key idea</td>
      <td>Descending order gives “papers seen” naturally</td>
      <td>Bucket citations, scan from top</td>
    </tr>
  </tbody>
</table>

<h2 id="common-mistakes">Common Mistakes</h2>

<ul>
  <li><strong>Confusing h-index with max citations:</strong> <code class="language-plaintext highlighter-rouge">h</code> is bounded by the number of papers, not the citation values</li>
  <li><strong>Off-by-one in sorting approach:</strong> Position <code class="language-plaintext highlighter-rouge">i</code> means <code class="language-plaintext highlighter-rouge">i + 1</code> papers (0-indexed), so the check is <code class="language-plaintext highlighter-rouge">citations[i] &lt; i + 1</code></li>
  <li><strong>Forgetting the <code class="language-plaintext highlighter-rouge">min(c, n)</code> clamp in counting sort:</strong> Any citation count <code class="language-plaintext highlighter-rouge">&gt;= n</code> is equivalent since <code class="language-plaintext highlighter-rouge">h &lt;= n</code></li>
</ul>

<h2 id="key-takeaways">Key Takeaways</h2>

<ul>
  <li>The h-index is a <strong>balance point</strong> between quantity (number of papers) and quality (citation count)</li>
  <li>Sort descending and scan gives the most intuitive solution</li>
  <li>Counting sort exploits the fact that <code class="language-plaintext highlighter-rouge">h &lt;= n</code> to achieve linear time</li>
  <li>This pattern of “find the largest k satisfying a threshold” appears in many problems</li>
</ul>

<h2 id="related-problems">Related Problems</h2>

<ul>
  <li><a href="https://leetcode.com/problems/h-index-ii/">275. H-Index II</a> – sorted input, use binary search for $O(\log n)$</li>
  <li><a href="https://leetcode.com/problems/find-the-duplicate-number/">287. Find the Duplicate Number</a> – counting / pigeonhole</li>
  <li><a href="https://leetcode.com/problems/majority-element/">169. Majority Element</a> – finding a threshold in an array</li>
</ul>]]></content><author><name></name></author><category term="leetcode" /><category term="medium" /><category term="sorting" /><category term="leetcode" /><category term="medium" /><category term="array" /><category term="sorting" /><category term="counting-sort" /><category term="greedy" /><summary type="html"><![CDATA[Given an array of integers citations where citations[i] is the number of citations a researcher received for their i-th paper, return the researcher’s h-index.]]></summary></entry><entry><title type="html">[Medium] 92. Reverse Linked List II</title><link href="https://robinali34.github.io/blog_leetcode_java/2026/04/16/medium-92-reverse-linked-list-ii/" rel="alternate" type="text/html" title="[Medium] 92. Reverse Linked List II" /><published>2026-04-16T00:00:00+00:00</published><updated>2026-04-16T00:00:00+00:00</updated><id>https://robinali34.github.io/blog_leetcode_java/2026/04/16/medium-92-reverse-linked-list-ii</id><content type="html" xml:base="https://robinali34.github.io/blog_leetcode_java/2026/04/16/medium-92-reverse-linked-list-ii/"><![CDATA[<p>Given the <code class="language-plaintext highlighter-rouge">head</code> of a singly linked list and two integers <code class="language-plaintext highlighter-rouge">left</code> and <code class="language-plaintext highlighter-rouge">right</code> where <code class="language-plaintext highlighter-rouge">left &lt;= right</code>, reverse the nodes of the list from position <code class="language-plaintext highlighter-rouge">left</code> to position <code class="language-plaintext highlighter-rouge">right</code> (1-indexed), and return the reversed list.</p>

<h2 id="examples">Examples</h2>

<p><strong>Example 1:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Input: head = [1,2,3,4,5], left = 2, right = 4
Output: [1,4,3,2,5]

1 → [2 → 3 → 4] → 5
      ↓ reverse ↓
1 → [4 → 3 → 2] → 5
</code></pre></div></div>

<p><strong>Example 2:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Input: head = [5], left = 1, right = 1
Output: [5]
</code></pre></div></div>

<h2 id="constraints">Constraints</h2>

<ul>
  <li><code class="language-plaintext highlighter-rouge">1 &lt;= n &lt;= 500</code> (number of nodes)</li>
  <li><code class="language-plaintext highlighter-rouge">-500 &lt;= Node.val &lt;= 500</code></li>
  <li><code class="language-plaintext highlighter-rouge">1 &lt;= left &lt;= right &lt;= n</code></li>
</ul>

<h2 id="thinking-process">Thinking Process</h2>

<h3 id="break-it-into-3-parts">Break It Into 3 Parts</h3>

<ol>
  <li><strong>Traverse</strong> to the node before <code class="language-plaintext highlighter-rouge">left</code> – call it <code class="language-plaintext highlighter-rouge">prev</code></li>
  <li><strong>Reverse</strong> the sublist <code class="language-plaintext highlighter-rouge">[left .. right]</code></li>
  <li><strong>Reconnect</strong>: <code class="language-plaintext highlighter-rouge">prev → new head of reversed sublist</code>, <code class="language-plaintext highlighter-rouge">tail of reversed sublist → node after right</code></li>
</ol>

<h3 id="the-head-insertion-trick">The Head Insertion Trick</h3>

<p>Instead of doing a standard three-pointer reversal and then reconnecting, we can use <strong>head insertion</strong>: repeatedly pull the node after <code class="language-plaintext highlighter-rouge">curr</code> to the front of the sublist. This avoids re-traversing and naturally keeps all connections intact.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Initial:  prev → [a → b → c → d] → next
                  ↑             ↑
                left          right

Step 1: move b before a
          prev → [b → a → c → d] → next

Step 2: move c before b
          prev → [c → b → a → d] → next

Step 3: move d before c
          prev → [d → c → b → a] → next
</code></pre></div></div>

<p>Each step does 3 pointer swaps and the sublist grows by one node at the front.</p>

<h3 id="edge-cases">Edge Cases</h3>

<table>
  <thead>
    <tr>
      <th>Case</th>
      <th>Handling</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">left == 1</code> (head changes)</td>
      <td>Dummy node absorbs head change</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">left == right</code> (no-op)</td>
      <td>Early return</td>
    </tr>
    <tr>
      <td>Single node</td>
      <td>Early return</td>
    </tr>
  </tbody>
</table>

<h2 id="solution-1-head-insertion--on-time-o1-space">Solution 1: Head Insertion – $O(n)$ time, $O(1)$ space</h2>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">Solution</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="nc">ListNode</span> <span class="nf">reverseBetween</span><span class="o">(</span><span class="nc">ListNode</span> <span class="n">head</span><span class="o">,</span> <span class="kt">int</span> <span class="n">left</span><span class="o">,</span> <span class="kt">int</span> <span class="n">right</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">if</span> <span class="o">(!</span><span class="n">head</span> <span class="o">||</span> <span class="n">left</span> <span class="o">==</span> <span class="n">right</span><span class="o">)</span> <span class="k">return</span> <span class="n">head</span><span class="o">;</span>

        <span class="nc">ListNode</span> <span class="nf">dummy</span><span class="o">(</span><span class="mi">0</span><span class="o">);</span>
        <span class="n">dummy</span><span class="o">.</span><span class="na">next</span> <span class="o">=</span> <span class="n">head</span><span class="o">;</span>
        <span class="nc">ListNode</span> <span class="n">prev</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">dummy</span><span class="o">;</span>

        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">left</span><span class="o">;</span> <span class="o">++</span><span class="n">i</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">prev</span> <span class="o">=</span> <span class="n">prev</span><span class="o">.</span><span class="na">next</span><span class="o">;</span>
        <span class="o">}</span>

        <span class="nc">ListNode</span> <span class="n">curr</span> <span class="o">=</span> <span class="n">prev</span><span class="o">.</span><span class="na">next</span><span class="o">;</span>
        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">right</span> <span class="o">-</span> <span class="n">left</span><span class="o">;</span> <span class="o">++</span><span class="n">i</span><span class="o">)</span> <span class="o">{</span>
            <span class="nc">ListNode</span> <span class="n">tmp</span> <span class="o">=</span> <span class="n">curr</span><span class="o">.</span><span class="na">next</span><span class="o">;</span>
            <span class="n">curr</span><span class="o">.</span><span class="na">next</span> <span class="o">=</span> <span class="n">tmp</span><span class="o">.</span><span class="na">next</span><span class="o">;</span>
            <span class="n">tmp</span><span class="o">.</span><span class="na">next</span> <span class="o">=</span> <span class="n">prev</span><span class="o">.</span><span class="na">next</span><span class="o">;</span>
            <span class="n">prev</span><span class="o">.</span><span class="na">next</span> <span class="o">=</span> <span class="n">tmp</span><span class="o">;</span>
        <span class="o">}</span>

        <span class="k">return</span> <span class="n">dummy</span><span class="o">.</span><span class="na">next</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<h3 id="how-the-inner-loop-works">How the Inner Loop Works</h3>

<p>Each iteration moves <code class="language-plaintext highlighter-rouge">curr-&gt;next</code> to the front of the sublist:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Before iteration:   prev → [... → curr → tmp → rest]
After iteration:    prev → [tmp → ... → curr → rest]
</code></pre></div></div>

<ul>
  <li><code class="language-plaintext highlighter-rouge">curr-&gt;next = tmp-&gt;next</code> – detach <code class="language-plaintext highlighter-rouge">tmp</code> from its position</li>
  <li><code class="language-plaintext highlighter-rouge">tmp-&gt;next = prev-&gt;next</code> – point <code class="language-plaintext highlighter-rouge">tmp</code> to the current front of the sublist</li>
  <li><code class="language-plaintext highlighter-rouge">prev-&gt;next = tmp</code> – make <code class="language-plaintext highlighter-rouge">tmp</code> the new front</li>
</ul>

<p>Note that <code class="language-plaintext highlighter-rouge">curr</code> never moves – it starts as the first node of the sublist and ends as the last.</p>

<h2 id="solution-2-classic-reversal--on-time-o1-space">Solution 2: Classic Reversal – $O(n)$ time, $O(1)$ space</h2>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">Solution</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="nc">ListNode</span> <span class="nf">reverseBetween</span><span class="o">(</span><span class="nc">ListNode</span> <span class="n">head</span><span class="o">,</span> <span class="kt">int</span> <span class="n">left</span><span class="o">,</span> <span class="kt">int</span> <span class="n">right</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">if</span> <span class="o">(!</span><span class="n">head</span> <span class="o">||</span> <span class="n">left</span> <span class="o">==</span> <span class="n">right</span><span class="o">)</span> <span class="k">return</span> <span class="n">head</span><span class="o">;</span>

        <span class="nc">ListNode</span> <span class="n">cur</span> <span class="o">=</span> <span class="n">head</span><span class="o">;</span>
        <span class="nc">ListNode</span> <span class="n">pre</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
        <span class="k">while</span> <span class="o">(</span><span class="n">left</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">pre</span> <span class="o">=</span> <span class="n">cur</span><span class="o">;</span>
            <span class="n">cur</span> <span class="o">=</span> <span class="n">cur</span><span class="o">.</span><span class="na">next</span><span class="o">;</span>
            <span class="n">left</span><span class="o">--;</span>
            <span class="n">right</span><span class="o">--;</span>
        <span class="o">}</span>

        <span class="nc">ListNode</span> <span class="n">con</span> <span class="o">=</span> <span class="n">pre</span><span class="o">;</span>
        <span class="nc">ListNode</span> <span class="n">tail</span> <span class="o">=</span> <span class="n">cur</span><span class="o">;</span>
        <span class="nc">ListNode</span> <span class="n">third</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
        <span class="k">while</span> <span class="o">(</span><span class="n">right</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">third</span> <span class="o">=</span> <span class="n">cur</span><span class="o">.</span><span class="na">next</span><span class="o">;</span>
            <span class="n">cur</span><span class="o">.</span><span class="na">next</span> <span class="o">=</span> <span class="n">pre</span><span class="o">;</span>
            <span class="n">pre</span> <span class="o">=</span> <span class="n">cur</span><span class="o">;</span>
            <span class="n">cur</span> <span class="o">=</span> <span class="n">third</span><span class="o">;</span>
            <span class="n">right</span><span class="o">--;</span>
        <span class="o">}</span>

        <span class="k">if</span> <span class="o">(</span><span class="n">con</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">con</span><span class="o">.</span><span class="na">next</span> <span class="o">=</span> <span class="n">pre</span><span class="o">;</span>
        <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
            <span class="n">head</span> <span class="o">=</span> <span class="n">pre</span><span class="o">;</span>
        <span class="o">}</span>
        <span class="n">tail</span><span class="o">.</span><span class="na">next</span> <span class="o">=</span> <span class="n">cur</span><span class="o">;</span>

        <span class="k">return</span> <span class="n">head</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<h3 id="walk-through">Walk-through</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>head = [1, 2, 3, 4, 5], left = 2, right = 4

Phase 1: Advance to position left
  pre = node(1), cur = node(2)   [left=1, right=3 after decrement]

Phase 2: Reverse right nodes starting from cur
  con = node(1)   (node before sublist)
  tail = node(2)  (will become tail of reversed sublist)

  Iteration 1: reverse 2→3  →  2←3   cur=node(3), pre=node(2)... wait
  Actually: 2→1 (wrong link, but ok), pre=2, cur=3, right=2
  Iteration 2: 3→2, pre=3, cur=4, right=1
  Iteration 3: 4→3, pre=4, cur=5, right=0

Phase 3: Reconnect
  con.next = pre  →  node(1).next = node(4)
  tail.next = cur →  node(2).next = node(5)

Result: 1 → 4 → 3 → 2 → 5  ✓
</code></pre></div></div>

<table>
  <thead>
    <tr>
      <th>Pointer</th>
      <th>Role</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">con</code></td>
      <td>Node before the sublist (saved before reversal)</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">tail</code></td>
      <td>First node of original sublist = last node after reversal</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">pre</code></td>
      <td>Last node reversed = new head of sublist</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">cur</code></td>
      <td>First node after the reversed sublist</td>
    </tr>
  </tbody>
</table>

<h2 id="comparison">Comparison</h2>

<table>
  <thead>
    <tr>
      <th>Aspect</th>
      <th>Head Insertion</th>
      <th>Classic Reversal</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Uses dummy node</td>
      <td>Yes (handles <code class="language-plaintext highlighter-rouge">left == 1</code>)</td>
      <td>No (explicit <code class="language-plaintext highlighter-rouge">if</code> for <code class="language-plaintext highlighter-rouge">left == 1</code>)</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">curr</code> pointer movement</td>
      <td>Stays fixed</td>
      <td>Advances through sublist</td>
    </tr>
    <tr>
      <td>Reconnection</td>
      <td>Automatic (pointers stay connected)</td>
      <td>Manual (set <code class="language-plaintext highlighter-rouge">con.next</code> and <code class="language-plaintext highlighter-rouge">tail.next</code>)</td>
    </tr>
    <tr>
      <td>Conceptual complexity</td>
      <td>Lower – single pattern repeated</td>
      <td>Higher – two distinct phases</td>
    </tr>
  </tbody>
</table>

<h2 id="common-mistakes">Common Mistakes</h2>

<ul>
  <li><strong>Off-by-one on <code class="language-plaintext highlighter-rouge">prev</code>:</strong> Walking <code class="language-plaintext highlighter-rouge">left</code> steps from dummy lands on node <code class="language-plaintext highlighter-rouge">left</code>, but we need node <code class="language-plaintext highlighter-rouge">left - 1</code>. Walk <code class="language-plaintext highlighter-rouge">left - 1</code> steps instead.</li>
  <li><strong>Moving <code class="language-plaintext highlighter-rouge">curr</code> in head insertion:</strong> <code class="language-plaintext highlighter-rouge">curr</code> should stay fixed – it’s always the tail of the growing reversed sublist. Only <code class="language-plaintext highlighter-rouge">tmp</code> moves.</li>
  <li><strong>Forgetting <code class="language-plaintext highlighter-rouge">left == 1</code>:</strong> Without a dummy, the head of the list changes. Either use a dummy or handle this case explicitly.</li>
</ul>

<h2 id="key-takeaways">Key Takeaways</h2>

<ul>
  <li><strong>Head insertion</strong> is the cleanest pattern for partial reversal – no separate reconnection step needed</li>
  <li>A <strong>dummy node</strong> eliminates the <code class="language-plaintext highlighter-rouge">left == 1</code> edge case entirely</li>
  <li>Both approaches are $O(n)$ time and $O(1)$ space – the choice is about clarity, not performance</li>
</ul>

<h2 id="related-problems">Related Problems</h2>

<ul>
  <li><a href="https://leetcode.com/problems/reverse-linked-list/">206. Reverse Linked List</a> – full list reversal</li>
  <li><a href="https://leetcode.com/problems/reverse-nodes-in-k-group/">25. Reverse Nodes in k-Group</a> – reverse segments of size k</li>
  <li><a href="https://leetcode.com/problems/swap-nodes-in-pairs/">24. Swap Nodes in Pairs</a> – special case of k=2 reversal</li>
  <li><a href="https://leetcode.com/problems/merge-in-between-linked-lists/">1669. Merge In Between Linked Lists</a> – similar pointer surgery on a sublist range</li>
</ul>

<h2 id="template-reference">Template Reference</h2>

<ul>
  <li><a href="/blog_leetcode_java/posts/2025-11-24-leetcode-templates-linked-list/">Linked List</a></li>
</ul>]]></content><author><name></name></author><category term="leetcode" /><category term="medium" /><category term="linked-list" /><category term="leetcode" /><category term="medium" /><category term="linked-list" /><category term="reversal" /><category term="pointer-manipulation" /><summary type="html"><![CDATA[Given the head of a singly linked list and two integers left and right where left &lt;= right, reverse the nodes of the list from position left to position right (1-indexed), and return the reversed list.]]></summary></entry><entry><title type="html">[Medium] 1669. Merge In Between Linked Lists</title><link href="https://robinali34.github.io/blog_leetcode_java/2026/04/15/medium-1669-merge-in-between-linked-lists/" rel="alternate" type="text/html" title="[Medium] 1669. Merge In Between Linked Lists" /><published>2026-04-15T00:00:00+00:00</published><updated>2026-04-15T00:00:00+00:00</updated><id>https://robinali34.github.io/blog_leetcode_java/2026/04/15/medium-1669-merge-in-between-linked-lists</id><content type="html" xml:base="https://robinali34.github.io/blog_leetcode_java/2026/04/15/medium-1669-merge-in-between-linked-lists/"><![CDATA[<p>You are given two linked lists: <code class="language-plaintext highlighter-rouge">list1</code> and <code class="language-plaintext highlighter-rouge">list2</code> of sizes <code class="language-plaintext highlighter-rouge">n</code> and <code class="language-plaintext highlighter-rouge">m</code> respectively. Remove <code class="language-plaintext highlighter-rouge">list1</code>’s nodes from the <code class="language-plaintext highlighter-rouge">a</code>-th node to the <code class="language-plaintext highlighter-rouge">b</code>-th node (0-indexed), and put <code class="language-plaintext highlighter-rouge">list2</code> in their place.</p>

<h2 id="examples">Examples</h2>

<p><strong>Example 1:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Input: list1 = [10,1,13,6,9,5], a = 3, b = 4, list2 = [1000000,1000001,1000002]
Output: [10,1,13,1000000,1000001,1000002,5]

list1:  10 → 1 → 13 → [6 → 9] → 5
                        ↑ remove ↑
list2:  1000000 → 1000001 → 1000002

Result: 10 → 1 → 13 → 1000000 → 1000001 → 1000002 → 5
</code></pre></div></div>

<p><strong>Example 2:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Input: list1 = [0,1,2,3,4,5,6], a = 2, b = 5, list2 = [1000000,1000001,1000002,1000003,1000004]
Output: [0,1,1000000,1000001,1000002,1000003,1000004,6]
</code></pre></div></div>

<h2 id="constraints">Constraints</h2>

<ul>
  <li><code class="language-plaintext highlighter-rouge">3 &lt;= list1.length &lt;= 10^4</code></li>
  <li><code class="language-plaintext highlighter-rouge">1 &lt;= a &lt;= b &lt; list1.length - 1</code></li>
  <li><code class="language-plaintext highlighter-rouge">1 &lt;= list2.length &lt;= 10^4</code></li>
</ul>

<p>The constraints guarantee <code class="language-plaintext highlighter-rouge">a &gt;= 1</code> and <code class="language-plaintext highlighter-rouge">b &lt; n - 1</code>, so there is always at least one node before <code class="language-plaintext highlighter-rouge">a</code> and one node after <code class="language-plaintext highlighter-rouge">b</code>.</p>

<h2 id="thinking-process">Thinking Process</h2>

<h3 id="what-do-we-need">What Do We Need?</h3>

<p>We’re splicing <code class="language-plaintext highlighter-rouge">list2</code> into <code class="language-plaintext highlighter-rouge">list1</code> by removing positions <code class="language-plaintext highlighter-rouge">a..b</code>. That means three pointer rewirings:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>prevA → list2_head → ... → list2_tail → afterB
</code></pre></div></div>

<p>We need:</p>
<ol>
  <li><strong><code class="language-plaintext highlighter-rouge">prevA</code></strong> – the node at index <code class="language-plaintext highlighter-rouge">a - 1</code> (just before the removed segment)</li>
  <li><strong><code class="language-plaintext highlighter-rouge">afterB</code></strong> – the node at index <code class="language-plaintext highlighter-rouge">b + 1</code> (just after the removed segment)</li>
  <li><strong><code class="language-plaintext highlighter-rouge">tail2</code></strong> – the last node of <code class="language-plaintext highlighter-rouge">list2</code></li>
</ol>

<h3 id="why-no-dummy-node-needed">Why No Dummy Node Needed?</h3>

<p>Since <code class="language-plaintext highlighter-rouge">a &gt;= 1</code>, the head of <code class="language-plaintext highlighter-rouge">list1</code> is never removed, so we don’t need a dummy node to protect the head.</p>

<h3 id="walk-through">Walk-through</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>list1: 10 → 1 → 13 → 6 → 9 → 5     a=3, b=4
index:  0   1    2   3   4   5

Step 1: Walk to index a-1 = 2
  prevA = node(13)

Step 2: From prevA, walk (b - a + 1) more steps to reach node at index b
  then afterB = that node's next
  afterB = node(5)

Step 3: Find tail of list2
  list2: 1000000 → 1000001 → 1000002
  tail2 = node(1000002)

Step 4: Rewire
  prevA.next = list2         →  13 → 1000000
  tail2.next = afterB        →  1000002 → 5

Result: 10 → 1 → 13 → 1000000 → 1000001 → 1000002 → 5  ✓
</code></pre></div></div>

<h2 id="solution-pointer-manipulation--on--m-time-o1-space">Solution: Pointer Manipulation – $O(n + m)$ time, $O(1)$ space</h2>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">Solution</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="nc">ListNode</span> <span class="nf">mergeInBetween</span><span class="o">(</span><span class="nc">ListNode</span> <span class="n">list1</span><span class="o">,</span> <span class="kt">int</span> <span class="n">a</span><span class="o">,</span> <span class="kt">int</span> <span class="n">b</span><span class="o">,</span> <span class="nc">ListNode</span> <span class="n">list2</span><span class="o">)</span> <span class="o">{</span>
        <span class="nc">ListNode</span> <span class="nf">dummy</span><span class="o">(</span><span class="mi">0</span><span class="o">);</span>
        <span class="n">dummy</span><span class="o">.</span><span class="na">next</span> <span class="o">=</span> <span class="n">list1</span><span class="o">;</span>

        <span class="nc">ListNode</span> <span class="n">prevA</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">dummy</span><span class="o">;</span>
        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">a</span><span class="o">;</span> <span class="o">++</span><span class="n">i</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">prevA</span> <span class="o">=</span> <span class="n">prevA</span><span class="o">.</span><span class="na">next</span><span class="o">;</span>
        <span class="o">}</span>

        <span class="nc">ListNode</span> <span class="n">afterB</span> <span class="o">=</span> <span class="n">prevA</span><span class="o">;</span>
        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">b</span> <span class="o">-</span> <span class="n">a</span><span class="o">;</span> <span class="o">++</span><span class="n">i</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">afterB</span> <span class="o">=</span> <span class="n">afterB</span><span class="o">.</span><span class="na">next</span><span class="o">;</span>
        <span class="o">}</span>
        <span class="n">afterB</span> <span class="o">=</span> <span class="n">afterB</span><span class="o">.</span><span class="na">next</span><span class="o">;</span>

        <span class="n">prevA</span><span class="o">.</span><span class="na">next</span> <span class="o">=</span> <span class="n">list2</span><span class="o">;</span>

        <span class="nc">ListNode</span> <span class="n">tail</span> <span class="o">=</span> <span class="n">list2</span><span class="o">;</span>
        <span class="k">while</span> <span class="o">(</span><span class="n">tail</span><span class="o">.</span><span class="na">next</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">tail</span> <span class="o">=</span> <span class="n">tail</span><span class="o">.</span><span class="na">next</span><span class="o">;</span>
        <span class="o">}</span>
        <span class="n">tail</span><span class="o">.</span><span class="na">next</span> <span class="o">=</span> <span class="n">afterB</span><span class="o">;</span>

        <span class="k">return</span> <span class="n">dummy</span><span class="o">.</span><span class="na">next</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p><strong>Time:</strong> $O(n + m)$ – traverse <code class="language-plaintext highlighter-rouge">list1</code> up to index <code class="language-plaintext highlighter-rouge">b</code>, then traverse all of <code class="language-plaintext highlighter-rouge">list2</code>
<strong>Space:</strong> $O(1)$ – only pointer variables</p>

<h2 id="key-details">Key Details</h2>

<table>
  <thead>
    <tr>
      <th>Detail</th>
      <th>Explanation</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Why <code class="language-plaintext highlighter-rouge">dummy</code>?</td>
      <td>Although the head is never removed (since <code class="language-plaintext highlighter-rouge">a &gt;= 1</code>), using a dummy keeps the traversal logic uniform – <code class="language-plaintext highlighter-rouge">prevA</code> starts at dummy and walks <code class="language-plaintext highlighter-rouge">a</code> steps</td>
    </tr>
    <tr>
      <td>Finding <code class="language-plaintext highlighter-rouge">afterB</code> from <code class="language-plaintext highlighter-rouge">prevA</code></td>
      <td>Starting from <code class="language-plaintext highlighter-rouge">prevA</code> (index <code class="language-plaintext highlighter-rouge">a-1</code>), we walk <code class="language-plaintext highlighter-rouge">b - a + 1</code> steps to reach the node at index <code class="language-plaintext highlighter-rouge">b</code>, then one more <code class="language-plaintext highlighter-rouge">.next</code> to get <code class="language-plaintext highlighter-rouge">afterB</code></td>
    </tr>
    <tr>
      <td>Finding <code class="language-plaintext highlighter-rouge">tail2</code> separately</td>
      <td>We can’t assume anything about <code class="language-plaintext highlighter-rouge">list2</code>’s length, so we walk to its end</td>
    </tr>
  </tbody>
</table>

<h2 id="without-dummy-slightly-simpler">Without Dummy (Slightly Simpler)</h2>

<p>Since the constraints guarantee <code class="language-plaintext highlighter-rouge">a &gt;= 1</code>, we can skip the dummy:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">Solution</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="nc">ListNode</span> <span class="nf">mergeInBetween</span><span class="o">(</span><span class="nc">ListNode</span> <span class="n">list1</span><span class="o">,</span> <span class="kt">int</span> <span class="n">a</span><span class="o">,</span> <span class="kt">int</span> <span class="n">b</span><span class="o">,</span> <span class="nc">ListNode</span> <span class="n">list2</span><span class="o">)</span> <span class="o">{</span>
        <span class="nc">ListNode</span> <span class="n">prevA</span> <span class="o">=</span> <span class="n">list1</span><span class="o">;</span>
        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">a</span> <span class="o">-</span> <span class="mi">1</span><span class="o">;</span> <span class="o">++</span><span class="n">i</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">prevA</span> <span class="o">=</span> <span class="n">prevA</span><span class="o">.</span><span class="na">next</span><span class="o">;</span>
        <span class="o">}</span>

        <span class="nc">ListNode</span> <span class="n">afterB</span> <span class="o">=</span> <span class="n">prevA</span><span class="o">;</span>
        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">b</span> <span class="o">-</span> <span class="n">a</span> <span class="o">+</span> <span class="mi">1</span><span class="o">;</span> <span class="o">++</span><span class="n">i</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">afterB</span> <span class="o">=</span> <span class="n">afterB</span><span class="o">.</span><span class="na">next</span><span class="o">;</span>
        <span class="o">}</span>

        <span class="n">prevA</span><span class="o">.</span><span class="na">next</span> <span class="o">=</span> <span class="n">list2</span><span class="o">;</span>

        <span class="nc">ListNode</span> <span class="n">tail</span> <span class="o">=</span> <span class="n">list2</span><span class="o">;</span>
        <span class="k">while</span> <span class="o">(</span><span class="n">tail</span><span class="o">.</span><span class="na">next</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">tail</span> <span class="o">=</span> <span class="n">tail</span><span class="o">.</span><span class="na">next</span><span class="o">;</span>
        <span class="o">}</span>
        <span class="n">tail</span><span class="o">.</span><span class="na">next</span> <span class="o">=</span> <span class="n">afterB</span><span class="o">;</span>

        <span class="k">return</span> <span class="n">list1</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<h2 id="common-mistakes">Common Mistakes</h2>

<ul>
  <li><strong>Off-by-one on <code class="language-plaintext highlighter-rouge">prevA</code>:</strong> Walking <code class="language-plaintext highlighter-rouge">a</code> steps from head lands on index <code class="language-plaintext highlighter-rouge">a</code>, but we need index <code class="language-plaintext highlighter-rouge">a - 1</code>. Use a dummy or walk <code class="language-plaintext highlighter-rouge">a - 1</code> steps.</li>
  <li><strong>Off-by-one on <code class="language-plaintext highlighter-rouge">afterB</code>:</strong> Forgetting the final <code class="language-plaintext highlighter-rouge">.next</code> after reaching the node at index <code class="language-plaintext highlighter-rouge">b</code>.</li>
  <li><strong>Forgetting to find <code class="language-plaintext highlighter-rouge">tail2</code>:</strong> The connection <code class="language-plaintext highlighter-rouge">list2_tail → afterB</code> is easy to miss if you only set <code class="language-plaintext highlighter-rouge">prevA → list2</code>.</li>
</ul>

<h2 id="key-takeaways">Key Takeaways</h2>

<ul>
  <li><strong>“Splice list into list”</strong> = find the boundary pointers (<code class="language-plaintext highlighter-rouge">prevA</code>, <code class="language-plaintext highlighter-rouge">afterB</code>) + find the tail of the inserted list + three pointer rewirings</li>
  <li>When the head can never be removed, a dummy node is optional but can simplify uniform traversal</li>
  <li>Constraints like <code class="language-plaintext highlighter-rouge">a &gt;= 1</code> and <code class="language-plaintext highlighter-rouge">b &lt; n - 1</code> eliminate edge cases – always read them carefully</li>
</ul>

<h2 id="related-problems">Related Problems</h2>

<ul>
  <li><a href="https://leetcode.com/problems/reverse-linked-list/">206. Reverse Linked List</a> – basic pointer manipulation</li>
  <li><a href="https://leetcode.com/problems/reverse-nodes-in-k-group/">25. Reverse Nodes in k-Group</a> – segment-based list surgery</li>
  <li><a href="https://leetcode.com/problems/partition-list/">86. Partition List</a> – pointer rewiring with dummy nodes</li>
  <li><a href="https://leetcode.com/problems/reorder-list/">143. Reorder List</a> – find middle, reverse, merge</li>
</ul>

<h2 id="template-reference">Template Reference</h2>

<ul>
  <li><a href="/blog_leetcode_java/posts/2025-11-24-leetcode-templates-linked-list/">Linked List</a></li>
</ul>]]></content><author><name></name></author><category term="leetcode" /><category term="medium" /><category term="linked-list" /><category term="leetcode" /><category term="medium" /><category term="linked-list" /><category term="pointer-manipulation" /><summary type="html"><![CDATA[You are given two linked lists: list1 and list2 of sizes n and m respectively. Remove list1’s nodes from the a-th node to the b-th node (0-indexed), and put list2 in their place.]]></summary></entry><entry><title type="html">[Medium] 1353. Maximum Number of Events That Can Be Attended</title><link href="https://robinali34.github.io/blog_leetcode_java/2026/04/13/medium-1353-maximum-number-of-events-that-can-be-attended/" rel="alternate" type="text/html" title="[Medium] 1353. Maximum Number of Events That Can Be Attended" /><published>2026-04-13T00:00:00+00:00</published><updated>2026-04-13T00:00:00+00:00</updated><id>https://robinali34.github.io/blog_leetcode_java/2026/04/13/medium-1353-maximum-number-of-events-that-can-be-attended</id><content type="html" xml:base="https://robinali34.github.io/blog_leetcode_java/2026/04/13/medium-1353-maximum-number-of-events-that-can-be-attended/"><![CDATA[<p>You are given an array of <code class="language-plaintext highlighter-rouge">events</code> where <code class="language-plaintext highlighter-rouge">events[i] = [startDay, endDay]</code>. You can attend an event on <strong>any single day</strong> in the range <code class="language-plaintext highlighter-rouge">[startDay, endDay]</code>. You can only attend <strong>one event per day</strong>. Return the <strong>maximum number of events</strong> you can attend.</p>

<h2 id="examples">Examples</h2>

<p><strong>Example 1:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Input: events = [[1,2],[2,3],[3,4]]
Output: 3
Explanation: Attend all three:
  Day 1 → event [1,2]
  Day 2 → event [2,3]
  Day 3 → event [3,4]
</code></pre></div></div>

<p><strong>Example 2:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Input: events = [[1,2],[2,3],[3,4],[1,2]]
Output: 4
Explanation:
  Day 1 → event [1,2] (first)
  Day 2 → event [1,2] (second)
  Day 2 → can't, already used. Day 3 → event [2,3]
  Day 4 → event [3,4]
</code></pre></div></div>

<h2 id="constraints">Constraints</h2>

<ul>
  <li><code class="language-plaintext highlighter-rouge">1 &lt;= events.length &lt;= 10^5</code></li>
  <li><code class="language-plaintext highlighter-rouge">events[i].length == 2</code></li>
  <li><code class="language-plaintext highlighter-rouge">1 &lt;= startDay &lt;= endDay &lt;= 10^5</code></li>
</ul>

<h2 id="thinking-process">Thinking Process</h2>

<h3 id="key-observations">Key Observations</h3>

<ol>
  <li><strong>Each event is flexible</strong> – you don’t have to attend on the start day; any day in <code class="language-plaintext highlighter-rouge">[start, end]</code> works</li>
  <li><strong>Greedy insight</strong>: on any given day, attend the event that <strong>expires soonest</strong> (smallest end day). Delaying it risks losing it forever, while events with later deadlines are safer to postpone</li>
  <li><strong>Efficient simulation</strong>: move day by day, maintain available events in a min-heap, pick the one expiring soonest</li>
</ol>

<h3 id="algorithm">Algorithm</h3>

<ol>
  <li><strong>Sort</strong> events by start day</li>
  <li>Use a <strong>min-heap</strong> of end days (earliest deadline on top)</li>
  <li>Iterate by day:
    <ul>
      <li>Add all newly available events (start day ≤ current day)</li>
      <li>Remove expired events from the heap (end day &lt; current day)</li>
      <li>Attend the event with the smallest end day (pop from heap)</li>
      <li>Advance to the next day</li>
    </ul>
  </li>
</ol>

<h3 id="walk-through">Walk-through</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>events (sorted): [[1,2], [1,2], [2,3], [3,4]]

Day 1: add [1,2],[1,2] → heap={2,2}
        attend end=2 → heap={2}, rtn=1

Day 2: add [2,3] → heap={2,3}
        attend end=2 → heap={3}, rtn=2

Day 3: add [3,4] → heap={3,4}
        attend end=3 → heap={4}, rtn=3

Day 4: attend end=4 → heap={}, rtn=4

Answer: 4 ✓
</code></pre></div></div>

<h3 id="why-skip-to-the-next-events-start">Why Skip to the Next Event’s Start?</h3>

<p>If the heap is empty and there are more events, we jump <code class="language-plaintext highlighter-rouge">day</code> forward to <code class="language-plaintext highlighter-rouge">events[i][0]</code> instead of incrementing one by one. This avoids iterating through idle days and keeps the algorithm efficient.</p>

<h2 id="solution-sort--greedy-min-heap--on-log-n">Solution: Sort + Greedy Min-Heap – $O(n \log n)$</h2>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// import java.util.Arrays;</span>
<span class="c1">// import java.util.Collections;</span>
<span class="kd">class</span> <span class="nc">Solution</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kt">int</span> <span class="nf">maxEvents</span><span class="o">(</span><span class="kt">int</span><span class="o">[][]&amp;</span> <span class="n">events</span><span class="o">)</span> <span class="o">{</span>
        <span class="nc">Arrays</span><span class="o">.</span><span class="na">sort</span><span class="o">(</span><span class="n">events</span><span class="o">);</span>
        <span class="n">priority_queue</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">,</span> <span class="kt">int</span><span class="o">[],</span> <span class="n">greater</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">pq</span><span class="o">;</span>
        <span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="n">events</span><span class="o">.</span><span class="na">size</span><span class="o">();</span>
        <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">,</span> <span class="n">day</span> <span class="o">=</span> <span class="mi">0</span><span class="o">,</span> <span class="n">rtn</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>

        <span class="k">while</span> <span class="o">(</span><span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span> <span class="o">||</span> <span class="o">!</span><span class="n">pq</span><span class="o">.</span><span class="na">length</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
            <span class="k">if</span> <span class="o">(</span><span class="n">pq</span><span class="o">.</span><span class="na">length</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="n">day</span> <span class="o">=</span> <span class="n">events</span><span class="o">[</span><span class="n">i</span><span class="o">][</span><span class="mi">0</span><span class="o">];</span>
            <span class="k">while</span> <span class="o">(</span><span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span> <span class="o">&amp;&amp;</span> <span class="n">events</span><span class="o">[</span><span class="n">i</span><span class="o">][</span><span class="mi">0</span><span class="o">]</span> <span class="o">&lt;=</span> <span class="n">day</span><span class="o">)</span> <span class="o">{</span>
                <span class="n">pq</span><span class="o">.</span><span class="na">push</span><span class="o">(</span><span class="n">events</span><span class="o">[</span><span class="n">i</span><span class="o">][</span><span class="mi">1</span><span class="o">]);</span>
                <span class="n">i</span><span class="o">++;</span>
            <span class="o">}</span>
            <span class="k">while</span> <span class="o">(!</span><span class="n">pq</span><span class="o">.</span><span class="na">length</span> <span class="o">==</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">pq</span><span class="o">.</span><span class="na">top</span><span class="o">()</span> <span class="o">&lt;</span> <span class="n">day</span><span class="o">)</span> <span class="n">pq</span><span class="o">.</span><span class="na">pop</span><span class="o">();</span>
            <span class="k">if</span> <span class="o">(!</span><span class="n">pq</span><span class="o">.</span><span class="na">length</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
                <span class="n">pq</span><span class="o">.</span><span class="na">pop</span><span class="o">();</span>
                <span class="n">rtn</span><span class="o">++;</span>
                <span class="n">day</span><span class="o">++;</span>
            <span class="o">}</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="n">rtn</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p><strong>Time</strong>: $O(n \log n)$ – sorting + each event enters/leaves the heap once
<strong>Space</strong>: $O(n)$ – heap</p>

<h2 id="key-details">Key Details</h2>

<p><strong>Why min-heap of end days (not start days)?</strong>
We want to prioritize the event that expires soonest. Start days don’t matter once an event is available – only the deadline matters for the greedy choice.</p>

<p><strong>Why <code class="language-plaintext highlighter-rouge">pq.top() &lt; day</code> (not <code class="language-plaintext highlighter-rouge">&lt;=</code>)?</strong>
An event with <code class="language-plaintext highlighter-rouge">end == day</code> is still valid today. We only discard events whose end day is strictly <strong>before</strong> the current day.</p>

<p><strong>Why the <code class="language-plaintext highlighter-rouge">if (pq.empty()) day = events[i][0]</code> jump?</strong>
Without this, we’d increment <code class="language-plaintext highlighter-rouge">day</code> through potentially thousands of idle days. Jumping to the next event’s start keeps the outer loop proportional to $O(n)$ iterations.</p>

<h2 id="common-mistakes">Common Mistakes</h2>

<ul>
  <li>Sorting by end day instead of start day (need start day ordering to add events as days progress)</li>
  <li>Not removing expired events before picking (could “attend” an already-expired event)</li>
  <li>Incrementing <code class="language-plaintext highlighter-rouge">day</code> one by one even when the heap is empty (TLE on large gaps)</li>
</ul>

<h2 id="key-takeaways">Key Takeaways</h2>

<ul>
  <li><strong>“Maximize events attended with earliest-deadline-first”</strong> = sort by start + min-heap of end days</li>
  <li>This is a variant of the <strong>Earliest Deadline First (EDF)</strong> scheduling strategy</li>
  <li>The pattern of “add available → remove expired → pick best” is common in event scheduling problems</li>
</ul>

<h2 id="related-problems">Related Problems</h2>

<ul>
  <li><a href="https://leetcode.com/problems/divide-intervals-into-minimum-number-of-groups/">2406. Divide Intervals Into Minimum Number of Groups</a> – greedy + heap on intervals</li>
  <li><a href="https://leetcode.com/problems/meeting-rooms-ii/">253. Meeting Rooms II</a> – min-heap scheduling</li>
  <li><a href="https://leetcode.com/problems/non-overlapping-intervals/">435. Non-overlapping Intervals</a> – greedy interval scheduling</li>
  <li><a href="https://leetcode.com/problems/maximum-profit-in-job-scheduling/">1235. Maximum Profit in Job Scheduling</a> – DP interval scheduling</li>
</ul>

<h2 id="template-reference">Template Reference</h2>

<ul>
  <li><a href="/blog_leetcode_java/posts/2026-01-05-leetcode-templates-heap/">Heap</a></li>
</ul>]]></content><author><name></name></author><category term="leetcode" /><category term="medium" /><category term="greedy" /><category term="heap" /><category term="leetcode" /><category term="medium" /><category term="greedy" /><category term="heap" /><category term="sorting" /><category term="scheduling" /><summary type="html"><![CDATA[You are given an array of events where events[i] = [startDay, endDay]. You can attend an event on any single day in the range [startDay, endDay]. You can only attend one event per day. Return the maximum number of events you can attend.]]></summary></entry><entry><title type="html">[Medium] 894. All Possible Full Binary Trees</title><link href="https://robinali34.github.io/blog_leetcode_java/2026/04/12/medium-894-all-possible-full-binary-trees/" rel="alternate" type="text/html" title="[Medium] 894. All Possible Full Binary Trees" /><published>2026-04-12T00:00:00+00:00</published><updated>2026-04-12T00:00:00+00:00</updated><id>https://robinali34.github.io/blog_leetcode_java/2026/04/12/medium-894-all-possible-full-binary-trees</id><content type="html" xml:base="https://robinali34.github.io/blog_leetcode_java/2026/04/12/medium-894-all-possible-full-binary-trees/"><![CDATA[<p>Given an integer <code class="language-plaintext highlighter-rouge">n</code>, return a list of all possible <strong>full binary trees</strong> with <code class="language-plaintext highlighter-rouge">n</code> nodes. Each node has value <code class="language-plaintext highlighter-rouge">0</code>. A full binary tree is a tree where every node has either 0 or 2 children.</p>

<h2 id="examples">Examples</h2>

<p><strong>Example 1:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Input: n = 7
Output: [[0,0,0,null,null,0,0,null,null,0,0],
         [0,0,0,null,null,0,0,0,0],
         [0,0,0,0,0,0,0],
         [0,0,0,0,0,null,null,null,null,0,0],
         [0,0,0,0,0,null,null,0,0]]
(5 distinct full binary trees)
</code></pre></div></div>

<p><strong>Example 2:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Input: n = 3
Output: [[0,0,0]]
(Only one: root with two leaves)
</code></pre></div></div>

<h2 id="constraints">Constraints</h2>

<ul>
  <li><code class="language-plaintext highlighter-rouge">1 &lt;= n &lt;= 20</code></li>
</ul>

<h2 id="thinking-process">Thinking Process</h2>

<h3 id="key-observation">Key Observation</h3>

<p>A full binary tree has the property: every internal node has exactly 2 children. This means:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">n</code> must be <strong>odd</strong> (each subtree adds 2 nodes at a time, plus the root)</li>
  <li>If <code class="language-plaintext highlighter-rouge">n</code> is even, no full binary tree exists</li>
</ul>

<h3 id="recursive-structure">Recursive Structure</h3>

<p>A full binary tree with <code class="language-plaintext highlighter-rouge">n</code> nodes has:</p>
<ul>
  <li>1 root node</li>
  <li><code class="language-plaintext highlighter-rouge">i</code> nodes in the left subtree</li>
  <li><code class="language-plaintext highlighter-rouge">n - 1 - i</code> nodes in the right subtree</li>
</ul>

<p>where <code class="language-plaintext highlighter-rouge">i</code> is odd and ranges over <code class="language-plaintext highlighter-rouge">1, 3, 5, ..., n-2</code>.</p>

<p>For each split, recursively generate all left trees and all right trees, then combine every pair.</p>

<h3 id="memoization">Memoization</h3>

<p>The same subproblem <code class="language-plaintext highlighter-rouge">allPossibleFBT(k)</code> may be called multiple times (e.g., both left and right subtrees can have the same size). Caching results avoids redundant computation.</p>

<h3 id="walk-through-n5">Walk-through (n=5)</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>n=5: root + split remaining 4 nodes
  i=1: left=FBT(1)=[leaf], right=FBT(3)=[root+2leaves]
    → 1 tree
  i=3: left=FBT(3)=[root+2leaves], right=FBT(1)=[leaf]
    → 1 tree

Total: 2 full binary trees with 5 nodes
</code></pre></div></div>

<h2 id="solution-recursive--memoization--o2n2">Solution: Recursive + Memoization – $O(2^{n/2})$</h2>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">Solution</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="nc">TreeNode</span><span class="o">[]</span> <span class="nf">allPossibleFBT</span><span class="o">(</span><span class="kt">int</span> <span class="n">n</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">n</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="k">return</span> <span class="o">{}</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">n</span> <span class="o">==</span> <span class="mi">1</span><span class="o">)</span> <span class="k">return</span> <span class="o">{</span><span class="k">new</span> <span class="nc">TreeNode</span><span class="o">(</span><span class="mi">0</span><span class="o">)}</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">memo</span><span class="o">.</span><span class="na">contains</span><span class="o">(</span><span class="n">n</span><span class="o">))</span> <span class="k">return</span> <span class="n">memo</span><span class="o">[</span><span class="n">n</span><span class="o">];</span>

        <span class="nc">TreeNode</span><span class="o">[]</span> <span class="n">rtn</span><span class="o">;</span>
        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">n</span><span class="o">;</span> <span class="n">i</span> <span class="o">+=</span> <span class="mi">2</span><span class="o">)</span> <span class="o">{</span>
            <span class="kt">var</span> <span class="n">leftTree</span> <span class="o">=</span> <span class="n">allPossibleFBT</span><span class="o">(</span><span class="n">i</span><span class="o">);</span>
            <span class="kt">var</span> <span class="n">rightTree</span> <span class="o">=</span> <span class="n">allPossibleFBT</span><span class="o">(</span><span class="n">n</span> <span class="o">-</span> <span class="mi">1</span> <span class="o">-</span> <span class="n">i</span><span class="o">);</span>
            <span class="k">for</span> <span class="o">(</span><span class="n">auto</span> <span class="n">l</span> <span class="o">:</span> <span class="n">leftTree</span><span class="o">)</span> <span class="o">{</span>
                <span class="k">for</span> <span class="o">(</span><span class="n">auto</span> <span class="n">r</span> <span class="o">:</span> <span class="n">rightTree</span><span class="o">)</span> <span class="o">{</span>
                    <span class="nc">TreeNode</span> <span class="n">root</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">TreeNode</span><span class="o">(</span><span class="mi">0</span><span class="o">);</span>
                    <span class="n">root</span><span class="o">.</span><span class="na">left</span> <span class="o">=</span> <span class="n">l</span><span class="o">;</span>
                    <span class="n">root</span><span class="o">.</span><span class="na">right</span> <span class="o">=</span> <span class="n">r</span><span class="o">;</span>
                    <span class="n">rtn</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">root</span><span class="o">);</span>
                <span class="o">}</span>
            <span class="o">}</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="n">memo</span><span class="o">[</span><span class="n">n</span><span class="o">]</span> <span class="o">=</span> <span class="n">rtn</span><span class="o">;</span>
    <span class="o">}</span>
    <span class="n">unordered_map</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">,</span> <span class="nc">TreeNode</span><span class="o">[]&gt;</span> <span class="n">memo</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<p><strong>Time</strong>: $O(2^{n/2})$ – the number of full binary trees grows as Catalan numbers
<strong>Space</strong>: $O(n \cdot 2^{n/2})$ – storing all trees in the memo</p>

<h2 id="key-details">Key Details</h2>

<p><strong>Why <code class="language-plaintext highlighter-rouge">i += 2</code>?</strong> Both subtrees must be full binary trees, so both must have an odd number of nodes. Starting at 1 and stepping by 2 ensures <code class="language-plaintext highlighter-rouge">i</code> and <code class="language-plaintext highlighter-rouge">n - 1 - i</code> are both odd.</p>

<p><strong>Why memoization helps</strong>: <code class="language-plaintext highlighter-rouge">FBT(3)</code> might be needed as a left subtree for <code class="language-plaintext highlighter-rouge">FBT(7)</code> in multiple splits, and also as a right subtree. Caching avoids regenerating the same trees.</p>

<p><strong>Catalan numbers</strong>: The count of full binary trees with $n$ nodes (where $n = 2k+1$) is the $k$-th Catalan number: $C_k = \frac{1}{k+1}\binom{2k}{k}$.</p>

<table>
  <thead>
    <tr>
      <th>n</th>
      <th>Trees</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td>1</td>
    </tr>
    <tr>
      <td>3</td>
      <td>1</td>
    </tr>
    <tr>
      <td>5</td>
      <td>2</td>
    </tr>
    <tr>
      <td>7</td>
      <td>5</td>
    </tr>
    <tr>
      <td>9</td>
      <td>14</td>
    </tr>
    <tr>
      <td>11</td>
      <td>42</td>
    </tr>
  </tbody>
</table>

<h2 id="common-mistakes">Common Mistakes</h2>

<ul>
  <li>Not checking for even <code class="language-plaintext highlighter-rouge">n</code> (no full binary tree exists)</li>
  <li>Stepping <code class="language-plaintext highlighter-rouge">i</code> by 1 instead of 2 (generates invalid subtree sizes)</li>
  <li>Forgetting to create a <strong>new root</strong> for each <code class="language-plaintext highlighter-rouge">(l, r)</code> combination (sharing root nodes across trees corrupts the output)</li>
</ul>

<h2 id="key-takeaways">Key Takeaways</h2>

<ul>
  <li><strong>“Generate all structurally unique trees”</strong> = recursive decomposition by subtree sizes + memoization</li>
  <li>The odd-only constraint and step-by-2 iteration are specific to full binary trees</li>
  <li>Same pattern as LC 95 (Unique BSTs II) – split, recurse, combine all pairs</li>
</ul>

<h2 id="related-problems">Related Problems</h2>

<ul>
  <li><a href="https://leetcode.com/problems/unique-binary-search-trees-ii/">95. Unique Binary Search Trees II</a> – generate all BSTs (similar recursive structure)</li>
  <li><a href="https://leetcode.com/problems/unique-binary-search-trees/">96. Unique Binary Search Trees</a> – count Catalan numbers</li>
  <li><a href="https://leetcode.com/problems/different-ways-to-add-parentheses/">241. Different Ways to Add Parentheses</a> – recursive split + combine pattern</li>
  <li><a href="https://leetcode.com/problems/convert-sorted-array-to-binary-search-tree/">108. Convert Sorted Array to BST</a> – tree construction</li>
</ul>

<h2 id="template-reference">Template Reference</h2>

<ul>
  <li><a href="/blog_leetcode_java/posts/2025-10-29-leetcode-templates-trees/">Trees</a></li>
  <li><a href="/blog_leetcode_java/posts/2025-10-29-leetcode-templates-dp/">DP</a></li>
</ul>]]></content><author><name></name></author><category term="leetcode" /><category term="medium" /><category term="tree" /><category term="recursion" /><category term="memoization" /><category term="leetcode" /><category term="medium" /><category term="tree" /><category term="recursion" /><category term="memoization" /><category term="dp" /><summary type="html"><![CDATA[Given an integer n, return a list of all possible full binary trees with n nodes. Each node has value 0. A full binary tree is a tree where every node has either 0 or 2 children.]]></summary></entry><entry><title type="html">[Medium] 2342. Max Sum of a Pair With Equal Sum of Digits</title><link href="https://robinali34.github.io/blog_leetcode_java/2026/04/11/medium-2342-max-sum-of-a-pair-with-equal-sum-of-digits/" rel="alternate" type="text/html" title="[Medium] 2342. Max Sum of a Pair With Equal Sum of Digits" /><published>2026-04-11T00:00:00+00:00</published><updated>2026-04-11T00:00:00+00:00</updated><id>https://robinali34.github.io/blog_leetcode_java/2026/04/11/medium-2342-max-sum-of-a-pair-with-equal-sum-of-digits</id><content type="html" xml:base="https://robinali34.github.io/blog_leetcode_java/2026/04/11/medium-2342-max-sum-of-a-pair-with-equal-sum-of-digits/"><![CDATA[<p>Given an array <code class="language-plaintext highlighter-rouge">nums</code>, find two indices <code class="language-plaintext highlighter-rouge">i</code> and <code class="language-plaintext highlighter-rouge">j</code> (<code class="language-plaintext highlighter-rouge">i != j</code>) such that the <strong>digit sum</strong> of <code class="language-plaintext highlighter-rouge">nums[i]</code> equals the digit sum of <code class="language-plaintext highlighter-rouge">nums[j]</code>, and return the <strong>maximum</strong> value of <code class="language-plaintext highlighter-rouge">nums[i] + nums[j]</code>. Return <code class="language-plaintext highlighter-rouge">-1</code> if no such pair exists.</p>

<h2 id="examples">Examples</h2>

<p><strong>Example 1:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Input: nums = [18,43,36,13,7]
Output: 54
Explanation:
  digitSum(18) = 9, digitSum(36) = 9
  18 + 36 = 54 is the maximum pair with equal digit sums.
</code></pre></div></div>

<p><strong>Example 2:</strong></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Input: nums = [10,12,19,14]
Output: -1
Explanation: No two numbers share the same digit sum.
</code></pre></div></div>

<h2 id="constraints">Constraints</h2>

<ul>
  <li><code class="language-plaintext highlighter-rouge">1 &lt;= nums.length &lt;= 10^5</code></li>
  <li><code class="language-plaintext highlighter-rouge">1 &lt;= nums[i] &lt;= 10^9</code></li>
</ul>

<h2 id="thinking-process">Thinking Process</h2>

<p>To maximize the sum of a pair with equal digit sums, we want the <strong>two largest</strong> numbers in each digit-sum group.</p>

<h3 id="key-insight">Key Insight</h3>

<p>We don’t need to store all numbers per group – just the <strong>largest so far</strong>. As we scan, for each number:</p>
<ol>
  <li>Compute its digit sum</li>
  <li>If we’ve seen a number with the same digit sum, try pairing with the best one</li>
  <li>Update the best for this digit sum</li>
</ol>

<p>This is the “best seen so far” pattern – same idea as tracking the min price in Best Time to Buy and Sell Stock.</p>

<h3 id="walk-through">Walk-through</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nums = [18, 43, 36, 13, 7]

x=18: digitSum=9,  best[9]=0  → no pair, best[9]=18
x=43: digitSum=7,  best[7]=0  → no pair, best[7]=43
x=36: digitSum=9,  best[9]=18 → pair: 18+36=54, rtn=54, best[9]=36
x=13: digitSum=4,  best[4]=0  → no pair, best[4]=13
x=7:  digitSum=7,  best[7]=43 → pair: 43+7=50, rtn=max(54,50)=54, best[7]=43

Answer: 54 ✓
</code></pre></div></div>

<h3 id="why-best-array-of-size-100">Why <code class="language-plaintext highlighter-rouge">best</code> Array of Size 100?</h3>

<p>Max digit sum occurs for <code class="language-plaintext highlighter-rouge">999,999,999</code> = $9 \times 9 = 81$. An array of size 100 covers all possible digit sums with margin.</p>

<h2 id="solution-greedy-best-seen-so-far--on">Solution: Greedy (Best Seen So Far) – $O(n)$</h2>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">Solution</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kt">int</span> <span class="nf">maximumSum</span><span class="o">(</span><span class="kt">int</span><span class="o">[]</span> <span class="n">nums</span><span class="o">)</span> <span class="o">{</span>
        <span class="kt">int</span><span class="o">[]</span> <span class="n">best</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">int</span><span class="o">[</span><span class="mi">100</span><span class="o">];</span>
        <span class="kt">int</span> <span class="n">rtn</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="o">;</span>
        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">x</span> <span class="o">:</span> <span class="n">nums</span><span class="o">)</span> <span class="o">{</span>
            <span class="kt">int</span> <span class="n">s</span> <span class="o">=</span> <span class="n">digitSum</span><span class="o">(</span><span class="n">x</span><span class="o">);</span>
            <span class="k">if</span> <span class="o">(</span><span class="n">best</span><span class="o">[</span><span class="n">s</span><span class="o">]</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
                <span class="n">rtn</span> <span class="o">=</span> <span class="nc">Math</span><span class="o">.</span><span class="na">max</span><span class="o">(</span><span class="n">rtn</span><span class="o">,</span> <span class="n">best</span><span class="o">[</span><span class="n">s</span><span class="o">]</span> <span class="o">+</span> <span class="n">x</span><span class="o">);</span>
            <span class="o">}</span>
            <span class="n">best</span><span class="o">[</span><span class="n">s</span><span class="o">]</span> <span class="o">=</span> <span class="nc">Math</span><span class="o">.</span><span class="na">max</span><span class="o">(</span><span class="n">best</span><span class="o">[</span><span class="n">s</span><span class="o">],</span> <span class="n">x</span><span class="o">);</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="n">rtn</span><span class="o">;</span>
    <span class="o">}</span>
    <span class="kt">int</span> <span class="nf">digitSum</span><span class="o">(</span><span class="kt">int</span> <span class="n">x</span><span class="o">)</span> <span class="o">{</span>
        <span class="kt">int</span> <span class="n">s</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
        <span class="k">while</span> <span class="o">(</span><span class="n">x</span><span class="o">)</span> <span class="o">{</span>
            <span class="n">s</span> <span class="o">+=</span> <span class="n">x</span> <span class="o">%</span> <span class="mi">10</span><span class="o">;</span>
            <span class="n">x</span> <span class="o">/=</span> <span class="mi">10</span><span class="o">;</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="n">s</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p><strong>Time</strong>: $O(n \cdot d)$ where $d$ = number of digits (at most 10) $\approx O(n)$
<strong>Space</strong>: $O(1)$ – fixed-size array of 100</p>

<h2 id="common-mistakes">Common Mistakes</h2>

<ul>
  <li>Storing all numbers per group and sorting (works but $O(n \log n)$ instead of $O(n)$)</li>
  <li>Forgetting to return <code class="language-plaintext highlighter-rouge">-1</code> when no valid pair exists</li>
  <li>Updating <code class="language-plaintext highlighter-rouge">best[s]</code> before checking the pair (would pair a number with itself)</li>
</ul>

<h2 id="key-takeaways">Key Takeaways</h2>

<ul>
  <li><strong>“Best pair in a group”</strong> = track the best seen so far per group, check pair on each new element</li>
  <li>Using a fixed-size array instead of a hash map leverages the bounded digit-sum range for better constants</li>
  <li>The “update after pairing” order is critical – pair with the old best, then potentially replace it</li>
</ul>

<h2 id="related-problems">Related Problems</h2>

<ul>
  <li><a href="https://leetcode.com/problems/two-sum/">1. Two Sum</a> – pair finding with hash map</li>
  <li><a href="https://leetcode.com/problems/best-time-to-buy-and-sell-stock/">121. Best Time to Buy and Sell Stock</a> – “best seen so far” pattern</li>
  <li><a href="https://leetcode.com/problems/group-anagrams/">49. Group Anagrams</a> – grouping by canonical key</li>
  <li><a href="https://leetcode.com/problems/valid-anagram/">242. Valid Anagram</a> – digit/character frequency</li>
</ul>

<h2 id="template-reference">Template Reference</h2>

<ul>
  <li><a href="/blog_leetcode_java/posts/2025-10-29-leetcode-templates-arrays-strings/">Arrays &amp; Strings</a></li>
</ul>]]></content><author><name></name></author><category term="leetcode" /><category term="medium" /><category term="hash-map" /><category term="array" /><category term="leetcode" /><category term="medium" /><category term="hash-map" /><category term="array" /><category term="greedy" /><summary type="html"><![CDATA[Given an array nums, find two indices i and j (i != j) such that the digit sum of nums[i] equals the digit sum of nums[j], and return the maximum value of nums[i] + nums[j]. Return -1 if no such pair exists.]]></summary></entry></feed>