<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Angela F.</title>
    <description>The latest articles on DEV Community by Angela F. (@afuji).</description>
    <link>https://dev.to/afuji</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3395584%2F28dc3e73-234b-4def-8a22-f9481aaa0ae3.png</url>
      <title>DEV Community: Angela F.</title>
      <link>https://dev.to/afuji</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/afuji"/>
    <language>en</language>
    <item>
      <title>Leetcode 150 | Day 5: Best Time to Buy and Sell Stock - Naive vs. Optimized</title>
      <dc:creator>Angela F.</dc:creator>
      <pubDate>Sun, 21 Jun 2026 23:44:16 +0000</pubDate>
      <link>https://dev.to/afuji/leetcode-150-day-5-best-time-to-buy-and-sell-stock-naive-vs-optimized-4mk1</link>
      <guid>https://dev.to/afuji/leetcode-150-day-5-best-time-to-buy-and-sell-stock-naive-vs-optimized-4mk1</guid>
      <description>&lt;h2&gt;
  
  
  Leetcode 121: Best Time to Buy and Sell Stock
&lt;/h2&gt;

&lt;p&gt;Leetcode 121 asks us to determine the best time to buy and sell stock from an input array &lt;code&gt;prices&lt;/code&gt;, where each index represents a day and the value stored at that index is the cost of stocks on that day. This problem is tagged as Dynamic Programming, but I'd argue it has a greedy element to it. The choice we need to make essentially requires the question, "If I sell today, how much profit have I made, and is that the best I could have done?" We make decisions locally at each iteration of the loop, and this leads to an optimal solution.&lt;/p&gt;

&lt;p&gt;The problem constraints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can choose to buy on any single day, and you must sell on a different day in the future.&lt;/li&gt;
&lt;li&gt;If it is not possible to achieve a maximum profit, you must return 0.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;1 &amp;lt;= prices.length &amp;lt;= 10^5&lt;/code&gt; - the length of our input array is capped at 100,000 indexes&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;0 &amp;lt;= prices[i] &amp;lt;= 10^4&lt;/code&gt; - prices are capped at 10,000&lt;br&gt;
For both approaches we will use the following value:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  - &lt;code&gt;prices = [7, 1, 5, 3, 6, 4]&lt;/code&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Approach 1: Naive (Brute Force)
&lt;/h2&gt;

&lt;p&gt;The naive or brute force approach requires us to check every possible buy/sell combination in order to find the optimal set of days, resulting in an O(n²) time complexity.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * @param {number[]} prices
 * @return {number}
 */&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;maxProfit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;profit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;profit&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;profit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In our example we have 6 days, so roughly 36 checks, not a big deal. However:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1,000 days is approximately 1,000,000 checks&lt;/li&gt;
&lt;li&gt;100,000 days is approximately 10,000,000,000 checks
At that scale, the naive approach becomes impractical and results in this error.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2my3u5j3otkhycy8igpr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2my3u5j3otkhycy8igpr.png" alt="LeetCode submission result showing Time Limit Exceeded, with 203 of 212 test cases passed" width="789" height="100"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The test results reflect this, 203 cases passed, but 9 failed. The failed cases are likely larger inputs where the number of checks becomes too costly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Approach 2: Optimized (For Loop)
&lt;/h2&gt;

&lt;p&gt;Tracing &lt;code&gt;[7, 1, 5, 3, 6, 4]&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;This approach uses two variables, &lt;code&gt;minPrice&lt;/code&gt; and &lt;code&gt;maxProfit&lt;/code&gt;, to track the lowest price seen so far and the best profit found so far, in one pass.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * @param {number[]} prices
 * @return {number}
 */&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;maxProfit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;minPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;Infinity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;maxProfit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;minPrice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;minPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;minPrice&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;maxProfit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;maxProfit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;minPrice&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;maxProfit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let me show you how.&lt;/p&gt;

&lt;p&gt;We begin by initializing &lt;code&gt;minPrice&lt;/code&gt; to &lt;code&gt;Infinity&lt;/code&gt;. Ultimately, we want to find the day where we can purchase the stock for the lowest price, and sell for the highest price. Initializing &lt;code&gt;minPrice&lt;/code&gt; to infinity means whatever value sits in &lt;code&gt;prices[0]&lt;/code&gt; will be stored in &lt;code&gt;minPrice&lt;/code&gt; on the first loop iteration. The second variable, &lt;code&gt;maxProfit&lt;/code&gt;, is initialized to zero, since no transaction has happened yet, so there's no profit to speak of at the start.&lt;/p&gt;

&lt;p&gt;The for loop header is standard. We initialize &lt;code&gt;i&lt;/code&gt; to 0, we continue looping through &lt;code&gt;prices&lt;/code&gt; while &lt;code&gt;i&lt;/code&gt; is less than the length of &lt;code&gt;prices&lt;/code&gt;, and we increment by 1 each time through.&lt;/p&gt;

&lt;p&gt;Once inside the loop, we enter an if/else if condition. The if statement asks if the value at &lt;code&gt;prices[i]&lt;/code&gt; is less than the current &lt;code&gt;minPrice&lt;/code&gt;. If it is, we update &lt;code&gt;minPrice&lt;/code&gt; to that value. If not, we move to the else if clause, which asks a different question:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;prices[i] - minPrice &amp;gt; maxProfit&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This equation is really asking, "if I sold today, would that beat the best profit I've found so far?"&lt;/p&gt;

&lt;p&gt;Profit, if we sold today, is defined as:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;prices[i] - minPrice&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This result has three possible outcomes:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;prices[i] - minPrice &amp;lt; maxProfit&lt;/code&gt; → selling today would still be worse than our current best, so we leave &lt;code&gt;maxProfit&lt;/code&gt; untouched.&lt;br&gt;
&lt;code&gt;prices[i] - minPrice == maxProfit&lt;/code&gt; → selling today ties our current best, so there's nothing to update.&lt;br&gt;
&lt;code&gt;prices[i] - minPrice &amp;gt; maxProfit&lt;/code&gt; → selling today beats everything we've found so far, so this becomes our new best.&lt;/p&gt;

&lt;p&gt;Here's a table showing the value of &lt;code&gt;maxProfit&lt;/code&gt; at each stage of the for loop:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh8fqna5agqu2gro1jtj5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh8fqna5agqu2gro1jtj5.png" alt="Table tracing the optimized algorithm through prices [7, 1, 5, 3, 6, 4], showing minPrice and maxProfit before and after each comparison at every index" width="800" height="344"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Whenever &lt;code&gt;prices[i] - minPrice &amp;gt; maxProfit&lt;/code&gt; is true, we update &lt;code&gt;maxProfit&lt;/code&gt;. Once the loop has gone through every day in the array, we return that final &lt;code&gt;maxProfit&lt;/code&gt; value as the answer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I think we have a clear winner here. While technically both approaches are valid, the naive approach times out in Leetcode, and realistically wouldn't scale well in a real world approach anyways. The optimized approach only needs to go through the array one time which leads to an O(n) time complexity, and since we aren't creating any additional data structures to solve this - space complexity is O(1).&lt;/p&gt;

</description>
      <category>leetcode</category>
      <category>greedy</category>
      <category>algorithms</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Leetcode 150 | Day 4: Majority Element - Naive vs. Optimized</title>
      <dc:creator>Angela F.</dc:creator>
      <pubDate>Wed, 17 Jun 2026 19:49:36 +0000</pubDate>
      <link>https://dev.to/afuji/leetcode-150-day-4-majority-element-naive-vs-optimized-eo6</link>
      <guid>https://dev.to/afuji/leetcode-150-day-4-majority-element-naive-vs-optimized-eo6</guid>
      <description>&lt;p&gt;Leetcode 169 asks us to identify the majority element in a given array. The majority element is defined as the element that appears more than &lt;code&gt;n / 2&lt;/code&gt; times. We are told that we can assume such an element always exists.&lt;/p&gt;

&lt;p&gt;For both approaches we will use the following value:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;nums = [2, 4, 2, 2, 4, 4, 4]&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Approach 1: Naive (Frequency Map)
&lt;/h2&gt;

&lt;p&gt;This approach uses a Map to count the frequency of each element in the array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;majorityElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;counts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our first step is to create the Map which will serve as our frequency map.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;counts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next step will require the use of a for loop. We will loop through the input array &lt;code&gt;nums&lt;/code&gt; and count the number of occurrences of each value, writing that as a key/value pair to our frequency map, &lt;code&gt;counts&lt;/code&gt;. The key will be the element from &lt;code&gt;nums&lt;/code&gt;, and the value will be the frequency of times it appears.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This for loop works by looking at each element in &lt;code&gt;nums&lt;/code&gt; and calling &lt;code&gt;.set()&lt;/code&gt; to store a value. The value that ends up being set depends on what &lt;code&gt;.get()&lt;/code&gt; returns. Here's how &lt;code&gt;.get()&lt;/code&gt; works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We attempt to get the current count for this number from &lt;code&gt;counts&lt;/code&gt;. There are only two possible outcomes - either we have seen this number before, or we haven't:

&lt;ul&gt;
&lt;li&gt;If we have seen it before, &lt;code&gt;.get()&lt;/code&gt; returns its current count and we increment by 1.&lt;/li&gt;
&lt;li&gt;If we haven't seen it before, &lt;code&gt;.get()&lt;/code&gt; returns &lt;code&gt;undefined&lt;/code&gt;. The &lt;code&gt;??&lt;/code&gt; operator (nullish coalescing) catches that and defaults it to 0, then we increment by 1 to initialize the count.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The next step involves another for loop. Because this loop is separate from the first rather than nested inside it, we are still O(n) overall - two sequential O(n) loops add up to O(n), not O(n²).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this for loop we iterate over our frequency map's key/value pairs one by one and compare each frequency to &lt;code&gt;nums.length / 2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Using our example array:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;nums = [2, 4, 2, 2, 4, 4, 4]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;counts&lt;/code&gt; would look like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;counts = [[2, 3], [4, 4]]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We compare the value in the first key/value pair, which is 3, to &lt;code&gt;nums.length / 2&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;3 &amp;gt; (7 / 2) -&amp;gt;&lt;br&gt;
3 &amp;gt; 3.5&lt;/code&gt; = &lt;strong&gt;FALSE&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We then perform the same operation on the next key/value pair:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;4 &amp;gt; 7 / 2 -&amp;gt; &lt;br&gt;
4 &amp;gt; 3.5&lt;/code&gt; = &lt;strong&gt;TRUE&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once we find a value that returns true we know this is our majority element, and we return &lt;code&gt;num&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time complexity: O(n)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Two sequential loops, each O(n). Two separate O(n) loops add up to O(n), not O(n²).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Space complexity: O(n)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Map grows proportionally to the number of unique elements in the array.&lt;/p&gt;


&lt;h2&gt;
  
  
  Approach 2: Optimized (Boyer-Moore Majority Vote Algorithm)
&lt;/h2&gt;

&lt;p&gt;The Boyer-Moore Majority Vote Algorithm, developed by Robert S. Boyer and J Strother Moore in 1981, finds the majority element in a sequence using linear time and constant memory - making it a natural fit for this problem.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;majorityElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;candidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;candidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;candidate&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We begin by initializing a variable &lt;code&gt;candidate&lt;/code&gt; - this is our current best guess for the majority element, and we initialize it to &lt;code&gt;null&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;candidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We initialize a second variable &lt;code&gt;count&lt;/code&gt;. This variable acts as a confidence meter for our current candidate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We initialize a for loop to iterate through each element of the &lt;code&gt;nums&lt;/code&gt; array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The logic that goes inside the for loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;candidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;candidate&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;count&lt;/code&gt; equals 0, we reassign &lt;code&gt;candidate&lt;/code&gt; to the current value of &lt;code&gt;num&lt;/code&gt;. This is because a &lt;code&gt;count&lt;/code&gt; of 0 means we have zero confidence in our current candidate, so we replace it with the number we're looking at right now.&lt;/p&gt;

&lt;p&gt;Then we update our confidence meter. If the current number matches our candidate, &lt;code&gt;count&lt;/code&gt; goes up by 1. If it doesn't match, &lt;code&gt;count&lt;/code&gt; drops by 1. Every time we see our candidate again we grow more confident. Every time we see something different, that confidence takes a hit.&lt;/p&gt;

&lt;p&gt;This took a moment for me to understand. Here is a quick explanation and a table that should help make the concept more concrete.&lt;/p&gt;

&lt;p&gt;Using our example array from earlier:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;nums = [2, 4, 2, 2, 4, 4, 4]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The easiest way to explain how we always end up with the correct answer is to think of the elements - 2 and 4 - as opposing teams. For every element 2, there is an element 4 to cancel it out. Since 4 is our majority element, there are not enough 2s to cancel out all of the 4s.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;2&lt;/th&gt;
&lt;th&gt;4&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MAJORITY ELEMENT&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Since each pair of elements cancels each other out, and we are guaranteed that a majority element exists, it will always be the value that has no pair that will be our majority element.&lt;/p&gt;

&lt;p&gt;Here is a step by step breakdown:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;num&lt;/th&gt;
&lt;th&gt;count === 0?&lt;/th&gt;
&lt;th&gt;candidate&lt;/th&gt;
&lt;th&gt;count&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Return &lt;code&gt;4&lt;/code&gt;. Correct.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time complexity: O(n)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One pass through the array.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Space complexity: O(1)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Just two variables regardless of input size. No additional data structures needed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Both approaches work fine, are pretty straightforward, and have a time complexity of O(n). However, the second approach has a space complexity of O(1). The reason for this is that this approach doesn't need a Map to determine the majority element - it can do everything using just two variables. So while Approach 1 will work fine in most cases, Approach 2 will scale significantly better.&lt;/p&gt;

&lt;p&gt;...&lt;em&gt;&lt;strong&gt;Day 5 coming soon&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>interview</category>
      <category>javascript</category>
      <category>leetcode</category>
    </item>
    <item>
      <title>Leetcode 150 | Day 3: Remove Duplicates From Sorted Array - Naive vs. Optimized</title>
      <dc:creator>Angela F.</dc:creator>
      <pubDate>Wed, 10 Jun 2026 16:56:20 +0000</pubDate>
      <link>https://dev.to/afuji/leetcode-150-day-3-remove-duplicates-from-sorted-array-naive-vs-optimized-2n3c</link>
      <guid>https://dev.to/afuji/leetcode-150-day-3-remove-duplicates-from-sorted-array-naive-vs-optimized-2n3c</guid>
      <description>&lt;h2&gt;
  
  
  Leetcode 80: Remove Duplicates II
&lt;/h2&gt;

&lt;p&gt;Leetcode 80 asks us to modify a sorted array so that each unique element appears at most twice. We are to preserve relative order and store the result in the first part of array &lt;code&gt;nums&lt;/code&gt;. The first &lt;code&gt;k&lt;/code&gt; elements of &lt;code&gt;nums&lt;/code&gt; will hold the result, and beyond &lt;code&gt;k&lt;/code&gt; it does not matter what values may have been left behind. Lastly, this must be accomplished by modifying the input array in-place, without allocating any extra space.&lt;/p&gt;

&lt;p&gt;I chose to do a writeup on this problem because it's the first time I've run into the possibility that there really isn't a feasible naive approach that respects all of the restrictions put in place - namely, the requirement of modifying in-place. I tried using &lt;code&gt;splice()&lt;/code&gt; to shift elements out of the array while tracking position with a single pointer. However, using &lt;code&gt;splice()&lt;/code&gt; and subsequently having to decrement the pointer with &lt;code&gt;i--&lt;/code&gt; doesn't work in the case of three or more consecutive duplicates. It will skip a value for the same reason outlined in Day 2. There was an identical issue I ran into there, and it is explained here &lt;a href="https://dev.to/afuji/leetcode-150-day-2-remove-element-naive-vs-optimized-3557"&gt;Day 2 Remove Element&lt;/a&gt;. It may not be worth the time to continue digging around, but I am curious whether there does exist a naive approach that respects the restrictions completely.&lt;/p&gt;

&lt;p&gt;While it's true the naive approach fails the restrictions laid out in the problem - even if that weren't the case, I'd still argue against it. The time complexity is the same as the optimized approach, but as you'll see below, the difference in readability is significant.&lt;/p&gt;

&lt;p&gt;For both approaches we will use the following array:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;nums = [1, 2, 3, 3, 4, 4, 4]&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Approach 1: Naive (Nested For Loop)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;removeDuplicates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;counts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;timesToAdd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;timesToAdd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach works in two passes. First, it builds a &lt;code&gt;counts&lt;/code&gt; array that tracks how many times each number appears consecutively. Each entry is a pair: &lt;code&gt;[number, count]&lt;/code&gt;. Then it loops over &lt;code&gt;counts&lt;/code&gt;, writes each number back into &lt;code&gt;nums&lt;/code&gt; at most twice using a nested loop, and returns the final index as &lt;code&gt;k&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It gets the job done. But it requires an extra array, and the logic is spread across two separate loops with a nested loop inside the second. Compare that to what follows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time complexity: O(n)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Two passes through the data, but each is O(n). The nested loop runs at most twice per element, so it doesn't change the overall complexity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Space complexity: O(n)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;counts&lt;/code&gt; array grows with the input. This is what disqualifies it - the problem explicitly requires O(1) extra memory.&lt;/p&gt;




&lt;h3&gt;
  
  
  Approach 2: Optimized (Two Pointers)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;removeDuplicates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;slow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;fast&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;fast&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;fast&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;fast&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;slow&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;slow&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;fast&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="nx"&gt;slow&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;slow&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach is comparatively more straightforward, and less code. We start the algorithm by pointing both the &lt;code&gt;slow&lt;/code&gt; and &lt;code&gt;fast&lt;/code&gt; pointer to index 2. Why 2? Because we can make two assumptions here - only one can be true, and both are acceptable per the problem description.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Assumption 1:&lt;/strong&gt; Both index 0 and index 1 hold the same value. This is allowed. Assuming it's true means we can skip those positions and iterate over a smaller portion of the array.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Assumption 2:&lt;/strong&gt; The elements at index 0 and 1 are unique values. Also allowed. Same result - we skip ahead and iterate over less.&lt;/p&gt;

&lt;p&gt;Perhaps it can be argued that the time saved here is nominal. But it can also be said, why not?&lt;/p&gt;

&lt;p&gt;Once we've entered the for loop and hit the if statement, the condition checks whether the value at &lt;code&gt;nums[fast]&lt;/code&gt; is the same as the value two positions behind &lt;code&gt;slow&lt;/code&gt;. If it is, that means we already have two of this value written into the result - adding another would violate the restriction. So we skip it. If it's different, we write &lt;code&gt;nums[fast]&lt;/code&gt; to &lt;code&gt;nums[slow]&lt;/code&gt; and increment &lt;code&gt;slow&lt;/code&gt;. The for loop handles advancing &lt;code&gt;fast&lt;/code&gt; automatically at the start of each iteration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Both &lt;code&gt;slow&lt;/code&gt; and &lt;code&gt;fast&lt;/code&gt; begin at index 2. We check whether &lt;code&gt;nums[fast]&lt;/code&gt; equals &lt;code&gt;nums[slow - 2]&lt;/code&gt;. &lt;code&gt;nums[2]&lt;/code&gt; is 3 and &lt;code&gt;nums[0]&lt;/code&gt; is 1. They are not equal, so we write 3 to &lt;code&gt;nums[slow]&lt;/code&gt; and increment &lt;code&gt;slow&lt;/code&gt; to 3.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fast&lt;/code&gt; advances to index 3. &lt;code&gt;nums[3]&lt;/code&gt; is 3 and &lt;code&gt;nums[slow - 2]&lt;/code&gt; is &lt;code&gt;nums[1]&lt;/code&gt;, which is also 3. They are equal - this would be a third consecutive 3, which violates the restriction. We skip. &lt;code&gt;slow&lt;/code&gt; stays at 3.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fast&lt;/code&gt; advances to index 4. &lt;code&gt;nums[4]&lt;/code&gt; is 4 and &lt;code&gt;nums[slow - 2]&lt;/code&gt; is &lt;code&gt;nums[1]&lt;/code&gt;, which is 2. Not equal - write 4 to &lt;code&gt;nums[slow]&lt;/code&gt;. Increment &lt;code&gt;slow&lt;/code&gt; to 4.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fast&lt;/code&gt; advances to index 5. &lt;code&gt;nums[5]&lt;/code&gt; is 4 and &lt;code&gt;nums[slow - 2]&lt;/code&gt; is &lt;code&gt;nums[2]&lt;/code&gt;, which is 3. Not equal - write 4 to &lt;code&gt;nums[slow]&lt;/code&gt;. Increment &lt;code&gt;slow&lt;/code&gt; to 5.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fast&lt;/code&gt; advances to index 6. &lt;code&gt;nums[6]&lt;/code&gt; is 4 and &lt;code&gt;nums[slow - 2]&lt;/code&gt; is &lt;code&gt;nums[3]&lt;/code&gt;, which is 4. Equal - skip. &lt;code&gt;slow&lt;/code&gt; stays at 5. &lt;code&gt;fast&lt;/code&gt; has reached the end of the array and the loop ends.&lt;/p&gt;

&lt;p&gt;We return &lt;code&gt;slow&lt;/code&gt;, which is 5. The first 5 elements of &lt;code&gt;nums&lt;/code&gt; are &lt;code&gt;[1, 2, 3, 4, 4]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time complexity: O(n)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One pass through the array. No shifting, no extra structures.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Space complexity: O(1)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Everything happens in place. No extra memory allocated.&lt;/p&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Both approaches have a time complexity of O(n). However, only Approach 2 truly meets the requirements of the problem. Space complexity for Approach 1 is O(n), while Approach 2 is O(1).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Approach 1 pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Readable logic. Each step is explicit.&lt;/li&gt;
&lt;li&gt;No pointer math required.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Approach 1 cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O(n) space. Fails the problem's constraints.&lt;/li&gt;
&lt;li&gt;More code. Two loops, one nested.&lt;/li&gt;
&lt;li&gt;Three loops total - two outer, one nested - means more to mentally track when reading the algorithm end to end.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Approach 2 pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O(1) space. Meets all requirements.&lt;/li&gt;
&lt;li&gt;Four lines of logic once you understand the two-pointer pattern.&lt;/li&gt;
&lt;li&gt;Scales cleanly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Approach 2 cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The two-pointer pattern is less intuitive at first glance, especially the &lt;code&gt;slow - 2&lt;/code&gt; check.&lt;/li&gt;
&lt;li&gt;Starting at index 2 requires understanding why the first two elements are skipped.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sometimes we have to sacrifice readability for better time complexity, or for other reasons. This time, I don't think that's the case. We get better readability and better space complexity.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;...Day 4 coming soon&lt;/em&gt;&lt;/p&gt;

</description>
      <category>leetcode</category>
      <category>javascript</category>
      <category>algorithms</category>
    </item>
    <item>
      <title>Leetcode 150 | Day 2: Remove Element - Naive vs. Optimized</title>
      <dc:creator>Angela F.</dc:creator>
      <pubDate>Thu, 04 Jun 2026 00:52:20 +0000</pubDate>
      <link>https://dev.to/afuji/leetcode-150-day-2-remove-element-naive-vs-optimized-3557</link>
      <guid>https://dev.to/afuji/leetcode-150-day-2-remove-element-naive-vs-optimized-3557</guid>
      <description>&lt;h2&gt;
  
  
  Leetcode 27: Remove Element
&lt;/h2&gt;

&lt;p&gt;Leetcode 27 asks us to remove a specific value from an array. The value to be removed is passed in as a parameter to the function along with the array. Just as we did in Day 1, we will cover a naive approach and an optimized approach and discuss the trade-offs between them. I think in the end there's a pretty clear winner. Let's get started.&lt;/p&gt;

&lt;p&gt;For both approaches we will use the following values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;nums = [1, 3, 3, 2, 4]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;val = 3&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Approach 1: Naive (For Loop + Splice)
&lt;/h3&gt;

&lt;p&gt;This approach uses a for loop and leverages &lt;code&gt;.splice()&lt;/code&gt; for removals.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;removeElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We begin by initializing a variable &lt;code&gt;k&lt;/code&gt; to 0. We then enter the for loop. The condition is standard: create a variable &lt;code&gt;i&lt;/code&gt; initialized to 0, continue looping while &lt;code&gt;i&lt;/code&gt; is less than &lt;code&gt;nums.length&lt;/code&gt; to avoid going past the end of the array, and increment by 1 each time through.&lt;/p&gt;

&lt;p&gt;Each iteration checks one condition: whether &lt;code&gt;nums[i]&lt;/code&gt; is equal to &lt;code&gt;val&lt;/code&gt;. If true, we call &lt;code&gt;.splice()&lt;/code&gt; on the array. The arguments we pass to splice are &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;1&lt;/code&gt;. &lt;code&gt;i&lt;/code&gt; is the index at which we want to start removing, and &lt;code&gt;1&lt;/code&gt; tells splice to remove only that one element.&lt;/p&gt;

&lt;p&gt;We then decrement &lt;code&gt;i&lt;/code&gt;. The reason for this took me some time to wrap my brain around, so I have included a visual below to make it concrete.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2r7as3u9vuyuffqdiaai.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2r7as3u9vuyuffqdiaai.png" alt="A three-frame diagram on a dark background illustrating why i-- is necessary after a splice call. Frame 1 shows the array before splice with i pointing at index 1 which holds the value 3. Frame 2 labeled WITHOUT i-- shows the array after splice where the 3 has been removed, every element has shifted left, and i has jumped forward to index 2, skipping the 3 that shifted into index 1. Frame 3 labeled WITH i-- shows the same post-splice array but with i correctly landing on index 1, catching the shifted 3 for evaluation on the next iteration." width="800" height="750"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The core issue is this: when splice removes an element, every element to the right shifts one index to the left. Without &lt;code&gt;i--&lt;/code&gt;, the loop would increment &lt;code&gt;i&lt;/code&gt; on the next iteration and skip right over the element that just shifted in. &lt;code&gt;i--&lt;/code&gt; counteracts that by stepping &lt;code&gt;i&lt;/code&gt; back, so after the loop increments it, &lt;code&gt;i&lt;/code&gt; lands exactly where the shifted element now sits.&lt;/p&gt;

&lt;p&gt;If &lt;code&gt;nums[i] !== val&lt;/code&gt;, we skip the splice and increment &lt;code&gt;k&lt;/code&gt; instead. At the end we return &lt;code&gt;k&lt;/code&gt;, which holds the count of elements remaining after all occurrences of &lt;code&gt;val&lt;/code&gt; have been removed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time complexity: O(n²)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every splice call shifts all elements to the right of the removed index, which is O(n) on its own. If every element in the array equals &lt;code&gt;val&lt;/code&gt;, you are doing that n times. That cost adds up fast.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Space complexity: O(1)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Everything happens in place. No extra memory is allocated.&lt;/p&gt;




&lt;h3&gt;
  
  
  Approach 2: Optimized (Two Pointers)
&lt;/h3&gt;

&lt;p&gt;This approach uses a two-pointer technique to solve the problem. One pointer is the fast pointer &lt;code&gt;i&lt;/code&gt;, which moves forward on every iteration. The other is the slow pointer &lt;code&gt;k&lt;/code&gt;, which only moves forward when a value worth keeping is found.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;removeElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's a legend to aid clarity:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa87kshphf3zeed8mxzej.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa87kshphf3zeed8mxzej.png" alt="A color coded legend for the two pointer walkthrough diagrams. Blue indicates the fast pointer i currently being evaluated. Green with a checkmark indicates a written value already copied to its final position. Red with an X indicates a value equal to val that will be skipped. Dark navy with a question mark indicates an unvisited element. A second blue block labeled k indicates the slow pointer representing the next available slot to write into" width="799" height="414"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's how it works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Both &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;k&lt;/code&gt; begin at index 0. We check whether &lt;code&gt;nums[i] === val&lt;/code&gt;. Since &lt;code&gt;nums[0]&lt;/code&gt; is 1 and 1 !== 3, we write the value at &lt;code&gt;nums[i]&lt;/code&gt; to &lt;code&gt;nums[k]&lt;/code&gt;. We then increment both &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;k&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpwf9ai117mtn8arw5azb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpwf9ai117mtn8arw5azb.png" alt="Array diagram showing Step 1 of the two pointer walkthrough. The array is [1, 3, 3, 2, 4]. Index 0 holds the value 1 and is highlighted in blue, indicating both i and k are pointing here. The remaining cells are dark navy indicating they are unvisited. A label below index 0 shows both i and k. The note reads: nums[0] = 1 is not equal to val. Write 1 to nums[k=0], k increments to 1." width="799" height="233"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Both &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;k&lt;/code&gt; are now at index 1. We ask the same question: is &lt;code&gt;nums[i] === val&lt;/code&gt;? It is. &lt;code&gt;nums[1]&lt;/code&gt; is 3.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz3p10edd6wfztyswa8hd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz3p10edd6wfztyswa8hd.png" alt="Array diagram showing Step 2. Index 0 is green indicating it has been written. Index 1 holds the value 3 and is highlighted in red, indicating it equals val. Both i and k are pointing at index 1. The note reads: nums[1] = 3 equals val. Skip. k stays at 1." width="800" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Since &lt;code&gt;nums[i] === val&lt;/code&gt;, we do not write anything. We increment &lt;code&gt;i&lt;/code&gt; but &lt;code&gt;k&lt;/code&gt; stays put. This is the two-pointer pattern in action. &lt;code&gt;k&lt;/code&gt; is now trailing behind &lt;code&gt;i&lt;/code&gt; by one index position.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;i&lt;/code&gt; is now at index 2. We ask our question again: is &lt;code&gt;nums[i] === val&lt;/code&gt;? It is. Once again &lt;code&gt;k&lt;/code&gt; stays put and &lt;code&gt;i&lt;/code&gt; moves forward to index 3.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdhwidtk6q8wl6aahjzp4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdhwidtk6q8wl6aahjzp4.png" alt="Array diagram showing Step 3. Index 0 is green. Indexes 1 and 2 are both red indicating they equal val. i is pointing at index 2 and k is pointing at index 1, showing k trailing behind i. The note reads: nums[2] = 3 equals val. Skip. k stays at 1." width="799" height="287"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We ask our question again: is &lt;code&gt;nums[i] === val&lt;/code&gt;? No. So we write the value at &lt;code&gt;nums[i]&lt;/code&gt; to &lt;code&gt;nums[k]&lt;/code&gt;, then increment both &lt;code&gt;i&lt;/code&gt; to index 4 and &lt;code&gt;k&lt;/code&gt; to index 2.&lt;/p&gt;

&lt;p&gt;Our array is now &lt;code&gt;nums = [1, 2, 3, 2, 4]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcqf3nne18r9r9dbxhtzt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcqf3nne18r9r9dbxhtzt.png" alt="Array diagram showing Step 4. Index 0 is green. Indexes 1 and 2 are red. Index 3 holds the value 2 and is highlighted in blue indicating i is pointing here. k is still pointing at index 1. The note reads: nums[3] = 2 is not equal to val. Write 2 to nums[k=1], k increments to 2." width="799" height="292"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;i&lt;/code&gt; is at index 4, &lt;code&gt;k&lt;/code&gt; is at index 2. We ask our question one final time: is &lt;code&gt;nums[i] === val&lt;/code&gt;? No. We write the value at &lt;code&gt;nums[i]&lt;/code&gt; to &lt;code&gt;nums[k]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Our array is now &lt;code&gt;nums = [1, 2, 4, 2, 4]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Since the problem asks us to return the count of elements remaining after removing val, we simply return &lt;code&gt;k&lt;/code&gt;. The elements beyond index &lt;code&gt;k&lt;/code&gt; are leftover and ignored. The first &lt;code&gt;k&lt;/code&gt; elements are our answer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdo3or8amzp6sxrdvyuj8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdo3or8amzp6sxrdvyuj8.png" alt="Array diagram showing Step 5. Indexes 0 and 1 are green indicating they have been written with values 1 and 2. Indexes 2 and 3 are red. Index 4 holds the value 4 and is highlighted in blue indicating i is pointing here. k is pointing at index 2. The note reads: nums[4] = 4 is not equal to val. Write 4 to nums[k=2], k increments to 3." width="800" height="238"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the final result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0t087pc9g22v3yaoe28j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0t087pc9g22v3yaoe28j.png" alt="Array diagram showing the final result. The first three cells are green and hold the values 1, 2, and 4, representing the elements that are not equal to val. The last two cells are dark purple with dashed borders labeled ignored, indicating they are beyond index k and not part of the answer. A note reads: first k=3 elements are the answer. Remainder is ignored." width="799" height="262"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time complexity: O(n)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One pass through the array. No shifting, no splice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Space complexity: O(1)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Also in place. No extra memory allocated.&lt;/p&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;There are genuine pros and cons to consider with each approach.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Approach 1 pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More intuitive to read. The logic maps closely to how most people think about removing something.&lt;/li&gt;
&lt;li&gt;The array stays clean. All occurrences of &lt;code&gt;val&lt;/code&gt; are actually removed, not just ignored.&lt;/li&gt;
&lt;li&gt;Shorter code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Approach 1 cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O(n²) time complexity due to repeated shifting from splice.&lt;/li&gt;
&lt;li&gt;Mutates indices mid-loop, which requires &lt;code&gt;i--&lt;/code&gt; and introduces a potential bug if forgotten.&lt;/li&gt;
&lt;li&gt;The cost of &lt;code&gt;.splice()&lt;/code&gt; is hidden, making it easy to underestimate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Approach 2 pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O(n) time. One clean pass, no shifting.&lt;/li&gt;
&lt;li&gt;No index mutation mid-loop, simpler to reason about once the two-pointer pattern clicks.&lt;/li&gt;
&lt;li&gt;Scales well.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Approach 2 cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The array is not truly cleaned up. Elements beyond &lt;code&gt;k&lt;/code&gt; still exist in memory, just ignored.&lt;/li&gt;
&lt;li&gt;The two-pointer pattern is less intuitive at first glance, especially for newer developers.&lt;/li&gt;
&lt;li&gt;Returning &lt;code&gt;k&lt;/code&gt; instead of the modified array can be confusing until you understand what the problem is actually asking for.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both approaches solve the problem. But the time complexity difference is significant, and Approach 2 scales in a way Approach 1 simply does not. For most real-world use cases, Approach 2 is the right call.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;...Day 3 coming soon&lt;/em&gt;&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>beginners</category>
      <category>javascript</category>
      <category>leetcode</category>
    </item>
    <item>
      <title>Leetcode 150 | Day 1: Merge Sorted Array - Naive vs. Optimized</title>
      <dc:creator>Angela F.</dc:creator>
      <pubDate>Tue, 02 Jun 2026 00:51:37 +0000</pubDate>
      <link>https://dev.to/afuji/leetcode-150-day-1-merge-sorted-array-naive-vs-optimized-11pg</link>
      <guid>https://dev.to/afuji/leetcode-150-day-1-merge-sorted-array-naive-vs-optimized-11pg</guid>
      <description>&lt;p&gt;There's been no shortage of debate lately about whether grinding Leetcode still makes sense in the age of AI. I think it does. AI is a powerful tool, but it was built by humans; which means it inherited our strengths, our blind spots, and our biases. Leaning on it entirely without understanding what's happening under the hood is a risk. A mentor once told me: those who refuse to use AI are not hireable. But neither are those who rely on it entirely. Learning deeply is how you stay on the right side of that line.&lt;/p&gt;

&lt;p&gt;This is my journey into just that - learning deeply.&lt;/p&gt;




&lt;h2&gt;
  
  
  Day 1 Leetcode 88: Merge Sorted Array
&lt;/h2&gt;

&lt;p&gt;This is an interesting problem. You begin with 4 pieces of data - 2 arrays and 2 integers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;nums1&lt;/strong&gt;: a sorted array whose length equals &lt;code&gt;nums1.length + nums2.length&lt;/code&gt;. The first &lt;code&gt;m&lt;/code&gt; elements are valid numbers; the remaining indexes hold &lt;code&gt;0&lt;/code&gt;s as placeholders.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;nums2&lt;/strong&gt;: a sorted array containing only valid numbers, with a length of &lt;code&gt;n&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;m&lt;/strong&gt;: the count of valid numbers in nums1.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;n&lt;/strong&gt;: the count of valid numbers in nums2.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Throughout both approaches we will use the following example values: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;nums1 = [1, 2, 3, 0, 0, 0]&lt;/li&gt;
&lt;li&gt;nums2 = [2, 5, 6]&lt;/li&gt;
&lt;li&gt;m = 3&lt;/li&gt;
&lt;li&gt;n = 3&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The objective is to merge both arrays into sorted order &lt;strong&gt;in place&lt;/strong&gt;. Since nums1 is already sized to hold every valid element from both arrays, it's where the final sorted result will live.&lt;/p&gt;




&lt;h3&gt;
  
  
  Approach 1: Naive (Splice + Sort)
&lt;/h3&gt;

&lt;p&gt;This solution is 2 lines of code. That's it. It's a testament to how much ES6 advanced JavaScript.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;nums1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;nums2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;nums1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Here's how it works.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We start by calling &lt;code&gt;.splice()&lt;/code&gt; on nums1. While &lt;code&gt;.splice()&lt;/code&gt; has many use cases, here's what each argument is doing in this context:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;m&lt;/strong&gt;: the index where we start deleting elements. Since &lt;code&gt;m&lt;/code&gt; is the count of valid numbers in nums1, starting at index &lt;code&gt;m&lt;/code&gt; puts us right at the first placeholder &lt;code&gt;0&lt;/code&gt; - exactly where we want to be.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;n&lt;/strong&gt;: the number of elements to delete. Since &lt;code&gt;n&lt;/code&gt; equals the length of nums2, we're deleting exactly as many placeholders as we have values to insert.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;...nums2&lt;/strong&gt;: the values we want to insert in place of the deleted elements. The &lt;code&gt;...&lt;/code&gt; is the spread operator, it unpacks nums2 so its values are inserted individually rather than as a nested array.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To make that concrete, without the spread operator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;nums1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;  &lt;span class="c1"&gt;// not what we want&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the spread operator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;nums1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;// ✓&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now all values live in one array. The last step is sorting. We call &lt;code&gt;.sort()&lt;/code&gt; on nums1 and pass a compare function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;nums1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; are the two elements being compared&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;negative&lt;/strong&gt; result means &lt;code&gt;a&lt;/code&gt; comes before &lt;code&gt;b&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;positive&lt;/strong&gt; result means &lt;code&gt;b&lt;/code&gt; comes before &lt;code&gt;a&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero&lt;/strong&gt; means they're equal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that's Approach 1, 2 lines and Leetcode 88 is solved.&lt;/p&gt;

&lt;p&gt;You might assume that brevity equals optimization. In terms of readability, you'd be right, as this solution is easy to scan and quick to understand. But as with most things, there are trade-offs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time complexity: O((m + n) log(m + n))&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;O(m + n)&lt;/code&gt; comes from iterating through both arrays once during the splice. The &lt;code&gt;log(m + n)&lt;/code&gt; comes from calling &lt;code&gt;.sort()&lt;/code&gt; on the combined array. Sort has to do real work, and that cost adds up as the array grows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Approach 2: Optimized (While Loop)
&lt;/h3&gt;

&lt;p&gt;This approach uses a more classic while loop. Using the same example arrays from above, here's how it works.&lt;/p&gt;

&lt;p&gt;We begin by initializing three pointers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;i&lt;/strong&gt;: set equal to &lt;code&gt;m - 1&lt;/code&gt;. This points to the last valid element in nums1. Since &lt;code&gt;m&lt;/code&gt; is 3 and arrays are zero-based, &lt;code&gt;i&lt;/code&gt; starts at index 2.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;j&lt;/strong&gt;: set equal to &lt;code&gt;n - 1&lt;/code&gt;. This points to the last valid element in nums2. Since &lt;code&gt;n&lt;/code&gt; is 3 and arrays are zero-based, &lt;code&gt;j&lt;/code&gt; starts at index 2.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;k&lt;/strong&gt;: set equal to the last index of nums1. Since nums1 has a length of &lt;code&gt;m + n&lt;/code&gt;, and arrays are zero-based, &lt;code&gt;k&lt;/code&gt; starts at &lt;code&gt;m + n - 1&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nums1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once our pointers are initialized, we enter the while loop.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The while loop condition:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Since we'll be decrementing both &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;j&lt;/code&gt; on each pass, we need to make sure neither pointer has gone past the beginning of its array. So we verify on each iteration that both &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;j&lt;/code&gt; are greater than or equal to zero:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Inside the loop:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We compare &lt;code&gt;nums1[i]&lt;/code&gt; and &lt;code&gt;nums2[j]&lt;/code&gt;. If &lt;code&gt;nums1[i]&lt;/code&gt; is the larger value, we copy it to the index &lt;code&gt;k&lt;/code&gt; is pointing to, then decrement both &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;k&lt;/code&gt;. Otherwise, we copy &lt;code&gt;nums2[j]&lt;/code&gt; to index &lt;code&gt;k&lt;/code&gt; and decrement both &lt;code&gt;j&lt;/code&gt; and &lt;code&gt;k&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;nums2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;nums1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nums1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;nums1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nums2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Handling remaining elements:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's entirely possible that nums2 has more elements than nums1. If that's the case, once &lt;code&gt;i&lt;/code&gt; reaches -1 the while loop exits, and because our condition uses &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;, it doesn't matter that &lt;code&gt;j&lt;/code&gt; hasn't reached zero yet. Any remaining elements in nums2 would be skipped.&lt;/p&gt;

&lt;p&gt;To handle this, we add a second while loop to copy over any remaining nums2 values. Since both arrays started sorted, we can copy them directly in order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;nums1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nums2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because our two while loops are not nested and we never call a sort method, the time complexity improves significantly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time complexity: O(m + n)&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Both approaches solve the problem, but with different trade-offs. Approach 1 is significantly easier to write and follow - two lines and you're done. But that readability comes at a cost in time complexity. Approach 2 is more involved, and more lines of code means more opportunities for bugs. But the time complexity is far better. Understanding those trade-offs is what allows us to make good decisions about which algorithmic approach to reach for.&lt;/p&gt;

&lt;p&gt;...&lt;em&gt;&lt;strong&gt;Day 2 coming soon&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>leetcode</category>
      <category>array</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Stop Your UMAP From Moving: The Pipeline Randomness You're Missing</title>
      <dc:creator>Angela F.</dc:creator>
      <pubDate>Tue, 30 Sep 2025 02:55:11 +0000</pubDate>
      <link>https://dev.to/afuji/stop-your-umap-from-moving-the-pipeline-randomness-youre-missing-gje</link>
      <guid>https://dev.to/afuji/stop-your-umap-from-moving-the-pipeline-randomness-youre-missing-gje</guid>
      <description>&lt;p&gt;During the Spring and Summer of 2025, I was asked to create a web application to show clusters of semantically similar tweets. This was an exciting endeavor aimed at creating a dashboard to visualize how ideas spread in society.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn652ziuuyjktcmx78j60.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn652ziuuyjktcmx78j60.gif" alt="Community Archive Cluster Map" width="560" height="342"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This article is about a specific problem I solved in this project: how to get cluster plots that were consistent from run to run. To achieve this, a deep dive into understanding how randomness is used within UMAP's algorithm became necessary: how it is applied, how it helps with efficiency, its pros, and its cons. This guided me in learning how to control it, and subsequently how to create the consistent render that was asked of me.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Paradox of Randomness in Optimization
&lt;/h2&gt;

&lt;p&gt;It's sometimes interesting to learn that the concepts and strategies you think you understand, you in fact do not. Such was the case with reproducibility. I had to first resolve the fact that to create stability from run to run, I needed to understand how randomness was being used as an optimization tool.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://machinelearningmastery.com/stochastic-optimization-for-machine-learning/" rel="noopener noreferrer"&gt;Machinelearningmastery.com&lt;/a&gt; offered a ton of clarity on this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Using randomness in an optimization algorithm allows the search procedure to perform well on challenging optimization problems that may have a nonlinear response surface. This is achieved by the algorithm taking locally suboptimal steps or moves in the search space that allow it to escape local optima.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  How UMAP Uses Randomness
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feg3e1jiooi59x0pdfmv7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feg3e1jiooi59x0pdfmv7.png" alt="Graph Showing Local/Global Optima" width="800" height="483"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This image gives an excellent visual explanation of the quote above. If the algorithm did not make random choices from time to time, it would find the local minima and naturally believe it had found the most optimal solution. A move along the X-axis in either direction would appear to be a worse choice as the graph would begin to travel back up the Y-axis. However, if we employ randomness, this gives the algorithm permission to make a seemingly 'bad choice' and in doing so creates the potential for finding the global minima – which is the optimal solution in this case.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How this helps us in creating semantic clusters:&lt;/strong&gt; UMAP needs to make random choices when it's learning from your data. It picks random starting spots for your data points, then makes random moves to create better clusters. This is the start of why we get different clusters every time we rerun our code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Controlling the Chaos with random_state
&lt;/h2&gt;

&lt;p&gt;To achieve stability with our renders, we would need to control for this. This is where &lt;code&gt;random_state&lt;/code&gt; comes in. Behind the scenes, randomness isn't really random at all. It is still a calculated value. By using &lt;code&gt;random_state = 42&lt;/code&gt;, as an example, 42 becomes the seed that is plugged into a mathematical formula. A formula that is rerun many times as random number generators need to produce a long sequence of numbers for UMAP to use throughout its process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here is how it works:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;First call:&lt;/strong&gt; plug 42 into the formula, get number A&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Second call:&lt;/strong&gt; plug number A back into the formula, get number B&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Third call:&lt;/strong&gt; plug number B back into the formula, get number C&lt;/li&gt;
&lt;li&gt;And so on…&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Since we are controlling for the very first input, and each subsequent calculation requires that the input be the output of the previous calculation, the sequence of values generated becomes predictable.&lt;/p&gt;

&lt;p&gt;My UMAP reducer looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;reducer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;umap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;UMAP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;n_components&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;random_state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;spread&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;spread&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;min_dist&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;min_dist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;n_neighbors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;n_neighbors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;metric&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;cosine&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;base_coordinates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reducer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit_transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base_embeddings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;reducer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base_coordinates&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base_indices&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Multiple Sources of Randomness
&lt;/h2&gt;

&lt;p&gt;After implementing this solution, I ran the project. Everything clustered as it should have. Then I reran the project, and much to my surprise – the data points moved. The render was not stable. There must be more points of randomness that I wasn't considering.&lt;/p&gt;

&lt;p&gt;I spent a great deal of time scouring the internet to try and find any resource that spoke to the different points within the UMAP pipeline where randomness would occur. I came across an article entitled &lt;a href="https://cran.r-project.org/web/packages/umap/vignettes/umap.html" rel="noopener noreferrer"&gt;"Uniform Manifold Approximation and Projection in R"&lt;/a&gt;. I performed a quick 'CTRL + F' and searched for 'randomness' to assess whether there would be anything useful here quickly. There was certainly something useful. The article states:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As shown in the section on tuning, embedding of a raw dataset can be stabilized by setting a seed for random number generation. However, the results are stable only when the raw data are re-processed in exactly the same way. Results are bound to change if data are presented in a different order.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Root(?) of the Problem
&lt;/h2&gt;

&lt;p&gt;So, what this meant for my code was a situation where my dataset was experiencing both 'change' and 'randomness' in two places:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The first&lt;/strong&gt; was with the sample number of tweets being used at each run. I have it set to a default value of 21K tweets. At each run, it was using a random set of 21K tweets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Additionally&lt;/strong&gt;, I have also implemented a feature where the user can enter in 'test tweets' – this was also changing the data at each run, each time a tweet was added and each time a tweet was deleted.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But if you recall, the article specifically stated: &lt;em&gt;"...the results are stable only when the raw data are re-processed in exactly the same way."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I then added a random seed here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;base_tweets_df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base_tweets_df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;max_tweets&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;random_state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would hopefully ensure that the sample tweets would remain consistent from run to run. After implementing the second random seed, I reran the project. And to my astonishment, the clusters no longer moved from run to run. I could now change the sample data size and rerun the project, and I would get a consistent and static render of clusters from run to run.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Final Challenge: Dynamic User Input
&lt;/h2&gt;

&lt;p&gt;The next test would be to see if my success held when adding and removing test tweets via the UI. Unfortunately, my previous success would be short-lived. Again, I would encounter data points that would move each time a tweet was added or removed.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"...the results are stable only when the raw data are re-processed in exactly the same way."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That phrase again. It was clear that every time a user inputted a test tweet or deleted a test tweet, the raw data was not being re-processed in the exact same way. UMAP was recalculating everything from scratch as it thought it had a new dataset to work with.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Storage Room Analogy: A Mental Model for the Solution
&lt;/h2&gt;

&lt;p&gt;So, the solution for this went like this. Let's say you were storing all of your holiday decorations in a storage room. And you have decided that Christmas decorations would always go in the upper right corner of the shelves. And Halloween decorations always went in the lower left corner, and Thanksgiving in the middle, so on and so forth. If this layout never changes, then when new boxes of Christmas decorations are added, instinctually they will go in the upper right corner. And that new glow-in-the-dark skeleton you got for this Halloween will naturally go in the lower left corner. These rules never change; therefore, when adding new decorations, they will always go in the same cluster of related boxes in the same location, and when you remove them, you will always be able to predictably find them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsqes0mv0e9u1atjvo4ma.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsqes0mv0e9u1atjvo4ma.png" alt="Image Depicting a Storage Room with Boxes" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this image, you can see that each holiday has a designated spot for its decorations. With these spots enforced, any new boxes of Christmas decorations will naturally go in the upper right-hand corner, and Thanksgiving decorations added will naturally go in the middle. This is possible because the rules have been cached and are applied to each new box of decorations as they are added.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This was the basis for the fix.&lt;/strong&gt; In the context of the code, the idea is identical. I would train UMAP on the exact same dataset from the embeddings file. The random seed ensured that the same dataset would be used from run to run, and the reducer would be cached so that UMAP's existing trained model could use &lt;code&gt;.transform()&lt;/code&gt; for new tweets. So, the base dataset would always cluster the same, and as new test tweets came in and had the same reducer applied, they would always cluster in the same location as well – exactly in the same way that Thanksgiving decorations would always end up in the middle of the shelves.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This project has taught me quite a bit. For starters, there is nuance in machine learning that is important to consider. The primary example being that without the feature that allows the user to enter test tweets and remove them – the two random seeds likely would have solved my entire reproducibility issue alone.&lt;/p&gt;

&lt;p&gt;I think at times it's also easy to default to 'Does this solution fix my problem?' If yes, great! – and we move on. Without diving into how stochastic algorithms work, and more importantly 'why' they have the randomness characteristic – solving this without this knowledge would have been so much more painful and time-consuming.&lt;/p&gt;

&lt;p&gt;In the end, what started as a frustrating bug became an important learning moment. Sometimes, the most annoying of bugs end up teaching us the most.&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>datascience</category>
      <category>machinelearning</category>
    </item>
  </channel>
</rss>
