<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Abiramisri J]]></title><description><![CDATA[Abiramisri J]]></description><link>https://abi-blog.hashnode.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1593680282896/kNC7E8IR4.png</url><title>Abiramisri J</title><link>https://abi-blog.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Sat, 12 Sep 2026 06:42:43 GMT</lastBuildDate><atom:link href="https://abi-blog.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Day 9 of My 30-Day DSA Journey - Binary Search Patterns]]></title><description><![CDATA[Day 9 of my DSA journey with JavaScript focuses on Binary Search.
Binary Search is one of the most important searching techniques for sorted data. Instead of checking every element one by one, it repe]]></description><link>https://abi-blog.hashnode.dev/day-9-of-my-30-day-dsa-journey-binary-search-patterns</link><guid isPermaLink="true">https://abi-blog.hashnode.dev/day-9-of-my-30-day-dsa-journey-binary-search-patterns</guid><category><![CDATA[DSA]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[leetcode]]></category><category><![CDATA[binary search]]></category><category><![CDATA[algorithms]]></category><category><![CDATA[data structures]]></category><category><![CDATA[Problem Solving]]></category><category><![CDATA[coding interview]]></category><category><![CDATA[DSA Patterns]]></category><category><![CDATA[JavaScript DSA]]></category><dc:creator><![CDATA[Abirami Sri]]></dc:creator><pubDate>Fri, 11 Sep 2026 17:34:43 GMT</pubDate><content:encoded><![CDATA[<p>Day 9 of my DSA journey with JavaScript focuses on <strong>Binary Search</strong>.</p>
<p>Binary Search is one of the most important searching techniques for sorted data. Instead of checking every element one by one, it repeatedly divides the search space into half.</p>
<p>Today, I solved 5 LeetCode problems:</p>
<ol>
<li><p>Binary Search</p>
</li>
<li><p>Search Insert Position</p>
</li>
<li><p>Find First and Last Position of Element in Sorted Array</p>
</li>
<li><p>Search in Rotated Sorted Array</p>
</li>
<li><p>First Bad Version</p>
</li>
</ol>
<p>These problems helped me understand that Binary Search is not only about finding an exact value. The same idea can also be used to find <strong>positions, boundaries, and the first/last occurrence</strong> of something.</p>
<hr />
<h2>Problems Solved</h2>
<table>
<thead>
<tr>
<th>#</th>
<th>Problem</th>
<th>Pattern</th>
<th>Difficulty</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>Binary Search</td>
<td>Binary Search</td>
<td>Easy</td>
</tr>
<tr>
<td>2</td>
<td>Search Insert Position</td>
<td>Binary Search</td>
<td>Easy</td>
</tr>
<tr>
<td>3</td>
<td>Find First and Last Position of Element in Sorted Array</td>
<td>Boundary Binary Search</td>
<td>Medium</td>
</tr>
<tr>
<td>4</td>
<td>Search in Rotated Sorted Array</td>
<td>Modified Binary Search</td>
<td>Medium</td>
</tr>
<tr>
<td>5</td>
<td>First Bad Version</td>
<td>Binary Search</td>
<td>Easy</td>
</tr>
</tbody></table>
<hr />
<h1>What is Binary Search?</h1>
<p>Binary Search works on a <strong>sorted search space</strong>.</p>
<p>Instead of checking every element:</p>
<pre><code class="language-text">1 → 2 → 3 → 4 → 5 → ...
</code></pre>
<p>we check the middle.</p>
<p>If the target is smaller than the middle:</p>
<pre><code class="language-text">Search left half
</code></pre>
<p>If the target is larger:</p>
<pre><code class="language-text">Search right half
</code></pre>
<p>So every step removes approximately half of the remaining search space.</p>
<h3>Example</h3>
<pre><code class="language-text">nums = [1,3,5,7,9,11,13]
target = 11
</code></pre>
<p>Start:</p>
<pre><code class="language-text">left = 0
right = 6
mid = 3
</code></pre>
<pre><code class="language-text">nums[mid] = 7
</code></pre>
<p>Since:</p>
<pre><code class="language-text">11 &gt; 7
</code></pre>
<p>we ignore the left half.</p>
<p>Now:</p>
<pre><code class="language-text">left = 4
right = 6
</code></pre>
<p>Continue until the target is found.</p>
<hr />
<h1>1. Binary Search</h1>
<p><strong>LeetCode:</strong> 704</p>
<p><a href="https://leetcode.com/problems/binary-search/?utm_source=chatgpt.com">Solve Binary Search on LeetCode</a></p>
<h2>Problem</h2>
<p>Given a sorted array of integers and a target value, return the index of the target.</p>
<p>If the target does not exist, return <code>-1</code>.</p>
<h2>Example</h2>
<pre><code class="language-text">Input:
nums = [-1,0,3,5,9,12]
target = 9

Output:
4
</code></pre>
<h2>Approach</h2>
<p>Maintain two pointers:</p>
<pre><code class="language-text">left
right
</code></pre>
<p>Find the middle:</p>
<pre><code class="language-javascript">let middleIndex = Math.floor((leftIndex + rightIndex) / 2);
</code></pre>
<p>Then compare the target with the middle element.</p>
<h3>If target is found</h3>
<p>Return the middle index.</p>
<h3>If target is smaller</h3>
<p>Search the left half:</p>
<pre><code class="language-javascript">right = mid - 1;
</code></pre>
<h3>If target is larger</h3>
<p>Search the right half:</p>
<pre><code class="language-javascript">left = mid + 1;
</code></pre>
<h2>Code</h2>
<pre><code class="language-javascript">var search = function(nums, target) {
    let leftIndex = 0;
    let rightIndex = nums.length - 1;

    while (leftIndex &lt;= rightIndex) {
        let middleIndex =
            Math.floor((leftIndex + rightIndex) / 2);

        if (target === nums[middleIndex]) {
            return middleIndex;
        }

        if (target &lt; nums[middleIndex]) {
            rightIndex = middleIndex - 1;
        } else {
            leftIndex = middleIndex + 1;
        }
    }

    return -1;
};
</code></pre>
<h2>How It Works</h2>
<p>For:</p>
<pre><code class="language-text">[-1,0,3,5,9,12]
</code></pre>
<p>Target:</p>
<pre><code class="language-text">9
</code></pre>
<p>First:</p>
<pre><code class="language-text">mid = 2
nums[mid] = 3
</code></pre>
<p>Since:</p>
<pre><code class="language-text">9 &gt; 3
</code></pre>
<p>move right.</p>
<p>Then:</p>
<pre><code class="language-text">mid = 4
nums[mid] = 9
</code></pre>
<p>Target found.</p>
<p>Return:</p>
<pre><code class="language-text">4
</code></pre>
<h2>Complexity</h2>
<pre><code class="language-text">Time:  O(log n)
Space: O(1)
</code></pre>
<hr />
<h1>2. Search Insert Position</h1>
<p><strong>LeetCode:</strong> 35</p>
<p><a href="https://leetcode.com/problems/search-insert-position/?utm_source=chatgpt.com">Solve Search Insert Position on LeetCode</a></p>
<h2>Problem</h2>
<p>Given a sorted array and a target, return the index if the target exists.</p>
<p>If it doesn't exist, return the position where it should be inserted.</p>
<h2>Example</h2>
<pre><code class="language-text">Input:
nums = [1,3,5,6]
target = 2

Output:
1
</code></pre>
<p>Because <code>2</code> should be inserted between:</p>
<pre><code class="language-text">1 and 3
</code></pre>
<h2>Approach</h2>
<p>This looks similar to normal Binary Search.</p>
<p>The important difference is what happens when the target is <strong>not found</strong>.</p>
<p>When the loop finishes, <code>left</code> represents the correct insertion position.</p>
<h2>Code</h2>
<pre><code class="language-javascript">var searchInsert = function(nums, target) {
    let left = 0;
    let right = nums.length - 1;

    while (right &gt;= left) {
        let mid = Math.floor((left + right) / 2);

        if (target === nums[mid]) {
            return mid;
        } else if (target &lt; nums[mid]) {
            right = mid - 1;
        } else {
            left = mid + 1;
        }
    }

    return left;
};
</code></pre>
<h2>How It Works</h2>
<p>Example:</p>
<pre><code class="language-text">nums = [1,3,5,6]
target = 2
</code></pre>
<p>Eventually the search space becomes empty.</p>
<p>At that point:</p>
<pre><code class="language-text">left = 1
</code></pre>
<p>Index <code>1</code> is exactly where <code>2</code> should be inserted.</p>
<p>Therefore:</p>
<pre><code class="language-text">[1,2,3,5,6]
   ↑
 index 1
</code></pre>
<h2>Key Idea</h2>
<p>In this problem:</p>
<pre><code class="language-text">left
</code></pre>
<p>is not just a search pointer.</p>
<p>After the search finishes, it represents the <strong>first valid position where the target can be placed</strong>.</p>
<h2>Complexity</h2>
<pre><code class="language-text">Time:  O(log n)
Space: O(1)
</code></pre>
<hr />
<h1>3. Find First and Last Position of Element in Sorted Array</h1>
<p><strong>LeetCode:</strong> 34</p>
<p><a href="https://leetcode.com/problems/find-first-and-last-position-of-element-in-sorted-array/?utm_source=chatgpt.com">Solve Find First and Last Position of Element in Sorted Array on LeetCode</a></p>
<h2>Problem</h2>
<p>Given a sorted array that may contain duplicate values, find the first and last position of a target.</p>
<h2>Example</h2>
<pre><code class="language-text">Input:
nums = [5,7,7,8,8,10]
target = 8

Output:
[3,4]
</code></pre>
<p>The first <code>8</code> is at index <code>3</code>.</p>
<p>The last <code>8</code> is at index <code>4</code>.</p>
<h2>Approach</h2>
<p>A normal Binary Search can find <strong>an occurrence</strong> of the target.</p>
<p>But here we need:</p>
<pre><code class="language-text">First occurrence
+
Last occurrence
</code></pre>
<p>So we perform Binary Search twice.</p>
<h3>First Search</h3>
<p>Find the <strong>leftmost</strong> occurrence.</p>
<p>When:</p>
<pre><code class="language-text">nums[mid] &gt;= target
</code></pre>
<p>we continue searching toward the left.</p>
<h3>Second Search</h3>
<p>Find the <strong>rightmost</strong> occurrence.</p>
<p>When:</p>
<pre><code class="language-text">nums[mid] &lt;= target
</code></pre>
<p>we continue searching toward the right.</p>
<h2>Code</h2>
<pre><code class="language-javascript">var searchRange = function(nums, target) {
    let l = 0;
    let r = nums.length - 1;
    let ans = [-1, -1];

    // Find first occurrence
    while (l &lt; r) {
        let m = l + Math.floor((r - l) / 2);

        if (nums[m] &lt; target) {
            l = m + 1;
        } else {
            r = m;
        }
    }

    if (nums[l] === target) {
        ans[0] = l;
    }

    // Find last occurrence
    l = 0;
    r = nums.length - 1;

    while (l &lt; r) {
        let m = l + Math.ceil((r - l) / 2);

        if (nums[m] &gt; target) {
            r = m - 1;
        } else {
            l = m;
        }
    }

    if (nums[l] === target) {
        ans[1] = l;
    }

    return ans;
};
</code></pre>
<h2>Why Are <code>floor</code> and <code>ceil</code> Different?</h2>
<p>For the first search, we want to move toward the left boundary, so we use:</p>
<pre><code class="language-javascript">Math.floor((r - l) / 2)
</code></pre>
<p>For the second search, we want to move toward the right boundary, so we use:</p>
<pre><code class="language-javascript">Math.ceil((r - l) / 2)
</code></pre>
<p>This helps prevent the pointers from getting stuck when only two elements remain.</p>
<h2>How It Works</h2>
<p>For:</p>
<pre><code class="language-text">[5,7,7,8,8,10]
</code></pre>
<p>and:</p>
<pre><code class="language-text">target = 8
</code></pre>
<p>First Binary Search finds:</p>
<pre><code class="language-text">3
</code></pre>
<p>Second Binary Search finds:</p>
<pre><code class="language-text">4
</code></pre>
<p>Therefore:</p>
<pre><code class="language-text">[3,4]
</code></pre>
<h2>Complexity</h2>
<p>We perform Binary Search twice:</p>
<pre><code class="language-text">Time:  O(log n)
Space: O(1)
</code></pre>
<hr />
<h1>4. Search in Rotated Sorted Array</h1>
<p><strong>LeetCode:</strong> 33</p>
<p><a href="https://leetcode.com/problems/search-in-rotated-sorted-array/?utm_source=chatgpt.com">Solve Search in Rotated Sorted Array on LeetCode</a></p>
<h2>Problem</h2>
<p>A sorted array has been rotated at an unknown position.</p>
<p>Find the index of the target.</p>
<h2>Example</h2>
<pre><code class="language-text">Input:
nums = [4,5,6,7,0,1,2]
target = 0

Output:
4
</code></pre>
<p>The original sorted array was:</p>
<pre><code class="language-text">[0,1,2,4,5,6,7]
</code></pre>
<p>After rotation:</p>
<pre><code class="language-text">[4,5,6,7,0,1,2]
</code></pre>
<h2>Challenge</h2>
<p>The entire array is no longer sorted.</p>
<p>However, at every Binary Search step, <strong>at least one half is still sorted</strong>.</p>
<p>That is the key observation.</p>
<h2>Approach</h2>
<p>Calculate the middle.</p>
<p>Then check:</p>
<pre><code class="language-javascript">if (nums[left] &lt;= nums[mid])
</code></pre>
<p>This means the <strong>left half is sorted</strong>.</p>
<p>Otherwise:</p>
<pre><code class="language-text">right half is sorted
</code></pre>
<p>Then check whether the target belongs inside the sorted half.</p>
<p>If it does, search there.</p>
<p>Otherwise, search the other half.</p>
<h2>Code</h2>
<pre><code class="language-javascript">var search = function(nums, target) {
    let l = 0;
    let r = nums.length - 1;

    while (l &lt;= r) {
        let m = l + Math.floor((r - l) / 2);

        if (target === nums[m]) {
            return m;
        }

        // Left half is sorted
        if (nums[l] &lt;= nums[m]) {
            if (target &lt; nums[m] &amp;&amp; target &gt;= nums[l]) {
                r = m - 1;
            } else {
                l = m + 1;
            }
        }

        // Right half is sorted
        else {
            if (target &gt; nums[m] &amp;&amp; target &lt;= nums[r]) {
                l = m + 1;
            } else {
                r = m - 1;
            }
        }
    }

    return -1;
};
</code></pre>
<h2>How It Works</h2>
<p>Consider:</p>
<pre><code class="language-text">[4,5,6,7,0,1,2]
</code></pre>
<p>Suppose:</p>
<pre><code class="language-text">mid = 3
nums[mid] = 7
</code></pre>
<p>The left half:</p>
<pre><code class="language-text">[4,5,6,7]
</code></pre>
<p>is sorted.</p>
<p>If the target is inside this range, search left.</p>
<p>Otherwise:</p>
<pre><code class="language-text">search right
</code></pre>
<p>At every step, we eliminate approximately half of the remaining search space.</p>
<h2>Complexity</h2>
<pre><code class="language-text">Time:  O(log n)
Space: O(1)
</code></pre>
<h2>Pattern</h2>
<p><strong>Modified Binary Search</strong></p>
<p>The key pattern is:</p>
<pre><code class="language-text">Find which half is sorted
        ↓
Check whether target belongs there
        ↓
Choose the correct half
</code></pre>
<hr />
<h1>5. First Bad Version</h1>
<p><strong>LeetCode:</strong> 278</p>
<p><a href="https://leetcode.com/problems/first-bad-version/?utm_source=chatgpt.com">Solve First Bad Version on LeetCode</a></p>
<h2>Problem</h2>
<p>There are versions:</p>
<pre><code class="language-text">1, 2, 3, 4, 5, ...
</code></pre>
<p>At some point, a version becomes bad.</p>
<p>Once a version is bad, all versions after it are also bad.</p>
<p>Find the <strong>first bad version</strong>.</p>
<h2>Example</h2>
<pre><code class="language-text">n = 5
first bad version = 4
</code></pre>
<p>The versions look like:</p>
<pre><code class="language-text">1  2  3  4  5
G  G  G  B  B
</code></pre>
<p>We need to find the first <code>B</code>.</p>
<h2>Approach</h2>
<p>This is another Binary Search problem.</p>
<p>But instead of searching for an exact value, we are searching for a <strong>boundary</strong>.</p>
<p>The pattern is:</p>
<pre><code class="language-text">Good Good Good Bad Bad Bad
                  ↑
            first bad version
</code></pre>
<p>If the middle version is good:</p>
<pre><code class="language-javascript">!isBadVersion(mid)
</code></pre>
<p>the first bad version must be after it.</p>
<p>So:</p>
<pre><code class="language-javascript">left = mid + 1;
</code></pre>
<p>If the middle version is bad:</p>
<pre><code class="language-javascript">isBadVersion(mid)
</code></pre>
<p>it could be the first bad version, so we keep it in the search space:</p>
<pre><code class="language-javascript">right = mid;
</code></pre>
<h2>Code</h2>
<pre><code class="language-javascript">var solution = function(isBadVersion) {
    /**
     * @param {integer} n Total versions
     * @return {integer} The first bad version
     */

    return function(n) {
        let l = 1;
        let r = n;

        while (l &lt; r) {
            let m = l + Math.floor((r - l) / 2);

            if (!isBadVersion(m)) {
                l = m + 1;
            } else {
                r = m;
            }
        }

        return r;
    };
};
</code></pre>
<h2>How It Works</h2>
<p>Suppose:</p>
<pre><code class="language-text">n = 5
</code></pre>
<p>and:</p>
<pre><code class="language-text">1  2  3  4  5
G  G  G  B  B
</code></pre>
<p>Binary Search checks the middle version.</p>
<p>If it finds:</p>
<pre><code class="language-text">Good
</code></pre>
<p>we know the answer must be to the right.</p>
<p>If it finds:</p>
<pre><code class="language-text">Bad
</code></pre>
<p>we know the answer is at the middle or somewhere to the left.</p>
<p>Eventually:</p>
<pre><code class="language-text">left === right
</code></pre>
<p>That position is the first bad version.</p>
<h2>Complexity</h2>
<pre><code class="language-text">Time:  O(log n)
Space: O(1)
</code></pre>
<hr />
<h1>Binary Search Patterns I Learned</h1>
<p>Today's problems show that Binary Search has several variations.</p>
<h3>1. Exact Search</h3>
<p>Example:</p>
<pre><code class="language-text">Binary Search
</code></pre>
<p>Find:</p>
<pre><code class="language-text">target
</code></pre>
<h3>2. Insertion Position</h3>
<p>Example:</p>
<pre><code class="language-text">Search Insert Position
</code></pre>
<p>Find:</p>
<pre><code class="language-text">where target should be placed
</code></pre>
<h3>3. Boundary Search</h3>
<p>Example:</p>
<pre><code class="language-text">Find First and Last Position
First Bad Version
</code></pre>
<p>Find:</p>
<pre><code class="language-text">first occurrence
last occurrence
first bad position
</code></pre>
<h3>4. Modified Binary Search</h3>
<p>Example:</p>
<pre><code class="language-text">Search in Rotated Sorted Array
</code></pre>
<p>Find which half remains sorted and continue searching there.</p>
<hr />
<h1>Binary Search Pattern Recognition</h1>
<p>When looking at a new problem, I can ask:</p>
<h3>Question 1</h3>
<p>Is the data sorted?</p>
<pre><code class="language-text">Yes → Binary Search may be possible
</code></pre>
<h3>Question 2</h3>
<p>Can I eliminate half of the search space after each comparison?</p>
<pre><code class="language-text">Yes → Binary Search is a strong candidate
</code></pre>
<h3>Question 3</h3>
<p>Am I looking for a boundary?</p>
<p>For example:</p>
<pre><code class="language-text">First
Last
Minimum valid
Maximum valid
First bad
Insertion position
</code></pre>
<p>Then I should think about <strong>Boundary Binary Search</strong>.</p>
<h3>Question 4</h3>
<p>Is the array rotated but still has a sorted half?</p>
<p>Then think about:</p>
<pre><code class="language-text">Modified Binary Search
</code></pre>
<hr />
<h1>Time Complexity Comparison</h1>
<p>One reason Binary Search is powerful is the difference in time complexity.</p>
<p>For a large array:</p>
<pre><code class="language-text">Linear Search
O(n)
</code></pre>
<p>Binary Search:</p>
<pre><code class="language-text">O(log n)
</code></pre>
<p>For example, with around one million elements, Binary Search needs only around 20 halving steps to narrow the search to a single position.</p>
<p>The important idea is not simply "Binary Search is faster."</p>
<p>It is:</p>
<blockquote>
<p><strong>Each step removes about half of the remaining possibilities.</strong></p>
</blockquote>
<hr />
<h1>What I Learned Today</h1>
<p>Today I learned that Binary Search is more than:</p>
<pre><code class="language-text">Find target in sorted array
</code></pre>
<p>It can also be used to find:</p>
<ul>
<li><p>An exact value</p>
</li>
<li><p>An insertion position</p>
</li>
<li><p>First occurrence</p>
</li>
<li><p>Last occurrence</p>
</li>
<li><p>A boundary</p>
</li>
<li><p>First bad version</p>
</li>
<li><p>A target in a rotated sorted array</p>
</li>
</ul>
<p>The most important concept for me is learning to identify the <strong>search space</strong> and understand how each condition can reduce that search space.</p>
<hr />
<h1>Day 9 Summary</h1>
<p>Today I solved:</p>
<pre><code class="language-text">704 → Binary Search
35  → Search Insert Position
34  → Find First and Last Position
33  → Search in Rotated Sorted Array
278 → First Bad Version
</code></pre>
<p>Main patterns:</p>
<pre><code class="language-text">Binary Search
      ↓
Boundary Search
      ↓
Modified Binary Search
</code></pre>
<hr />
<h1>Key Takeaway</h1>
<blockquote>
<p><strong>Binary Search is not just about finding a target. It is a general technique for repeatedly cutting a sorted or monotonic search space in half.</strong></p>
</blockquote>
<p>Day 9 complete.</p>
]]></content:encoded></item><item><title><![CDATA[Day 8 of My 30-Day DSA Journey - Sliding Window Pattern]]></title><description><![CDATA[Today, I continued learning one of the most important DSA patterns for string and array problems: Sliding Window.
Sliding Window is useful when a problem asks us to find something inside a continuous ]]></description><link>https://abi-blog.hashnode.dev/day-8-of-my-30-day-dsa-journey-sliding-window-pattern</link><guid isPermaLink="true">https://abi-blog.hashnode.dev/day-8-of-my-30-day-dsa-journey-sliding-window-pattern</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[DSA]]></category><category><![CDATA[leetcode]]></category><category><![CDATA[sliding window]]></category><category><![CDATA[algorithms]]></category><category><![CDATA[coding interview]]></category><category><![CDATA[data structures]]></category><category><![CDATA[Frontend Developer ]]></category><dc:creator><![CDATA[Abirami Sri]]></dc:creator><pubDate>Thu, 10 Sep 2026 11:32:26 GMT</pubDate><content:encoded><![CDATA[<p>Today, I continued learning one of the most important DSA patterns for string and array problems: <strong>Sliding Window</strong>.</p>
<p>Sliding Window is useful when a problem asks us to find something inside a <strong>continuous part of an array or string</strong>, such as:</p>
<ul>
<li><p>Longest substring</p>
</li>
<li><p>Shortest substring</p>
</li>
<li><p>Fixed-size substring</p>
</li>
<li><p>Permutation</p>
</li>
<li><p>Anagram</p>
</li>
<li><p>Maximum/minimum value inside a window</p>
</li>
<li><p>Number of valid subarrays/substrings</p>
</li>
</ul>
<p>For Day 8, I practiced three important LeetCode problems:</p>
<ol>
<li><p><strong>LeetCode 424 — Longest Repeating Character Replacement</strong></p>
</li>
<li><p><strong>LeetCode 567 — Permutation in String</strong></p>
</li>
<li><p><strong>LeetCode 438 — Find All Anagrams in a String</strong></p>
</li>
</ol>
<p>The main idea is:</p>
<blockquote>
<p>Instead of repeatedly checking the entire substring, maintain information about the current window and update it when the window moves.</p>
</blockquote>
<hr />
<h1>1. LeetCode 424 — Longest Repeating Character Replacement</h1>
<h2>Problem</h2>
<p><strong>LeetCode 424 — Longest Repeating Character Replacement</strong></p>
<p>You are given a string <code>s</code> containing uppercase English letters and an integer <code>k</code>.</p>
<p>You can replace at most <code>k</code> characters in the string.</p>
<p>Find the length of the <strong>longest substring</strong> that can be made to contain only the same character after at most <code>k</code> replacements.</p>
<h3>Example</h3>
<pre><code class="language-text">Input:
s = "AABABBA"
k = 1

Output:
4
</code></pre>
<p>Why?</p>
<p>The substring:</p>
<pre><code class="language-text">AABA
</code></pre>
<p>can become:</p>
<pre><code class="language-text">AAAA
</code></pre>
<p>by replacing one <code>B</code>.</p>
<p>So the answer is:</p>
<pre><code class="language-text">4
</code></pre>
<hr />
<h2>Problem Understanding</h2>
<p>Suppose our current window is:</p>
<pre><code class="language-text">A A B A
</code></pre>
<p>Counts:</p>
<pre><code class="language-text">A → 3
B → 1
</code></pre>
<p>The most frequent character is <code>A</code>.</p>
<p>If we want the entire window to contain only <code>A</code>, we need to replace the other characters.</p>
<pre><code class="language-text">Window size = 4
Most frequent count = 3

Characters to replace:
4 - 3 = 1
</code></pre>
<p>If:</p>
<pre><code class="language-text">charactersToReplace &lt;= k
</code></pre>
<p>the window is valid.</p>
<p>So the important formula is:</p>
<pre><code class="language-text">window size - most frequent character count &lt;= k
</code></pre>
<hr />
<h1>Approach</h1>
<p>We use a <strong>variable-size sliding window</strong>.</p>
<p>We maintain:</p>
<pre><code class="language-text">i → left side of window
j → right side of window
map → frequency of characters
maxWindow → longest valid window
</code></pre>
<p>For every character added to the window:</p>
<ol>
<li><p>Increase its frequency.</p>
</li>
<li><p>Find the most frequent character.</p>
</li>
<li><p>Calculate how many replacements are required.</p>
</li>
<li><p>If the window is valid, update the answer.</p>
</li>
<li><p>If the window is invalid, move the left pointer forward.</p>
</li>
</ol>
<h3>Window condition</h3>
<pre><code class="language-javascript">windowSize - maxFrequency &lt;= k
</code></pre>
<p>If this is true:</p>
<pre><code class="language-text">Valid window
</code></pre>
<p>Otherwise:</p>
<pre><code class="language-text">Invalid window → shrink it
</code></pre>
<hr />
<h2>Code</h2>
<pre><code class="language-javascript">var characterReplacement = function (s, k) {
    let i = 0;
    let j = 0;

    let map = Array(26).fill(0);
    let maxWindow = 0;

    while (j &lt; s.length) {

        ++map[s.charCodeAt(j) - 65];

        if (isValidWindow(map, k)) {
            maxWindow = Math.max(maxWindow, j - i + 1);
            ++j;
        } else {
            --map[s.charCodeAt(i) - 65];
            ++i;
        }
    }

    return maxWindow;
};

var isValidWindow = function (map, k) {
    let totalCount = 0;
    let maxCount = 0;

    for (let i = 0; i &lt; 26; i++) {
        totalCount += map[i];
        maxCount = Math.max(maxCount, map[i]);
    }

    return totalCount - maxCount &lt;= k;
};
</code></pre>
<hr />
<h1>How It Works</h1>
<p>Consider:</p>
<pre><code class="language-text">s = "AABABBA"
k = 1
</code></pre>
<p>Initially:</p>
<pre><code class="language-text">i = 0
j = 0
</code></pre>
<p>Window:</p>
<pre><code class="language-text">A
</code></pre>
<p>Frequency:</p>
<pre><code class="language-text">A → 1
</code></pre>
<p>Replacement needed:</p>
<pre><code class="language-text">1 - 1 = 0
</code></pre>
<p>Valid.</p>
<hr />
<p>Next:</p>
<pre><code class="language-text">AA
</code></pre>
<p>Frequency:</p>
<pre><code class="language-text">A → 2
</code></pre>
<p>Replacement:</p>
<pre><code class="language-text">2 - 2 = 0
</code></pre>
<p>Valid.</p>
<hr />
<p>Next:</p>
<pre><code class="language-text">AAB
</code></pre>
<p>Frequency:</p>
<pre><code class="language-text">A → 2
B → 1
</code></pre>
<p>Most frequent:</p>
<pre><code class="language-text">A → 2
</code></pre>
<p>Replacement:</p>
<pre><code class="language-text">3 - 2 = 1
</code></pre>
<p>Since:</p>
<pre><code class="language-text">1 &lt;= k
</code></pre>
<p>the window is valid.</p>
<hr />
<p>Next:</p>
<pre><code class="language-text">AABA
</code></pre>
<p>Frequency:</p>
<pre><code class="language-text">A → 3
B → 1
</code></pre>
<p>Replacement:</p>
<pre><code class="language-text">4 - 3 = 1
</code></pre>
<p>Still valid.</p>
<p>So:</p>
<pre><code class="language-text">maxWindow = 4
</code></pre>
<hr />
<p>When the window becomes invalid, we remove the character at <code>i</code>.</p>
<p>For example:</p>
<pre><code class="language-text">AABABB
</code></pre>
<p>Frequency:</p>
<pre><code class="language-text">A → 3
B → 3
</code></pre>
<p>Window size:</p>
<pre><code class="language-text">6
</code></pre>
<p>Most frequent:</p>
<pre><code class="language-text">3
</code></pre>
<p>Required replacements:</p>
<pre><code class="language-text">6 - 3 = 3
</code></pre>
<p>But:</p>
<pre><code class="language-text">k = 1
</code></pre>
<p>So the window is invalid.</p>
<p>We shrink it:</p>
<pre><code class="language-text">i++
</code></pre>
<p>and remove the leftmost character from the frequency array.</p>
<hr />
<h1>Pattern Recognition</h1>
<p>When you see:</p>
<blockquote>
<p>"Find the longest substring where we can modify/replace at most <code>k</code> elements."</p>
</blockquote>
<p>Think:</p>
<pre><code class="language-text">Variable Sliding Window
        +
Frequency Map
        +
Longest Valid Window
</code></pre>
<p>The important question to ask is:</p>
<blockquote>
<p>"How many characters do I need to change to make this window valid?"</p>
</blockquote>
<p>Here:</p>
<pre><code class="language-text">windowSize - maxFrequency
</code></pre>
<hr />
<h1>Complexity</h1>
<p>Let:</p>
<pre><code class="language-text">n = length of string
</code></pre>
<p>The sliding window moves each pointer at most <code>n</code> times.</p>
<p><code>isValidWindow()</code> checks 26 characters.</p>
<p>Therefore:</p>
<pre><code class="language-text">Time: O(26 × n)
     = O(n)

Space: O(26)
      = O(1)
</code></pre>
<hr />
<h1>2. LeetCode 567 — Permutation in String</h1>
<h2>Problem</h2>
<p><strong>LeetCode 567 — Permutation in String</strong></p>
<p>Given two strings <code>s1</code> and <code>s2</code>, return <code>true</code> if <code>s2</code> contains a permutation of <code>s1</code>.</p>
<p>Otherwise, return <code>false</code>.</p>
<h3>Example</h3>
<pre><code class="language-text">Input:
s1 = "ab"
s2 = "eidbaooo"

Output:
true
</code></pre>
<p>Because:</p>
<pre><code class="language-text">"ba"
</code></pre>
<p>is a permutation of:</p>
<pre><code class="language-text">"ab"
</code></pre>
<p>and <code>"ba"</code> exists inside <code>s2</code>.</p>
<hr />
<h1>Problem Understanding</h1>
<p>A permutation contains exactly the same characters with exactly the same frequencies.</p>
<p>For:</p>
<pre><code class="language-text">s1 = "ab"
</code></pre>
<p>Possible permutations:</p>
<pre><code class="language-text">ab
ba
</code></pre>
<p>We don't actually need to generate all permutations.</p>
<p>Instead, we can compare character frequencies.</p>
<p>For:</p>
<pre><code class="language-text">"ab"
</code></pre>
<p>frequency:</p>
<pre><code class="language-text">a → 1
b → 1
</code></pre>
<p>If a window in <code>s2</code> has the same frequency:</p>
<pre><code class="language-text">a → 1
b → 1
</code></pre>
<p>then that window is a permutation.</p>
<hr />
<h1>Approach</h1>
<p>Here the window size is fixed.</p>
<p>If:</p>
<pre><code class="language-text">s1.length = 2
</code></pre>
<p>every window in <code>s2</code> must have exactly:</p>
<pre><code class="language-text">2 characters
</code></pre>
<p>So this is a:</p>
<pre><code class="language-text">Fixed-Size Sliding Window
</code></pre>
<p>We create two frequency arrays:</p>
<pre><code class="language-javascript">mapS
mapW
</code></pre>
<p>Where:</p>
<pre><code class="language-text">mapS → frequency of s1
mapW → frequency of current window in s2
</code></pre>
<p>Then compare them.</p>
<hr />
<h2>Code</h2>
<pre><code class="language-javascript">var checkInclusion = function (s1, s2) {
    if (s1.length &gt; s2.length) {
        return false;
    }

    let mapS = Array(26).fill(0);
    let mapW = Array(26).fill(0);

    let windowLength = s1.length;

    // Create the initial window
    for (let i = 0; i &lt; windowLength; i++) {
        ++mapS[s1.charCodeAt(i) - 97];
        ++mapW[s2.charCodeAt(i) - 97];
    }

    let i = 0;
    let j = windowLength - 1;

    while (j &lt; s2.length) {

        if (isMapSame(mapS, mapW)) {
            return true;
        }

        // Remove left character
        --mapW[s2.charCodeAt(i) - 97];

        ++i;
        ++j;

        // Add new right character
        if (j &lt; s2.length) {
            ++mapW[s2.charCodeAt(j) - 97];
        }
    }

    return false;
};

var isMapSame = function (mapS, mapW) {
    for (let i = 0; i &lt; 26; i++) {
        if (mapS[i] !== mapW[i]) {
            return false;
        }
    }

    return true;
};
</code></pre>
<hr />
<h1>How It Works</h1>
<p>Consider:</p>
<pre><code class="language-text">s1 = "ab"
s2 = "eidbaooo"
</code></pre>
<p>The required window size is:</p>
<pre><code class="language-text">2
</code></pre>
<p>Initial window:</p>
<pre><code class="language-text">ei
</code></pre>
<p>Frequency doesn't match:</p>
<pre><code class="language-text">s1:
a → 1
b → 1

window:
e → 1
i → 1
</code></pre>
<p>So we slide.</p>
<hr />
<p>Next window:</p>
<pre><code class="language-text">id
</code></pre>
<p>Still doesn't match.</p>
<p>Next:</p>
<pre><code class="language-text">db
</code></pre>
<p>Still doesn't match.</p>
<p>Next:</p>
<pre><code class="language-text">ba
</code></pre>
<p>Frequency:</p>
<pre><code class="language-text">b → 1
a → 1
</code></pre>
<p>Same as <code>s1</code>.</p>
<p>Therefore:</p>
<pre><code class="language-text">return true
</code></pre>
<hr />
<h1>Why Sliding Window?</h1>
<p>Without Sliding Window, we might repeatedly create substrings and count characters.</p>
<p>That creates unnecessary work.</p>
<p>Instead:</p>
<pre><code class="language-text">Remove one character
        ↓
Move window
        ↓
Add one character
</code></pre>
<p>We reuse the previous window's information.</p>
<p>For example:</p>
<pre><code class="language-text">[e i]
</code></pre>
<p>moves to:</p>
<pre><code class="language-text">[i d]
</code></pre>
<p>We don't recount everything.</p>
<p>We:</p>
<pre><code class="language-text">remove e
add d
</code></pre>
<p>This is the main advantage of Sliding Window.</p>
<hr />
<h1>Pattern Recognition</h1>
<p>When you see:</p>
<blockquote>
<p>"Does one string contain a permutation/anagram of another string?"</p>
</blockquote>
<p>Think:</p>
<pre><code class="language-text">Fixed-Size Sliding Window
        +
Frequency Array
        +
Frequency Comparison
</code></pre>
<p>The key clue is:</p>
<pre><code class="language-text">window size = pattern length
</code></pre>
<hr />
<h1>Complexity</h1>
<p>There are 26 possible lowercase English characters.</p>
<p>For each window, we compare 26 values.</p>
<p>Therefore:</p>
<pre><code class="language-text">Time: O(26 × n)
     = O(n)

Space: O(26)
      = O(1)
</code></pre>
<hr />
<h1>3. LeetCode 438 — Find All Anagrams in a String</h1>
<h2>Problem</h2>
<p><strong>LeetCode 438 — Find All Anagrams in a String</strong></p>
<p>Given two strings <code>s</code> and <code>p</code>, return an array containing the starting indices of all anagrams of <code>p</code> in <code>s</code>.</p>
<h3>Example</h3>
<pre><code class="language-text">Input:

s = "cbaebabacd"
p = "abc"

Output:

[0, 6]
</code></pre>
<p>Because:</p>
<pre><code class="language-text">cba
</code></pre>
<p>is an anagram of:</p>
<pre><code class="language-text">abc
</code></pre>
<p>and:</p>
<pre><code class="language-text">bac
</code></pre>
<p>is also an anagram of:</p>
<pre><code class="language-text">abc
</code></pre>
<p>Their starting indices are:</p>
<pre><code class="language-text">0
6
</code></pre>
<hr />
<h1>Problem Understanding</h1>
<p>Anagrams have:</p>
<ol>
<li><p>Same characters</p>
</li>
<li><p>Same frequency</p>
</li>
<li><p>Different order is allowed</p>
</li>
</ol>
<p>For example:</p>
<pre><code class="language-text">abc
bca
cab
acb
bac
cba
</code></pre>
<p>All are anagrams.</p>
<p>So we don't care about character order.</p>
<p>We only care about:</p>
<pre><code class="language-text">frequency
</code></pre>
<hr />
<h1>Approach</h1>
<p>This problem is very similar to LeetCode 567.</p>
<p>The difference is:</p>
<h3>LeetCode 567</h3>
<p>We need to know:</p>
<pre><code class="language-text">Does at least one permutation exist?
</code></pre>
<p>So we return:</p>
<pre><code class="language-text">true / false
</code></pre>
<h3>LeetCode 438</h3>
<p>We need:</p>
<pre><code class="language-text">All positions where an anagram exists
</code></pre>
<p>So we store the starting index.</p>
<hr />
<p>The window size is:</p>
<pre><code class="language-text">p.length
</code></pre>
<p>We maintain:</p>
<pre><code class="language-text">mapP → frequency of pattern
mapW → frequency of current window
</code></pre>
<p>Whenever:</p>
<pre><code class="language-text">mapP === mapW
</code></pre>
<p>we found an anagram.</p>
<hr />
<h2>Code</h2>
<pre><code class="language-javascript">var findAnagrams = function (s, p) {
    if (p.length &gt; s.length) {
        return [];
    }

    let mapW = Array(26).fill(0);
    let mapP = Array(26).fill(0);

    let window = p.length;

    // Create initial window
    for (let i = 0; i &lt; window; i++) {
        ++mapW[s.charCodeAt(i) - 97];
        ++mapP[p.charCodeAt(i) - 97];
    }

    let i = 0;
    let j = window - 1;

    let res = [];

    while (j &lt; s.length) {

        if (isAnagram(mapW, mapP)) {
            res.push(i);
        }

        // Remove left character
        --mapW[s.charCodeAt(i) - 97];

        ++i;
        ++j;

        // Add new right character
        if (j &lt; s.length) {
            ++mapW[s.charCodeAt(j) - 97];
        }
    }

    return res;
};

var isAnagram = function (mapW, mapP) {
    for (let i = 0; i &lt; 26; i++) {
        if (mapW[i] !== mapP[i]) {
            return false;
        }
    }

    return true;
};
</code></pre>
<hr />
<h1>How It Works</h1>
<p>Consider:</p>
<pre><code class="language-text">s = "cbaebabacd"
p = "abc"
</code></pre>
<p>Pattern:</p>
<pre><code class="language-text">abc
</code></pre>
<p>Frequency:</p>
<pre><code class="language-text">a → 1
b → 1
c → 1
</code></pre>
<p>Initial window:</p>
<pre><code class="language-text">cba
</code></pre>
<p>Frequency:</p>
<pre><code class="language-text">a → 1
b → 1
c → 1
</code></pre>
<p>Both maps are equal.</p>
<p>Therefore:</p>
<pre><code class="language-text">res.push(0)
</code></pre>
<hr />
<p>Now slide the window.</p>
<p>Current:</p>
<pre><code class="language-text">cba
</code></pre>
<p>Remove:</p>
<pre><code class="language-text">c
</code></pre>
<p>Add:</p>
<pre><code class="language-text">e
</code></pre>
<p>New window:</p>
<pre><code class="language-text">bae
</code></pre>
<p>Frequency doesn't match.</p>
<p>Continue sliding.</p>
<p>Eventually we reach:</p>
<pre><code class="language-text">bac
</code></pre>
<p>Its frequency is:</p>
<pre><code class="language-text">a → 1
b → 1
c → 1
</code></pre>
<p>Again it matches the pattern.</p>
<p>Starting index:</p>
<pre><code class="language-text">6
</code></pre>
<p>So:</p>
<pre><code class="language-javascript">res = [0, 6]
</code></pre>
<hr />
<h1>Pattern Recognition</h1>
<p>When you see:</p>
<blockquote>
<p>"Find all anagrams of a pattern inside a string."</p>
</blockquote>
<p>Think:</p>
<pre><code class="language-text">Fixed-Size Sliding Window
             +
Frequency Array
             +
Compare Window With Pattern
</code></pre>
<p>The most important clue is:</p>
<pre><code class="language-text">window size = pattern length
</code></pre>
<hr />
<h1>Complexity</h1>
<p>We compare 26 characters for every window.</p>
<p>Therefore:</p>
<pre><code class="language-text">Time: O(26 × n)
     = O(n)

Space: O(26)
      = O(1)
</code></pre>
<hr />
<h1>Fixed vs Variable Sliding Window</h1>
<p>These three problems help identify an important difference.</p>
<h2>Fixed-Size Window</h2>
<p>The window size is already known.</p>
<p>Examples:</p>
<pre><code class="language-text">LeetCode 567
LeetCode 438
</code></pre>
<p>If:</p>
<pre><code class="language-text">pattern.length = 3
</code></pre>
<p>then every window has exactly 3 characters.</p>
<p>Pattern:</p>
<pre><code class="language-text">abc
</code></pre>
<p>Windows:</p>
<pre><code class="language-text">cba
bae
aeb
eba
...
</code></pre>
<hr />
<h2>Variable-Size Window</h2>
<p>The window size changes depending on whether the current window is valid.</p>
<p>Example:</p>
<pre><code class="language-text">LeetCode 424
</code></pre>
<p>We expand:</p>
<pre><code class="language-text">j++
</code></pre>
<p>when the window is valid.</p>
<p>We shrink:</p>
<pre><code class="language-text">i++
</code></pre>
<p>when the window becomes invalid.</p>
<hr />
<h1>The Sliding Window Mental Model</h1>
<p>The easiest way I understand Sliding Window is:</p>
<pre><code class="language-text">          j
          ↓
A B A B C A A
↑
i
</code></pre>
<p><code>i</code> represents the left side.</p>
<p><code>j</code> represents the right side.</p>
<p>The window is:</p>
<pre><code class="language-text">[i ........ j]
</code></pre>
<p>For example:</p>
<pre><code class="language-text">A B A B
↑     ↑
i     j
</code></pre>
<p>When we want to move the window:</p>
<pre><code class="language-text">Remove s[i]
Move i
Add s[j]
Move j
</code></pre>
<p>So instead of rebuilding the window again and again, we maintain it incrementally.</p>
<hr />
<h1>How to Recognize Sliding Window in Interviews</h1>
<p>Look for these keywords:</p>
<h3>1. "Substring"</h3>
<p>Example:</p>
<pre><code class="language-text">Find the longest substring...
</code></pre>
<p>Possible Sliding Window problem.</p>
<hr />
<h3>2. "Subarray"</h3>
<p>Example:</p>
<pre><code class="language-text">Find the smallest subarray...
</code></pre>
<p>Possible Sliding Window problem.</p>
<hr />
<h3>3. "Contiguous"</h3>
<p>Example:</p>
<pre><code class="language-text">Find the maximum sum of a contiguous subarray...
</code></pre>
<p>Strong Sliding Window clue.</p>
<hr />
<h3>4. "At most K"</h3>
<p>Example:</p>
<pre><code class="language-text">At most k replacements
At most k distinct characters
</code></pre>
<p>Usually suggests a variable-size Sliding Window.</p>
<hr />
<h3>5. "Permutation"</h3>
<p>Example:</p>
<pre><code class="language-text">Does s2 contain a permutation of s1?
</code></pre>
<p>Think:</p>
<pre><code class="language-text">Fixed Window + Frequency Map
</code></pre>
<hr />
<h3>6. "Anagram"</h3>
<p>Example:</p>
<pre><code class="language-text">Find all anagrams in a string
</code></pre>
<p>Think:</p>
<pre><code class="language-text">Fixed Window + Frequency Map
</code></pre>
<hr />
<h1>Day 8 Pattern Summary</h1>
<table>
<thead>
<tr>
<th>Problem</th>
<th>Window Type</th>
<th>Main Technique</th>
</tr>
</thead>
<tbody><tr>
<td>LeetCode 424</td>
<td>Variable</td>
<td>Frequency + Valid Window</td>
</tr>
<tr>
<td>LeetCode 567</td>
<td>Fixed</td>
<td>Frequency Comparison</td>
</tr>
<tr>
<td>LeetCode 438</td>
<td>Fixed</td>
<td>Frequency Comparison</td>
</tr>
</tbody></table>
<p>The common structure is:</p>
<pre><code class="language-text">Sliding Window
      ↓
Maintain Frequency
      ↓
Move Window
      ↓
Check Condition
      ↓
Update Answer
</code></pre>
<hr />
<h1>One Important Improvement to My Original Code</h1>
<p>While solving these problems, I learned that pointer movement and array access need to be handled carefully.</p>
<p>For example, code like this can cause a boundary problem:</p>
<pre><code class="language-javascript">++j;
++map[s.charCodeAt(j) - 65];
</code></pre>
<p>If <code>j</code> becomes:</p>
<pre><code class="language-text">s.length
</code></pre>
<p>then:</p>
<pre><code class="language-javascript">s.charCodeAt(j)
</code></pre>
<p>does not give a valid character.</p>
<p>So it is safer to:</p>
<pre><code class="language-javascript">++j;

if (j &lt; s.length) {
    ++map[s.charCodeAt(j) - 65];
}
</code></pre>
<p>This small check prevents accessing outside the string.</p>
<hr />
<h1>What I Learned Today</h1>
<p>The biggest lesson from Day 8 was that Sliding Window is not one single technique.</p>
<p>There are two major forms:</p>
<pre><code class="language-text">1. Fixed-Size Sliding Window

2. Variable-Size Sliding Window
</code></pre>
<h3>Fixed Size</h3>
<p>Used when the problem gives us a specific window size.</p>
<pre><code class="language-text">window = pattern.length
</code></pre>
<p>Examples:</p>
<pre><code class="language-text">LeetCode 567
LeetCode 438
</code></pre>
<h3>Variable Size</h3>
<p>Used when the window size depends on a condition.</p>
<pre><code class="language-text">Expand → Check → Shrink if invalid
</code></pre>
<p>Example:</p>
<pre><code class="language-text">LeetCode 424
</code></pre>
<p>The most important habit is to ask:</p>
<blockquote>
<p><strong>Is the window size fixed, or does it change based on a condition?</strong></p>
</blockquote>
<p>Once I identify that, the implementation becomes much easier.</p>
<hr />
<h1>Final Pattern Cheat Sheet</h1>
<pre><code class="language-text">Substring / Subarray
        ↓
Think Sliding Window
        ↓
Is window size fixed?
        ↓
   ┌────┴────┐
   ↓         ↓
  YES        NO
   ↓         ↓
Fixed      Variable
Window     Window
   ↓         ↓
Frequency   Expand
Map         ↓
   ↓       Check
Compare     ↓
            Shrink
          if invalid
</code></pre>
<h3>Problems practiced today</h3>
<pre><code class="language-text">424 → Longest Repeating Character Replacement
567 → Permutation in String
438 → Find All Anagrams in a String
</code></pre>
<p>These three problems gave me a better understanding of how <strong>Sliding Window + Frequency Array</strong> works in JavaScript.</p>
<p>Day 8 completed.</p>
]]></content:encoded></item><item><title><![CDATA[Object-Oriented Programming (OOP) — A Beginner-Friendly Guide with Real-World Examples]]></title><description><![CDATA[When we start learning programming, we usually begin by writing variables, functions, and conditions.
But as applications become larger, managing all that code becomes difficult.
Imagine building a ba]]></description><link>https://abi-blog.hashnode.dev/object-oriented-programming-oop-a-beginner-friendly-guide-with-real-world-examples</link><guid isPermaLink="true">https://abi-blog.hashnode.dev/object-oriented-programming-oop-a-beginner-friendly-guide-with-real-world-examples</guid><category><![CDATA[Java]]></category><category><![CDATA[oop]]></category><category><![CDATA[Object Oriented Programming]]></category><category><![CDATA[#java #oop]]></category><category><![CDATA[inheritance]]></category><category><![CDATA[encapsulation]]></category><category><![CDATA[polymorphism]]></category><category><![CDATA[abstraction]]></category><category><![CDATA[Java interview ]]></category><category><![CDATA[coding]]></category><category><![CDATA[software development]]></category><category><![CDATA[beginner java]]></category><category><![CDATA[Programming Blogs]]></category><dc:creator><![CDATA[Abirami Sri]]></dc:creator><pubDate>Wed, 09 Sep 2026 16:31:24 GMT</pubDate><content:encoded><![CDATA[<p>When we start learning programming, we usually begin by writing variables, functions, and conditions.</p>
<p>But as applications become larger, managing all that code becomes difficult.</p>
<p>Imagine building a <strong>banking application</strong> with thousands of lines of code. You need to manage customers, accounts, transactions, loans, payments, cards, and many other things.</p>
<p>If everything is written using unrelated variables and functions, the code can quickly become difficult to understand and maintain.</p>
<p>This is where <strong>Object-Oriented Programming (OOP)</strong> becomes useful.</p>
<p>OOP is a programming approach where we organize our program around <strong>objects</strong> that contain both <strong>data</strong> and <strong>behavior</strong>.</p>
<p>Let's understand OOP step by step using simple programming examples and real-world examples.</p>
<hr />
<h1>What is OOP?</h1>
<p><strong>OOP stands for Object-Oriented Programming.</strong></p>
<p>It is a programming paradigm that organizes software around <strong>objects</strong> rather than only functions and procedures.</p>
<p>An object can contain:</p>
<ul>
<li><p><strong>Data</strong> → information about the object</p>
</li>
<li><p><strong>Methods</strong> → actions that the object can perform</p>
</li>
</ul>
<h3>Real-world example: Mobile Phone</h3>
<p>Think about a <strong>mobile phone</strong>.</p>
<p>A phone has properties such as:</p>
<ul>
<li><p>Brand</p>
</li>
<li><p>Model</p>
</li>
<li><p>Price</p>
</li>
<li><p>Storage</p>
</li>
</ul>
<p>And it can perform actions such as:</p>
<ul>
<li><p>Call</p>
</li>
<li><p>Send message</p>
</li>
<li><p>Take photo</p>
</li>
<li><p>Play video</p>
</li>
</ul>
<p>We can represent this idea in programming using a class and objects.</p>
<pre><code class="language-java">class Phone {

    String brand;
    String model;

    void call() {
        System.out.println("Calling...");
    }

    void takePhoto() {
        System.out.println("Taking photo...");
    }
}
</code></pre>
<p>Here:</p>
<ul>
<li><p><code>brand</code> and <code>model</code> are <strong>attributes/data</strong></p>
</li>
<li><p><code>call()</code> and <code>takePhoto()</code> are <strong>methods/behaviors</strong></p>
</li>
</ul>
<p>So we can think of an object as:</p>
<pre><code class="language-text">Phone Object
│
├── Data
│   ├── brand
│   ├── model
│   └── price
│
└── Behavior
    ├── call()
    ├── takePhoto()
    └── sendMessage()
</code></pre>
<h3>Other real-world objects</h3>
<p>In a shopping application, objects could be:</p>
<pre><code class="language-text">Customer
Product
Cart
Order
Payment
Delivery
</code></pre>
<p>Each object can have its own data and behavior.</p>
<p>For example:</p>
<pre><code class="language-text">Order
│
├── Data
│   ├── orderId
│   ├── totalAmount
│   └── status
│
└── Behavior
    ├── placeOrder()
    ├── cancelOrder()
    └── trackOrder()
</code></pre>
<hr />
<h1>Class vs Object</h1>
<p>One of the most important concepts in OOP is understanding the difference between a <strong>class</strong> and an <strong>object</strong>.</p>
<h2>Class</h2>
<p>A class is like a <strong>blueprint or template</strong>.</p>
<p>For example, a house blueprint describes:</p>
<ul>
<li><p>Number of rooms</p>
</li>
<li><p>Doors</p>
</li>
<li><p>Windows</p>
</li>
<li><p>Structure</p>
</li>
</ul>
<p>But the blueprint itself is not a real house.</p>
<p>Similarly, a class defines what an object should contain.</p>
<pre><code class="language-java">class Car {

    String color;

    void drive() {
        System.out.println("Car is driving");
    }
}
</code></pre>
<p>The <code>Car</code> class is a blueprint.</p>
<p>It describes that a car has:</p>
<ul>
<li><p><code>color</code></p>
</li>
<li><p><code>drive()</code> behavior</p>
</li>
</ul>
<p>But we haven't created an actual car yet.</p>
<hr />
<h2>Object</h2>
<p>An object is a <strong>real instance created from a class</strong>.</p>
<pre><code class="language-java">Car car1 = new Car();
Car car2 = new Car();
</code></pre>
<p>Here:</p>
<ul>
<li><p><code>Car</code> → class</p>
</li>
<li><p><code>car1</code> → object</p>
</li>
<li><p><code>car2</code> → object</p>
</li>
</ul>
<p>We can give different values to each object.</p>
<pre><code class="language-java">car1.color = "Red";
car2.color = "Blue";
</code></pre>
<p>Now we have:</p>
<pre><code class="language-text">Car Class
   │
   ├── car1 → Red
   │
   └── car2 → Blue
</code></pre>
<h3>Real-world analogy</h3>
<p>Think about a <strong>cookie cutter</strong>.</p>
<pre><code class="language-text">Cookie Cutter → Class
        ↓
   ┌─────────┐
   │ Cookie  │ → Object 1
   └─────────┘
   ┌─────────┐
   │ Cookie  │ → Object 2
   └─────────┘
</code></pre>
<p>The cookie cutter defines the shape.</p>
<p>Each actual cookie is an object created from that design.</p>
<hr />
<h1>Why Do We Use OOP?</h1>
<p>OOP is useful because it helps us organize large applications.</p>
<p>Some important benefits are:</p>
<h3>1. Better Organization</h3>
<p>Related data and behavior can be kept together.</p>
<p>For example, instead of having:</p>
<pre><code class="language-text">customerName
customerEmail
customerAddress

sendEmail()
updateAddress()
</code></pre>
<p>scattered throughout the application, we can organize them inside a <code>Customer</code> class.</p>
<pre><code class="language-java">class Customer {

    String name;
    String email;
    String address;

    void sendEmail() {
        // send email
    }

    void updateAddress() {
        // update address
    }
}
</code></pre>
<hr />
<h3>2. Reusability</h3>
<p>We can create a class once and create many objects from it.</p>
<p>For example:</p>
<pre><code class="language-java">Customer customer1 = new Customer();
Customer customer2 = new Customer();
Customer customer3 = new Customer();
</code></pre>
<p>We don't need to rewrite the customer logic for every customer.</p>
<hr />
<h3>3. Maintainability</h3>
<p>Suppose the payment logic needs to change.</p>
<p>If payment-related logic is organized inside a <code>Payment</code> class, we can modify that class instead of searching through hundreds of unrelated functions.</p>
<hr />
<h3>4. Scalability</h3>
<p>Large applications such as:</p>
<ul>
<li><p>Banking applications</p>
</li>
<li><p>E-commerce platforms</p>
</li>
<li><p>Food delivery applications</p>
</li>
<li><p>Ride-booking applications</p>
</li>
<li><p>Enterprise software</p>
</li>
</ul>
<p>can contain many different objects.</p>
<p>OOP provides a structured way to model these entities and their interactions.</p>
<hr />
<h3>5. Security</h3>
<p>Encapsulation allows us to control how sensitive data is accessed.</p>
<p>For example, a banking application should not allow users to directly modify their account balance.</p>
<p>Instead, operations such as:</p>
<pre><code class="language-java">deposit()
withdraw()
</code></pre>
<p>can validate the request before changing the balance.</p>
<hr />
<h1>The Four Pillars of OOP</h1>
<p>OOP is commonly explained using four major concepts:</p>
<ol>
<li><p><strong>Encapsulation</strong></p>
</li>
<li><p><strong>Inheritance</strong></p>
</li>
<li><p><strong>Polymorphism</strong></p>
</li>
<li><p><strong>Abstraction</strong></p>
</li>
</ol>
<p>Let's understand each one using programming and real-world examples.</p>
<hr />
<h1>1. Encapsulation</h1>
<p><strong>Encapsulation means bundling data and the methods that operate on that data together, while controlling direct access to the data.</strong></p>
<p>In simple words:</p>
<blockquote>
<p><strong>Keep data protected and provide controlled ways to access or modify it.</strong></p>
</blockquote>
<h2>Real-world example: Bank Account</h2>
<p>Consider a bank account.</p>
<p>You shouldn't be able to directly change your bank balance like this:</p>
<pre><code class="language-java">balance = -50000;
</code></pre>
<p>Instead, the bank should provide controlled operations such as:</p>
<pre><code class="language-java">deposit(5000);
withdraw(1000);
</code></pre>
<p>The bank can then check whether the operation is valid.</p>
<p>For example:</p>
<pre><code class="language-text">User
 │
 │ deposit(5000)
 ↓
Bank Account
 │
 ├── Check amount
 ├── Update balance
 └── Return result
</code></pre>
<h3>Java example</h3>
<pre><code class="language-java">class BankAccount {

    private double balance;

    public void deposit(double amount) {

        if (amount &gt; 0) {
            balance += amount;
        }
    }

    public double getBalance() {
        return balance;
    }
}
</code></pre>
<p>Here:</p>
<pre><code class="language-java">private double balance;
</code></pre>
<p>means that the balance cannot be directly accessed from outside the class.</p>
<p>Instead, we use methods such as:</p>
<pre><code class="language-java">deposit()
getBalance()
</code></pre>
<p>This gives us control over how the data is accessed and changed.</p>
<h3>Another real-world example: ATM</h3>
<p>When using an ATM, you don't directly manipulate the bank's database.</p>
<p>Instead, you perform controlled actions:</p>
<pre><code class="language-text">Insert Card
    ↓
Enter PIN
    ↓
Choose Withdraw
    ↓
Enter Amount
    ↓
Bank validates request
    ↓
Money is dispensed
</code></pre>
<p>The internal account data remains protected.</p>
<p>That is the basic idea behind encapsulation.</p>
<h3>Why is encapsulation useful?</h3>
<p>It helps:</p>
<ul>
<li><p>Protect data</p>
</li>
<li><p>Prevent invalid modifications</p>
</li>
<li><p>Control access</p>
</li>
<li><p>Make code easier to maintain</p>
</li>
</ul>
<hr />
<h1>2. Inheritance</h1>
<p><strong>Inheritance allows one class to acquire properties and behaviors from another class.</strong></p>
<p>The existing class is commonly called the <strong>parent/superclass</strong>.</p>
<p>The new class is called the <strong>child/subclass</strong>.</p>
<h2>Real-world example: Animal</h2>
<p>Consider:</p>
<pre><code class="language-text">Animal
  │
  ├── Dog
  ├── Cat
  └── Bird
</code></pre>
<p>All these animals may have common behaviors such as:</p>
<ul>
<li><p>Eat</p>
</li>
<li><p>Sleep</p>
</li>
<li><p>Breathe</p>
</li>
</ul>
<p>But each animal can also have its own behavior.</p>
<p>For example:</p>
<ul>
<li><p>Dog → Bark</p>
</li>
<li><p>Cat → Meow</p>
</li>
<li><p>Bird → Fly</p>
</li>
</ul>
<p>Instead of writing the common functionality repeatedly, we can place it inside the parent class.</p>
<pre><code class="language-java">class Animal {

    void eat() {
        System.out.println("Animal is eating");
    }
}

class Dog extends Animal {

    void bark() {
        System.out.println("Dog is barking");
    }
}
</code></pre>
<p>Now:</p>
<pre><code class="language-java">Dog dog = new Dog();

dog.eat();
dog.bark();
</code></pre>
<p>The <code>Dog</code> object can use:</p>
<ul>
<li><p><code>eat()</code> → inherited from <code>Animal</code></p>
</li>
<li><p><code>bark()</code> → defined in <code>Dog</code></p>
</li>
</ul>
<h3>Real-world software example</h3>
<p>Imagine an e-commerce application.</p>
<p>We might have:</p>
<pre><code class="language-text">User
│
├── Customer
├── Seller
└── Admin
</code></pre>
<p>All users might share:</p>
<pre><code class="language-text">name
email
login()
logout()
</code></pre>
<p>But each type can have additional behavior.</p>
<pre><code class="language-text">Customer
 ├── placeOrder()
 └── addToCart()

Seller
 ├── addProduct()
 └── manageInventory()

Admin
 ├── manageUsers()
 └── generateReports()
</code></pre>
<p>Inheritance can help represent these shared relationships.</p>
<h3>Important note</h3>
<p>Inheritance should generally represent a genuine <strong>"is-a" relationship</strong>.</p>
<p>For example:</p>
<pre><code class="language-text">Dog is an Animal
Car is a Vehicle
SavingsAccount is an Account
</code></pre>
<p>But:</p>
<pre><code class="language-text">Car is an Engine
</code></pre>
<p>doesn't make sense.</p>
<p>A car <strong>has an engine</strong>, so that relationship is better modeled using composition rather than inheritance.</p>
<h3>Types of inheritance</h3>
<p>Common types include:</p>
<ol>
<li><p>Single inheritance</p>
</li>
<li><p>Multilevel inheritance</p>
</li>
<li><p>Hierarchical inheritance</p>
</li>
<li><p>Multiple inheritance</p>
</li>
<li><p>Hybrid inheritance</p>
</li>
</ol>
<p>However, the exact types supported depend on the programming language.</p>
<p>For example, <strong>Java does not support multiple inheritance through classes</strong>, but it can achieve multiple inheritance of type through interfaces.</p>
<hr />
<h1>3. Polymorphism</h1>
<p>The word <strong>polymorphism</strong> comes from:</p>
<ul>
<li><p>Poly → many</p>
</li>
<li><p>Morph → forms</p>
</li>
</ul>
<p>So polymorphism means <strong>one interface/name can represent different forms of behavior</strong>.</p>
<p>In simple words:</p>
<blockquote>
<p><strong>The same method call can produce different behavior depending on the object.</strong></p>
</blockquote>
<p>There are two commonly discussed forms:</p>
<ol>
<li><p>Compile-time polymorphism</p>
</li>
<li><p>Runtime polymorphism</p>
</li>
</ol>
<hr />
<h1>Compile-Time Polymorphism</h1>
<p>This is commonly achieved through <strong>method overloading</strong>.</p>
<p>Method overloading means having multiple methods with the same name but different parameter lists.</p>
<pre><code class="language-java">class Calculator {

    int add(int a, int b) {
        return a + b;
    }

    int add(int a, int b, int c) {
        return a + b + c;
    }
}
</code></pre>
<p>Both methods are named:</p>
<pre><code class="language-java">add()
</code></pre>
<p>But they accept different numbers of parameters.</p>
<pre><code class="language-java">Calculator calculator = new Calculator();

calculator.add(10, 20);

calculator.add(10, 20, 30);
</code></pre>
<p>The compiler determines which method should be called.</p>
<p>Therefore, this is called <strong>compile-time polymorphism</strong>.</p>
<h3>Real-world example</h3>
<p>Think about a food delivery application.</p>
<p>You might have a function:</p>
<pre><code class="language-text">calculateDeliveryFee()
</code></pre>
<p>But it could work differently depending on the parameters:</p>
<pre><code class="language-text">calculateDeliveryFee(distance)

calculateDeliveryFee(distance, peakTime)

calculateDeliveryFee(distance, peakTime, membership)
</code></pre>
<p>The method name remains the same, but the input parameters differ.</p>
<p>That's similar to method overloading.</p>
<hr />
<h1>Runtime Polymorphism</h1>
<p>Runtime polymorphism is commonly achieved through <strong>method overriding</strong>.</p>
<p>A child class provides its own implementation of a method inherited from the parent class.</p>
<pre><code class="language-java">class Animal {

    void sound() {
        System.out.println("Animal makes a sound");
    }
}

class Dog extends Animal {

    @Override
    void sound() {
        System.out.println("Dog barks");
    }
}
</code></pre>
<p>Now:</p>
<pre><code class="language-java">Animal animal = new Dog();

animal.sound();
</code></pre>
<p>The reference type is <code>Animal</code>, but the actual object is <code>Dog</code>.</p>
<p>Therefore, the <code>Dog</code> implementation of <code>sound()</code> is executed.</p>
<p>This decision happens at <strong>runtime</strong>.</p>
<h3>Real-world example: Payment system</h3>
<p>Imagine an application supporting different payment methods:</p>
<pre><code class="language-text">Payment
│
├── CreditCardPayment
├── UpiPayment
└── NetBankingPayment
</code></pre>
<p>Each payment type can implement:</p>
<pre><code class="language-java">pay()
</code></pre>
<p>differently.</p>
<p>For example:</p>
<pre><code class="language-java">class Payment {
    void pay() {
        System.out.println("Processing payment");
    }
}

class UpiPayment extends Payment {

    @Override
    void pay() {
        System.out.println("Processing UPI payment");
    }
}

class CardPayment extends Payment {

    @Override
    void pay() {
        System.out.println("Processing card payment");
    }
}
</code></pre>
<p>Now:</p>
<pre><code class="language-java">Payment payment = new UpiPayment();

payment.pay();
</code></pre>
<p>The same:</p>
<pre><code class="language-java">payment.pay();
</code></pre>
<p>can produce different behavior depending on the actual object.</p>
<p>That's the power of runtime polymorphism.</p>
<hr />
<h1>Overloading vs Overriding</h1>
<p>This is a very common interview question.</p>
<table>
<thead>
<tr>
<th>Method Overloading</th>
<th>Method Overriding</th>
</tr>
</thead>
<tbody><tr>
<td>Same method name</td>
<td>Same method signature</td>
</tr>
<tr>
<td>Different parameter lists</td>
<td>Same parameter list</td>
</tr>
<tr>
<td>Usually within the same class</td>
<td>Parent-child relationship</td>
</tr>
<tr>
<td>Compile-time polymorphism</td>
<td>Runtime polymorphism</td>
</tr>
<tr>
<td>Compiler chooses the method</td>
<td>Runtime determines implementation</td>
</tr>
</tbody></table>
<h3>Easy way to remember</h3>
<p><strong>Overloading → Same name, different parameters</strong></p>
<p><strong>Overriding → Child changes parent's implementation</strong></p>
<hr />
<h1>4. Abstraction</h1>
<p><strong>Abstraction means hiding unnecessary implementation details and exposing only the essential functionality.</strong></p>
<p>Think about driving a car.</p>
<p>You know how to:</p>
<ul>
<li><p>Start the car</p>
</li>
<li><p>Accelerate</p>
</li>
<li><p>Brake</p>
</li>
<li><p>Turn the steering wheel</p>
</li>
</ul>
<p>But you don't need to understand every internal engine operation to drive it.</p>
<p>That's abstraction.</p>
<h3>Real-world example: Food Delivery App</h3>
<p>When you click:</p>
<pre><code class="language-text">"Place Order"
</code></pre>
<p>you don't need to know everything happening internally.</p>
<p>Behind the scenes, the system may:</p>
<pre><code class="language-text">Place Order
    ↓
Validate cart
    ↓
Calculate price
    ↓
Apply discount
    ↓
Process payment
    ↓
Create order
    ↓
Assign delivery partner
    ↓
Send notification
</code></pre>
<p>The user only sees:</p>
<pre><code class="language-text">Order Placed Successfully
</code></pre>
<p>The complicated implementation is hidden.</p>
<p>That is the basic idea of abstraction.</p>
<hr />
<h1>Abstraction in Java</h1>
<p>Java commonly provides abstraction using:</p>
<ul>
<li><p>Abstract classes</p>
</li>
<li><p>Interfaces</p>
</li>
</ul>
<h2>Abstract Class Example</h2>
<pre><code class="language-java">abstract class Shape {

    abstract void draw();
}
</code></pre>
<p>Here, <code>Shape</code> defines that every shape should have a <code>draw()</code> method.</p>
<p>But it doesn't provide the actual implementation.</p>
<p>A child class can provide the implementation.</p>
<pre><code class="language-java">class Circle extends Shape {

    @Override
    void draw() {
        System.out.println("Drawing Circle");
    }
}
</code></pre>
<p>Now:</p>
<pre><code class="language-java">Shape shape = new Circle();

shape.draw();
</code></pre>
<p>The user only needs to know that a shape can be drawn.</p>
<p>The actual implementation is provided by <code>Circle</code>.</p>
<h3>Real-world example: Payment</h3>
<p>A payment system might define:</p>
<pre><code class="language-java">interface Payment {

    void pay();
}
</code></pre>
<p>Different payment methods can implement it:</p>
<pre><code class="language-java">class UPI implements Payment {

    public void pay() {
        System.out.println("Paying using UPI");
    }
}

class CreditCard implements Payment {

    public void pay() {
        System.out.println("Paying using Credit Card");
    }
}
</code></pre>
<p>The application only needs to know:</p>
<pre><code class="language-java">payment.pay();
</code></pre>
<p>It doesn't need to know all the internal details of how UPI or credit-card processing works.</p>
<hr />
<h1>Encapsulation vs Abstraction</h1>
<p>These two concepts are often confused.</p>
<h2>Encapsulation</h2>
<p>Focuses on:</p>
<blockquote>
<p><strong>How do we protect and control access to data?</strong></p>
</blockquote>
<p>Example:</p>
<pre><code class="language-java">private double balance;
</code></pre>
<p>Encapsulation is about <strong>data + controlled access</strong>.</p>
<hr />
<h2>Abstraction</h2>
<p>Focuses on:</p>
<blockquote>
<p><strong>What should the user see, and what implementation details can be hidden?</strong></p>
</blockquote>
<p>Example:</p>
<pre><code class="language-java">abstract void draw();
</code></pre>
<p>Abstraction is about <strong>exposing essential functionality while hiding unnecessary implementation details</strong>.</p>
<h3>Easy way to remember</h3>
<p><strong>Encapsulation → Protect and control data</strong></p>
<p><strong>Abstraction → Hide implementation complexity</strong></p>
<hr />
<h1>Quick Revision of the Four Pillars</h1>
<table>
<thead>
<tr>
<th>Pillar</th>
<th>Simple Meaning</th>
<th>Real-World Example</th>
</tr>
</thead>
<tbody><tr>
<td>Encapsulation</td>
<td>Protect and control data</td>
<td>Bank account</td>
</tr>
<tr>
<td>Inheritance</td>
<td>Reuse common behavior</td>
<td>Dog → Animal</td>
</tr>
<tr>
<td>Polymorphism</td>
<td>Same interface, different behavior</td>
<td>Different payment methods</td>
</tr>
<tr>
<td>Abstraction</td>
<td>Hide implementation complexity</td>
<td>Place order / make payment</td>
</tr>
</tbody></table>
<hr />
<h1>A Complete Real-World Example: E-Commerce Application</h1>
<p>Let's imagine we are building an application like Amazon or Flipkart.</p>
<p>Our application might contain:</p>
<pre><code class="language-text">E-Commerce System
│
├── User
├── Product
├── Cart
├── Order
├── Payment
└── Delivery
</code></pre>
<p>Now let's see how OOP concepts can be applied.</p>
<h2>Encapsulation</h2>
<p>A product's price should not be changed randomly.</p>
<pre><code class="language-java">class Product {

    private double price;

    public void setPrice(double price) {

        if (price &gt;= 0) {
            this.price = price;
        }
    }

    public double getPrice() {
        return price;
    }
}
</code></pre>
<p>The price is protected and can only be changed through controlled logic.</p>
<hr />
<h2>Inheritance</h2>
<p>Different types of users can share common functionality.</p>
<pre><code class="language-text">User
│
├── Customer
├── Seller
└── Admin
</code></pre>
<pre><code class="language-java">class User {

    void login() {
        System.out.println("User logged in");
    }
}

class Customer extends User {

    void placeOrder() {
        System.out.println("Order placed");
    }
}
</code></pre>
<p><code>Customer</code> can reuse <code>login()</code> from <code>User</code>.</p>
<hr />
<h2>Polymorphism</h2>
<p>Different payment methods can implement payment differently.</p>
<pre><code class="language-text">Payment
│
├── UPI
├── Credit Card
└── Net Banking
</code></pre>
<p>The application can simply call:</p>
<pre><code class="language-java">payment.pay();
</code></pre>
<p>The actual implementation depends on the payment object.</p>
<hr />
<h2>Abstraction</h2>
<p>The user doesn't need to understand:</p>
<ul>
<li><p>Payment gateway communication</p>
</li>
<li><p>Database transactions</p>
</li>
<li><p>Fraud detection</p>
</li>
<li><p>Order creation</p>
</li>
<li><p>Inventory updates</p>
</li>
</ul>
<p>The application can expose a simple operation:</p>
<pre><code class="language-text">Place Order
</code></pre>
<p>while hiding the complicated internal implementation.</p>
<hr />
<h1>OOP in Real Software Companies</h1>
<p>OOP is not just an interview topic or a theoretical programming concept.</p>
<p>It is used to structure real software systems.</p>
<p>For example, an e-commerce system might contain classes such as:</p>
<pre><code class="language-text">User
Product
Cart
Order
Payment
Inventory
Delivery
</code></pre>
<p>A banking system might contain:</p>
<pre><code class="language-text">Customer
Account
SavingsAccount
Loan
Transaction
Payment
ATM
</code></pre>
<p>A ride-booking application might contain:</p>
<pre><code class="language-text">User
Driver
Passenger
Ride
Vehicle
Payment
Location
</code></pre>
<p>A hospital management system might contain:</p>
<pre><code class="language-text">Patient
Doctor
Appointment
Prescription
Billing
Hospital
</code></pre>
<p>The exact architecture depends on the company, programming language, and system design, but the idea of modeling related data and behavior using objects is widely used.</p>
<hr />
<h1>OOP in One Sentence</h1>
<p>If you remember only one thing:</p>
<blockquote>
<p><strong>OOP is a way of organizing programs using objects that combine data and behavior, making code easier to organize, reuse, maintain, and extend.</strong></p>
</blockquote>
<p>And the four pillars are:</p>
<p><strong>Encapsulation → Protect</strong></p>
<p><strong>Inheritance → Reuse</strong></p>
<p><strong>Polymorphism → Many forms</strong></p>
<p><strong>Abstraction → Hide complexity</strong></p>
<hr />
<h1>Final Takeaway</h1>
<p>OOP may look complicated at first because there are many new terms.</p>
<p>But the basic idea is simple:</p>
<pre><code class="language-text">Class
  ↓
Object
  ↓
Data + Behavior
  ↓
Organized Code
</code></pre>
<p>Then we use the four major OOP concepts:</p>
<pre><code class="language-text">Encapsulation → Protect and control data
Inheritance   → Reuse common behavior
Polymorphism  → Different behavior through a common interface
Abstraction   → Hide unnecessary implementation details
</code></pre>
<h3>A simple memory trick</h3>
<p>Think about a <strong>banking application</strong>:</p>
<pre><code class="language-text">             OOP
              │
     ┌────────┼─────────┐
     ↓        ↓         ↓
   Data    Behavior   Objects
     │        │         │
     └────────┴─────────┘
              │
       Four Pillars
              │
   ┌──────────┼───────────┐
   ↓          ↓           ↓          ↓
Encapsulation Inheritance Polymorphism Abstraction
   ↓          ↓           ↓          ↓
 Protect      Reuse       Different   Hide
 data         code        behavior    complexity
</code></pre>
<p>Once you understand these four concepts with <strong>real-world examples + small programs</strong>, OOP becomes much easier to understand and explain in interviews.</p>
<p>The key is not to memorize definitions.</p>
<p>Instead, ask yourself:</p>
<blockquote>
<p><strong>What is the object? What data does it have? What can it do? How should that data be protected? Can behavior be reused or changed? What implementation details can be hidden?</strong></p>
</blockquote>
<p>That way of thinking will help you understand OOP rather than simply memorizing it.</p>
]]></content:encoded></item><item><title><![CDATA[Day 7 of My 30-Day DSA Journey - Sliding Window Pattern]]></title><description><![CDATA[Day 7 of my DSA journey with JavaScript focuses on one of the most useful array and string patterns: Sliding Window.
Today, I solved two LeetCode problems:

Maximum Average Subarray I

Maximum Number ]]></description><link>https://abi-blog.hashnode.dev/day-7-of-my-30-day-dsa-journey-sliding-window-pattern</link><guid isPermaLink="true">https://abi-blog.hashnode.dev/day-7-of-my-30-day-dsa-journey-sliding-window-pattern</guid><category><![CDATA[DSA]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Learning Journey]]></category><category><![CDATA[interview questions]]></category><category><![CDATA[coding interview]]></category><category><![CDATA[leetcode]]></category><category><![CDATA[sliding window]]></category><category><![CDATA[Solution]]></category><category><![CDATA[data structures]]></category><category><![CDATA[algorithms]]></category><category><![CDATA[dsapatterns]]></category><category><![CDATA[Problem Solving]]></category><dc:creator><![CDATA[Abirami Sri]]></dc:creator><pubDate>Tue, 08 Sep 2026 16:07:21 GMT</pubDate><content:encoded><![CDATA[<p>Day 7 of my DSA journey with JavaScript focuses on one of the most useful array and string patterns: <strong>Sliding Window</strong>.</p>
<p>Today, I solved two LeetCode problems:</p>
<ol>
<li><p>Maximum Average Subarray I</p>
</li>
<li><p>Maximum Number of Vowels in a Substring of Given Length</p>
</li>
</ol>
<p>Both problems use a <strong>fixed-size sliding window</strong>.</p>
<p>The main idea is simple: instead of calculating every window from scratch, we maintain the current window and update it by removing the element that leaves and adding the element that enters.</p>
<hr />
<h2>Problems Solved</h2>
<table>
<thead>
<tr>
<th>#</th>
<th>Problem</th>
<th>Pattern</th>
<th>Difficulty</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>Maximum Average Subarray I</td>
<td>Fixed Sliding Window</td>
<td>Easy</td>
</tr>
<tr>
<td>2</td>
<td>Maximum Number of Vowels in a Substring of Given Length</td>
<td>Fixed Sliding Window</td>
<td>Medium</td>
</tr>
</tbody></table>
<hr />
<h1>What is Sliding Window?</h1>
<p>Sliding Window is a technique used when we need to work with a <strong>continuous subarray or substring</strong>.</p>
<p>Instead of repeatedly calculating information for every possible window, we maintain a window and slide it across the array or string.</p>
<p>For example:</p>
<pre><code class="language-text">nums = [1, 2, 3, 4, 5]
k = 3
</code></pre>
<p>The windows are:</p>
<pre><code class="language-text">[1, 2, 3]
   [2, 3, 4]
      [3, 4, 5]
</code></pre>
<p>Instead of calculating the sum of each window from scratch:</p>
<pre><code class="language-text">1 + 2 + 3
2 + 3 + 4
3 + 4 + 5
</code></pre>
<p>we can reuse the previous sum.</p>
<p>For example:</p>
<pre><code class="language-text">Old window:
[1, 2, 3]
sum = 6

Remove 1
Add 4

New window:
[2, 3, 4]
sum = 6 - 1 + 4
sum = 9
</code></pre>
<p>This reduces unnecessary work.</p>
<hr />
<h1>1. Maximum Average Subarray I</h1>
<p><strong>LeetCode:</strong> 643</p>
<p><a href="https://leetcode.com/problems/maximum-average-subarray-i/?utm_source=chatgpt.com">Solve Maximum Average Subarray I on LeetCode</a></p>
<h2>Problem</h2>
<p>Given an integer array <code>nums</code> and an integer <code>k</code>, find the contiguous subarray of length <code>k</code> that has the maximum average value.</p>
<h2>Example</h2>
<pre><code class="language-text">Input:
nums = [1,12,-5,-6,50,3]
k = 4

Output:
12.75
</code></pre>
<p>The subarray is:</p>
<pre><code class="language-text">[12,-5,-6,50]
</code></pre>
<p>Its sum is:</p>
<pre><code class="language-text">12 + (-5) + (-6) + 50 = 51
</code></pre>
<p>Average:</p>
<pre><code class="language-text">51 / 4 = 12.75
</code></pre>
<hr />
<h2>Approach</h2>
<p>Since every subarray must have exactly <code>k</code> elements, we can use a <strong>fixed-size sliding window</strong>.</p>
<h3>Step 1</h3>
<p>Calculate the sum of the first <code>k</code> elements.</p>
<pre><code class="language-text">[1,12,-5,-6]
</code></pre>
<h3>Step 2</h3>
<p>Store this as the initial maximum sum.</p>
<h3>Step 3</h3>
<p>Slide the window one position at a time.</p>
<p>When the window moves:</p>
<ul>
<li><p>Remove the element leaving the window.</p>
</li>
<li><p>Add the new element entering the window.</p>
</li>
<li><p>Update the maximum sum.</p>
</li>
</ul>
<p>Finally:</p>
<pre><code class="language-text">maximum average = maximum sum / k
</code></pre>
<hr />
<h2>Code</h2>
<pre><code class="language-javascript">var findMaxAverage = function (nums, k) {
    let sum = 0;

    // Calculate the first window
    for (let i = 0; i &lt; k; i++) {
        sum += nums[i];
    }

    let maxSum = sum;

    // Slide the window
    for (let i = k; i &lt; nums.length; i++) {
        sum = sum - nums[i - k] + nums[i];

        maxSum = Math.max(maxSum, sum);
    }

    return maxSum / k;
};
</code></pre>
<hr />
<h2>How It Works</h2>
<p>Consider:</p>
<pre><code class="language-text">nums = [1,12,-5,-6,50,3]
k = 4
</code></pre>
<p>First window:</p>
<pre><code class="language-text">[1,12,-5,-6]

sum = 1 + 12 - 5 - 6
    = 2
</code></pre>
<p>So:</p>
<pre><code class="language-text">maxSum = 2
</code></pre>
<p>Now slide the window.</p>
<p>Remove:</p>
<pre><code class="language-text">1
</code></pre>
<p>Add:</p>
<pre><code class="language-text">50
</code></pre>
<p>New window:</p>
<pre><code class="language-text">[12,-5,-6,50]
</code></pre>
<p>New sum:</p>
<pre><code class="language-text">2 - 1 + 50
= 51
</code></pre>
<p>Update:</p>
<pre><code class="language-text">maxSum = 51
</code></pre>
<p>Next window:</p>
<pre><code class="language-text">[-5,-6,50,3]
</code></pre>
<p>Update:</p>
<pre><code class="language-text">51 - 12 + 3
= 42
</code></pre>
<p>The maximum sum remains:</p>
<pre><code class="language-text">51
</code></pre>
<p>Therefore:</p>
<pre><code class="language-text">51 / 4 = 12.75
</code></pre>
<hr />
<h2>Complexity</h2>
<pre><code class="language-text">Time:  O(n)
Space: O(1)
</code></pre>
<p>We visit each element essentially once.</p>
<hr />
<h1>2. Maximum Number of Vowels in a Substring of Given Length</h1>
<p><strong>LeetCode:</strong> 1456</p>
<p><a href="https://leetcode.com/problems/maximum-number-of-vowels-in-a-substring-of-given-length/?utm_source=chatgpt.com">Solve Maximum Number of Vowels in a Substring of Given Length on LeetCode</a></p>
<h2>Problem</h2>
<p>Given a string <code>s</code> and an integer <code>k</code>, find the maximum number of vowels in any substring of length <code>k</code>.</p>
<p>The vowels are:</p>
<pre><code class="language-text">a, e, i, o, u
</code></pre>
<h2>Example</h2>
<pre><code class="language-text">Input:
s = "abciiidef"
k = 3

Output:
3
</code></pre>
<p>The substring:</p>
<pre><code class="language-text">"iii"
</code></pre>
<p>contains 3 vowels.</p>
<hr />
<h2>Approach</h2>
<p>Again, we use a <strong>fixed-size sliding window</strong>.</p>
<p>Instead of calculating the number of vowels in every substring separately, maintain the vowel count of the current window.</p>
<p>When the window moves:</p>
<ol>
<li><p>Check the character leaving the window.</p>
</li>
<li><p>If it is a vowel, decrease the count.</p>
</li>
<li><p>Check the new character entering the window.</p>
</li>
<li><p>If it is a vowel, increase the count.</p>
</li>
<li><p>Update the maximum.</p>
</li>
</ol>
<hr />
<h2>Code</h2>
<pre><code class="language-javascript">var maxVowels = function(s, k) {
    let vowels = new Set(['a', 'e', 'i', 'o', 'u']);

    let count = 0;

    // Count vowels in the first window
    for (let i = 0; i &lt; k; i++) {
        if (vowels.has(s[i])) {
            count++;
        }
    }

    let maxCount = count;

    // Slide the window
    for (let i = k; i &lt; s.length; i++) {
        // Remove the character leaving the window
        if (vowels.has(s[i - k])) {
            count--;
        }

        // Add the character entering the window
        if (vowels.has(s[i])) {
            count++;
        }

        maxCount = Math.max(maxCount, count);
    }

    return maxCount;
};
</code></pre>
<hr />
<h2>How It Works</h2>
<p>Consider:</p>
<pre><code class="language-text">s = "abciiidef"
k = 3
</code></pre>
<p>First window:</p>
<pre><code class="language-text">"abc"
</code></pre>
<p>Vowels:</p>
<pre><code class="language-text">a → 1
</code></pre>
<p>So:</p>
<pre><code class="language-text">count = 1
maxCount = 1
</code></pre>
<p>Move the window:</p>
<pre><code class="language-text">"bci"
</code></pre>
<p>The character leaving:</p>
<pre><code class="language-text">a
</code></pre>
<p>is a vowel.</p>
<p>So:</p>
<pre><code class="language-text">count--
</code></pre>
<p>The character entering:</p>
<pre><code class="language-text">i
</code></pre>
<p>is a vowel.</p>
<p>So:</p>
<pre><code class="language-text">count++
</code></pre>
<p>The new count is:</p>
<pre><code class="language-text">1
</code></pre>
<p>Continue sliding.</p>
<p>Eventually we get:</p>
<pre><code class="language-text">"iii"
</code></pre>
<p>which contains:</p>
<pre><code class="language-text">3 vowels
</code></pre>
<p>Therefore:</p>
<pre><code class="language-text">maxCount = 3
</code></pre>
<hr />
<h2>Why Use a Set?</h2>
<p>I used a JavaScript <code>Set</code> to store the vowels:</p>
<pre><code class="language-javascript">let vowels = new Set(['a', 'e', 'i', 'o', 'u']);
</code></pre>
<p>Then we can check whether a character is a vowel using:</p>
<pre><code class="language-javascript">vowels.has(s[i])
</code></pre>
<p>This makes the vowel-checking logic clean and easy to understand.</p>
<hr />
<h2>Complexity</h2>
<pre><code class="language-text">Time:  O(n)
Space: O(1)
</code></pre>
<p>The Set contains only 5 vowels, so its size is constant.</p>
<hr />
<h1>Fixed-Size Sliding Window</h1>
<p>Today's two problems follow almost the same structure.</p>
<p>The general pattern is:</p>
<pre><code class="language-javascript">// 1. Build the first window

// 2. Store the current result

// 3. Slide the window

// 4. Remove the element leaving

// 5. Add the element entering

// 6. Update the result
</code></pre>
<p>Visually:</p>
<pre><code class="language-text">[ a b c ] d e
  ↓
a [ b c d ] e
  ↓
a b [ c d e ]
</code></pre>
<p>The window always contains exactly <code>k</code> elements.</p>
<hr />
<h1>Why Sliding Window Is Better</h1>
<p>Suppose:</p>
<pre><code class="language-text">n = 1000
k = 100
</code></pre>
<p>A brute-force solution might calculate the information for every window again.</p>
<p>Sliding Window avoids that repeated work.</p>
<p>Instead of:</p>
<pre><code class="language-text">Calculate window
Calculate next window from scratch
Calculate next window from scratch
...
</code></pre>
<p>we do:</p>
<pre><code class="language-text">Current window
     ↓
Remove outgoing element
     ↓
Add incoming element
     ↓
Next window
</code></pre>
<p>This often changes the solution from <strong>O(n × k)</strong> to <strong>O(n)</strong>.</p>
<hr />
<h1>Pattern Recognition</h1>
<p>When should I think about Sliding Window?</p>
<p>Look for clues such as:</p>
<ul>
<li><p>Contiguous subarray</p>
</li>
<li><p>Substring</p>
</li>
<li><p>Window of size <code>k</code></p>
</li>
<li><p>Maximum/minimum in a fixed-length range</p>
</li>
<li><p>Count/sum inside a continuous range</p>
</li>
<li><p>Longest/shortest substring or subarray</p>
</li>
<li><p>Need to examine consecutive elements</p>
</li>
</ul>
<p>A particularly strong clue is:</p>
<blockquote>
<p><strong>"Find something in every subarray/substring of size k."</strong></p>
</blockquote>
<p>That should immediately make me think:</p>
<pre><code class="language-text">Fixed-Size Sliding Window
</code></pre>
<hr />
<h1>What I Learned Today</h1>
<p>Today I learned that Sliding Window is mainly about <strong>reusing the previous window's work</strong>.</p>
<p>Instead of recalculating everything:</p>
<pre><code class="language-text">Old Window
    ↓
Remove one element
    ↓
Add one element
    ↓
New Window
</code></pre>
<p>I also learned that the same pattern can work with different types of information:</p>
<h3>Sum</h3>
<p>Used in:</p>
<p><strong>Maximum Average Subarray I</strong></p>
<pre><code class="language-text">sum = sum - outgoing + incoming
</code></pre>
<h3>Count</h3>
<p>Used in:</p>
<p><strong>Maximum Number of Vowels</strong></p>
<pre><code class="language-text">count = count - outgoing + incoming
</code></pre>
<p>So the underlying pattern stays the same even though the calculation changes.</p>
<hr />
<h1>Day 7 Summary</h1>
<p>Today I solved:</p>
<pre><code class="language-text">643  → Maximum Average Subarray I
1456 → Maximum Number of Vowels in a Substring of Given Length
</code></pre>
<p>Main pattern:</p>
<pre><code class="language-text">Fixed-Size Sliding Window
</code></pre>
<p>The most important formula I learned today is:</p>
<pre><code class="language-text">New Window
= Old Window
- Element Leaving
+ Element Entering
</code></pre>
<hr />
<h1>Key Takeaway</h1>
<blockquote>
<p><strong>When a problem asks you to examine every contiguous subarray or substring of a fixed size, think Sliding Window before using nested loops.</strong></p>
</blockquote>
<p>Day 7 complete.</p>
]]></content:encoded></item><item><title><![CDATA[Day 6 of My 30-Day DSA Journey  — Two Pointers & Array Patterns]]></title><description><![CDATA[Day 6 of my DSA journey focuses on the Two Pointers pattern and how it can be used to solve different types of array and string problems efficiently.
Today, I solved 5 LeetCode problems:

Container Wi]]></description><link>https://abi-blog.hashnode.dev/day-6-of-my-30-day-dsa-journey-two-pointers-array-patterns</link><guid isPermaLink="true">https://abi-blog.hashnode.dev/day-6-of-my-30-day-dsa-journey-two-pointers-array-patterns</guid><category><![CDATA[DSA]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[problem solving skills]]></category><category><![CDATA[leetcode]]></category><category><![CDATA[two pointers]]></category><category><![CDATA[algorithms]]></category><category><![CDATA[data structures]]></category><category><![CDATA[coding interview]]></category><category><![CDATA[coding challenge]]></category><category><![CDATA[dsapatterns]]></category><dc:creator><![CDATA[Abirami Sri]]></dc:creator><pubDate>Sun, 06 Sep 2026 15:40:46 GMT</pubDate><content:encoded><![CDATA[<p>Day 6 of my DSA journey focuses on the <strong>Two Pointers pattern</strong> and how it can be used to solve different types of array and string problems efficiently.</p>
<p>Today, I solved 5 LeetCode problems:</p>
<ol>
<li><p>Container With Most Water</p>
</li>
<li><p>Is Subsequence</p>
</li>
<li><p>Squares of a Sorted Array</p>
</li>
<li><p>3Sum</p>
</li>
<li><p>Trapping Rain Water</p>
</li>
</ol>
<p>These problems helped me understand how two pointers can reduce unnecessary nested loops and improve the efficiency of solutions.</p>
<hr />
<h2>Problems Solved</h2>
<table>
<thead>
<tr>
<th>#</th>
<th>Problem</th>
<th>Pattern</th>
<th>Difficulty</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>Container With Most Water</td>
<td>Two Pointers</td>
<td>Medium</td>
</tr>
<tr>
<td>2</td>
<td>Is Subsequence</td>
<td>Two Pointers</td>
<td>Easy</td>
</tr>
<tr>
<td>3</td>
<td>Squares of a Sorted Array</td>
<td>Two Pointers</td>
<td>Easy</td>
</tr>
<tr>
<td>4</td>
<td>3Sum</td>
<td>Sorting + Two Pointers</td>
<td>Medium</td>
</tr>
<tr>
<td>5</td>
<td>Trapping Rain Water</td>
<td>Prefix/Suffix Maximum</td>
<td>Hard</td>
</tr>
</tbody></table>
<hr />
<h1>1. Container With Most Water</h1>
<p><strong>LeetCode:</strong> 11</p>
<p><a href="https://leetcode.com/problems/container-with-most-water/?utm_source=chatgpt.com">Solve Container With Most Water on LeetCode</a></p>
<h2>Problem</h2>
<p>You are given an array <code>height</code>, where each element represents the height of a vertical line.</p>
<p>Choose two lines that together with the x-axis form a container that holds the most water.</p>
<p>The amount of water is:</p>
<pre><code class="language-text">min(height[i], height[j]) × (j - i)
</code></pre>
<h2>Example</h2>
<pre><code class="language-text">Input:
[1,8,6,2,5,4,8,3,7]

Output:
49
</code></pre>
<p>The maximum area is created by heights <code>8</code> and <code>7</code>.</p>
<pre><code class="language-text">min(8,7) × (8-1)
= 7 × 7
= 49
</code></pre>
<h2>Approach</h2>
<p>Start with two pointers:</p>
<pre><code class="language-text">left  → beginning
right → end
</code></pre>
<p>Calculate the area between them.</p>
<p>Then move the pointer pointing to the <strong>shorter height</strong>.</p>
<p>Why?</p>
<p>The width decreases every time we move a pointer.</p>
<p>So, to potentially get a larger area, we need to find a taller boundary.</p>
<h2>Code</h2>
<pre><code class="language-javascript">var maxArea = function(height) {
    let i = 0;
    let j = height.length - 1;
    let maxWater = 0;

    while (i &lt; j) {
        let area = Math.min(height[i], height[j]) * (j - i);

        maxWater = Math.max(maxWater, area);

        if (height[i] &gt; height[j]) {
            --j;
        } else {
            ++i;
        }
    }

    return maxWater;
};
</code></pre>
<h2>How It Works</h2>
<p>Suppose:</p>
<pre><code class="language-text">height = [1,8,6,2,5,4,8,3,7]
</code></pre>
<p>Initially:</p>
<pre><code class="language-text">i = 0
j = 8
</code></pre>
<p>We calculate:</p>
<pre><code class="language-text">min(1,7) × 8 = 8
</code></pre>
<p>Since <code>height[i]</code> is smaller, move <code>i</code>.</p>
<p>We continue this process until:</p>
<pre><code class="language-text">i &gt;= j
</code></pre>
<p>Throughout the process, <code>maxWater</code> stores the maximum area found.</p>
<h2>Complexity</h2>
<pre><code class="language-text">Time:  O(n)
Space: O(1)
</code></pre>
<h2>Pattern</h2>
<p><strong>Two Pointers</strong></p>
<h3>Key idea</h3>
<p>When the calculation depends on two ends of an array and one pointer can be safely moved based on a condition, think about <strong>Two Pointers</strong>.</p>
<hr />
<h1>2. Is Subsequence</h1>
<p><strong>LeetCode:</strong> 392</p>
<p><a href="https://leetcode.com/problems/is-subsequence/?utm_source=chatgpt.com">Solve Is Subsequence on LeetCode</a></p>
<h2>Problem</h2>
<p>Given two strings <code>s</code> and <code>t</code>, determine whether <code>s</code> is a subsequence of <code>t</code>.</p>
<p>A subsequence means the characters of <code>s</code> must appear in <code>t</code> <strong>in the same order</strong>, but they don't have to be next to each other.</p>
<h2>Example</h2>
<pre><code class="language-text">s = "abc"
t = "ahbgdc"

Output:
true
</code></pre>
<p>Because:</p>
<pre><code class="language-text">a → h → b → g → d → c
^       ^           ^
a       b           c
</code></pre>
<p>The characters <code>a</code>, <code>b</code>, and <code>c</code> appear in the correct order.</p>
<h2>Approach</h2>
<p>Use two pointers:</p>
<pre><code class="language-text">i → s
j → t
</code></pre>
<p>If:</p>
<pre><code class="language-javascript">s[i] === t[j]
</code></pre>
<p>we found the next required character, so move <code>i</code>.</p>
<p>Always move <code>j</code> because we are scanning through <code>t</code>.</p>
<p>At the end:</p>
<pre><code class="language-javascript">i === s.length
</code></pre>
<p>means every character in <code>s</code> was found.</p>
<h2>Code</h2>
<pre><code class="language-javascript">var isSubsequence = function(s, t) {
    let i = 0;
    let j = 0;

    while (j &lt; t.length) {
        if (s[i] === t[j]) {
            ++i;
        }

        ++j;
    }

    return i === s.length;
};
</code></pre>
<h2>How It Works</h2>
<p>Example:</p>
<pre><code class="language-text">s = "abc"
t = "ahbgdc"
</code></pre>
<p>We compare:</p>
<pre><code class="language-text">a == a → match → move i
b != h → move j
b == b → match → move i
c != g → move j
c != d → move j
c == c → match → move i
</code></pre>
<p>Now:</p>
<pre><code class="language-text">i === s.length
</code></pre>
<p>So the answer is:</p>
<pre><code class="language-text">true
</code></pre>
<h2>Complexity</h2>
<p>Let:</p>
<pre><code class="language-text">m = s.length
n = t.length
</code></pre>
<pre><code class="language-text">Time:  O(n)
Space: O(1)
</code></pre>
<h2>Pattern</h2>
<p><strong>Two Pointers</strong></p>
<p>This is a good example of using two pointers when comparing two sequences while maintaining their relative order.</p>
<hr />
<h1>3. Squares of a Sorted Array</h1>
<p><strong>LeetCode:</strong> 977</p>
<p><a href="https://leetcode.com/problems/squares-of-a-sorted-array/?utm_source=chatgpt.com">Solve Squares of a Sorted Array on LeetCode</a></p>
<h2>Problem</h2>
<p>Given a sorted array containing negative and positive integers, return an array containing the squares of every number, also sorted in non-decreasing order.</p>
<h2>Example</h2>
<pre><code class="language-text">Input:
[-4,-1,0,3,10]

Output:
[0,1,9,16,100]
</code></pre>
<h2>The Challenge</h2>
<p>Although the original array is sorted:</p>
<pre><code class="language-text">[-4,-1,0,3,10]
</code></pre>
<p>after squaring:</p>
<pre><code class="language-text">[16,1,0,9,100]
</code></pre>
<p>it is no longer sorted.</p>
<p>The largest square can come from either:</p>
<ul>
<li><p>the left side because of a large negative number</p>
</li>
<li><p>the right side because of a large positive number</p>
</li>
</ul>
<h2>Approach</h2>
<p>Use two pointers:</p>
<pre><code class="language-text">left  → beginning
right → end
</code></pre>
<p>Compare:</p>
<pre><code class="language-javascript">nums[left]²
nums[right]²
</code></pre>
<p>The larger square belongs at the <strong>end</strong> of the result array.</p>
<p>So we fill the result from right to left.</p>
<h2>Code</h2>
<pre><code class="language-javascript">var sortedSquares = function(nums) {
    let n = nums.length;
    let res = [];

    let left = 0;
    let right = n - 1;
    let x = n - 1;

    while (left &lt;= right) {
        let leftSq = nums[left] * nums[left];
        let rightSq = nums[right] * nums[right];

        if (leftSq &gt; rightSq) {
            res[x] = leftSq;
            left++;
        } else {
            res[x] = rightSq;
            right--;
        }

        x--;
    }

    return res;
};
</code></pre>
<h2>How It Works</h2>
<p>For:</p>
<pre><code class="language-text">[-4,-1,0,3,10]
</code></pre>
<p>Compare the two ends:</p>
<pre><code class="language-text">(-4)² = 16
10²   = 100
</code></pre>
<p>100 is larger, so:</p>
<pre><code class="language-text">res[4] = 100
</code></pre>
<p>Move <code>right</code>.</p>
<p>Then compare again.</p>
<p>We continue filling:</p>
<pre><code class="language-text">[0,1,9,16,100]
</code></pre>
<p>from right to left.</p>
<h2>Complexity</h2>
<pre><code class="language-text">Time:  O(n)
Space: O(n)
</code></pre>
<p>The result array itself requires <code>O(n)</code> space.</p>
<h2>Pattern</h2>
<p><strong>Two Pointers + Sorted Array</strong></p>
<h3>Key observation</h3>
<p>When an array is sorted and you need to compare the largest values from both ends, check whether <strong>Two Pointers</strong> can avoid sorting again.</p>
<hr />
<h1>4. 3Sum</h1>
<p><strong>LeetCode:</strong> 15</p>
<p><a href="https://leetcode.com/problems/3sum/?utm_source=chatgpt.com">Solve 3Sum on LeetCode</a></p>
<h2>Problem</h2>
<p>Given an integer array <code>nums</code>, find all unique triplets:</p>
<pre><code class="language-text">[a, b, c]
</code></pre>
<p>such that:</p>
<pre><code class="language-text">a + b + c = 0
</code></pre>
<p>The solution should not contain duplicate triplets.</p>
<h2>Example</h2>
<pre><code class="language-text">Input:
[-1,0,1,2,-1,-4]

Output:
[[-1,-1,2],[-1,0,1]]
</code></pre>
<h2>Approach</h2>
<p>The important idea is:</p>
<p><strong>Sort the array first.</strong></p>
<p>For example:</p>
<pre><code class="language-text">[-1,0,1,2,-1,-4]
</code></pre>
<p>becomes:</p>
<pre><code class="language-text">[-4,-1,-1,0,1,2]
</code></pre>
<p>Then:</p>
<ol>
<li><p>Fix one number.</p>
</li>
<li><p>Use two pointers for the remaining part.</p>
</li>
<li><p>Move the pointers depending on the sum.</p>
</li>
<li><p>Skip duplicates.</p>
</li>
</ol>
<p>So the problem becomes:</p>
<pre><code class="language-text">One fixed pointer + Two Pointers
</code></pre>
<h2>Code</h2>
<pre><code class="language-javascript">var threeSum = function(nums) {
    nums.sort((a, b) =&gt; a - b);

    let ans = [];

    for (let i = 0; i &lt; nums.length; i++) {
        if (i === 0 || nums[i] !== nums[i - 1]) {
            twoSum(nums, i, ans);
        }
    }

    return ans;
};

var twoSum = function(arr, x, ans) {
    let i = x + 1;
    let j = arr.length - 1;

    while (i &lt; j) {
        let sum = arr[x] + arr[i] + arr[j];

        if (sum &gt; 0) {
            j--;
        } else if (sum &lt; 0) {
            i++;
        } else {
            ans.push([arr[x], arr[i], arr[j]]);

            i++;
            j--;

            while (i &lt; j &amp;&amp; arr[i] === arr[i - 1]) {
                i++;
            }
        }
    }
};
</code></pre>
<h2>How It Works</h2>
<p>After sorting:</p>
<pre><code class="language-text">[-4,-1,-1,0,1,2]
</code></pre>
<p>Suppose:</p>
<pre><code class="language-text">arr[x] = -1
</code></pre>
<p>Now use two pointers:</p>
<pre><code class="language-text">i → next element
j → last element
</code></pre>
<p>Calculate:</p>
<pre><code class="language-text">-1 + arr[i] + arr[j]
</code></pre>
<h3>If sum &lt; 0</h3>
<p>We need a larger value.</p>
<p>Move:</p>
<pre><code class="language-text">i++
</code></pre>
<h3>If sum &gt; 0</h3>
<p>We need a smaller value.</p>
<p>Move:</p>
<pre><code class="language-text">j--
</code></pre>
<h3>If sum === 0</h3>
<p>We found a valid triplet.</p>
<p>Then move both pointers and skip duplicates.</p>
<h2>Why Sorting Is Important</h2>
<p>Sorting makes two things possible:</p>
<h3>1. Two-pointer movement</h3>
<p>Because the values are ordered, we know which pointer to move based on the sum.</p>
<h3>2. Duplicate handling</h3>
<p>For example:</p>
<pre><code class="language-text">[-1,-1,0,1]
</code></pre>
<p>If we process both <code>-1</code>s as starting points, we may generate duplicate triplets.</p>
<p>So we skip repeated values:</p>
<pre><code class="language-javascript">if (i === 0 || nums[i] !== nums[i - 1])
</code></pre>
<h2>Complexity</h2>
<p>Sorting:</p>
<pre><code class="language-text">O(n log n)
</code></pre>
<p>Two-pointer search for each element:</p>
<pre><code class="language-text">O(n²)
</code></pre>
<p>Overall:</p>
<pre><code class="language-text">Time:  O(n²)
Space: O(log n)*
</code></pre>
<p><code>O(log n)</code> is the typical auxiliary space associated with the JavaScript sorting implementation for the in-place sort, though the exact implementation-dependent stack usage can vary.</p>
<p>The returned answer itself requires additional space proportional to the number of triplets.</p>
<h2>Pattern</h2>
<p><strong>Sorting + Two Pointers</strong></p>
<p>This is an important pattern:</p>
<pre><code class="language-text">3Sum
   ↓
Sort
   ↓
Fix one element
   ↓
Two Pointers
</code></pre>
<hr />
<h1>5. Trapping Rain Water</h1>
<p><strong>LeetCode:</strong> 42</p>
<p><a href="https://leetcode.com/problems/trapping-rain-water/?utm_source=chatgpt.com">Solve Trapping Rain Water on LeetCode</a></p>
<h2>Problem</h2>
<p>Given an array representing an elevation map, calculate how much rainwater can be trapped after raining.</p>
<h2>Example</h2>
<pre><code class="language-text">Input:
[0,1,0,2,1,0,1,3,2,1,2,1]

Output:
6
</code></pre>
<h2>Key Idea</h2>
<p>For every position, the amount of water it can hold depends on:</p>
<pre><code class="language-text">minimum(
    maximum height on the left,
    maximum height on the right
)
- current height
</code></pre>
<p>Formula:</p>
<pre><code class="language-text">water[i] =
min(maxL[i], maxR[i]) - height[i]
</code></pre>
<p>If the result is negative, we don't add water.</p>
<hr />
<h2>Approach</h2>
<p>Create two arrays:</p>
<pre><code class="language-text">maxL
maxR
</code></pre>
<h3>maxL</h3>
<p><code>maxL[i]</code> stores the maximum height from the left up to index <code>i</code>.</p>
<h3>maxR</h3>
<p><code>maxR[i]</code> stores the maximum height from the right up to index <code>i</code>.</p>
<p>Then calculate:</p>
<pre><code class="language-text">min(maxL[i], maxR[i]) - height[i]
</code></pre>
<p>for every position.</p>
<h2>Code</h2>
<pre><code class="language-javascript">var trap = function(height) {
    let n = height.length;

    let maxL = [];
    maxL[0] = height[0];

    let maxR = [];
    maxR[n - 1] = height[n - 1];

    for (let i = 1; i &lt; n; i++) {
        maxL[i] = Math.max(maxL[i - 1], height[i]);

        maxR[n - 1 - i] =
            Math.max(maxR[n - i], height[n - 1 - i]);
    }

    let ans = 0;

    for (let i = 0; i &lt; n; i++) {
        ans += Math.max(
            Math.min(maxL[i], maxR[i]) - height[i],
            0
        );
    }

    return ans;
};
</code></pre>
<h2>How It Works</h2>
<p>Consider:</p>
<pre><code class="language-text">[4,2,0,3,2,5]
</code></pre>
<p>At index <code>2</code>:</p>
<pre><code class="language-text">height = 0
</code></pre>
<p>Maximum height on the left:</p>
<pre><code class="language-text">4
</code></pre>
<p>Maximum height on the right:</p>
<pre><code class="language-text">5
</code></pre>
<p>The smaller boundary is:</p>
<pre><code class="language-text">min(4,5) = 4
</code></pre>
<p>Therefore:</p>
<pre><code class="language-text">water = 4 - 0
      = 4
</code></pre>
<p>The same calculation is performed for every position.</p>
<h2>Complexity</h2>
<pre><code class="language-text">Time:  O(n)
Space: O(n)
</code></pre>
<p>We use two additional arrays:</p>
<pre><code class="language-text">maxL
maxR
</code></pre>
<hr />
<h1>What I Learned Today</h1>
<p>Day 6 helped me understand that the <strong>Two Pointers pattern is not limited to simple left-right traversal</strong>.</p>
<p>I learned several variations:</p>
<h3>1. Two pointers from opposite ends</h3>
<p>Used in:</p>
<ul>
<li><p>Container With Most Water</p>
</li>
<li><p>Squares of a Sorted Array</p>
</li>
</ul>
<h3>2. Two pointers across two sequences</h3>
<p>Used in:</p>
<ul>
<li>Is Subsequence</li>
</ul>
<h3>3. Fixed pointer + two pointers</h3>
<p>Used in:</p>
<ul>
<li>3Sum</li>
</ul>
<h3>4. Prefix and suffix maximums</h3>
<p>Used in:</p>
<ul>
<li>Trapping Rain Water</li>
</ul>
<hr />
<h1>Pattern Recognition</h1>
<p>One of the biggest things I am learning from solving DSA problems is that the main challenge is not always writing the code.</p>
<p>The important question is:</p>
<blockquote>
<p><strong>What pattern does this problem belong to?</strong></p>
</blockquote>
<p>Today, I noticed these clues:</p>
<table>
<thead>
<tr>
<th>Problem clue</th>
<th>Possible pattern</th>
</tr>
</thead>
<tbody><tr>
<td>Sorted array + compare both ends</td>
<td>Two Pointers</td>
</tr>
<tr>
<td>Need to preserve sequence/order</td>
<td>Two Pointers</td>
</tr>
<tr>
<td>Find triplets in a sorted array</td>
<td>Sorting + Two Pointers</td>
</tr>
<tr>
<td>Need maximum on left and right</td>
<td>Prefix/Suffix Maximum</td>
</tr>
<tr>
<td>Array values are increasing/decreasing</td>
<td>Two Pointers may help</td>
</tr>
<tr>
<td>Avoid checking every pair/triplet</td>
<td>Look for pointer-based optimization</td>
</tr>
</tbody></table>
<hr />
<h1>Day 6 Summary</h1>
<p>Today I solved:</p>
<pre><code class="language-text">11   → Container With Most Water
392  → Is Subsequence
977  → Squares of a Sorted Array
15   → 3Sum
42   → Trapping Rain Water
</code></pre>
<p>The major patterns were:</p>
<pre><code class="language-text">Two Pointers
     ↓
Sorting + Two Pointers
     ↓
Prefix/Suffix Maximum
</code></pre>
<p>The biggest takeaway from today is that <strong>Two Pointers is a technique, not just one fixed algorithm</strong>.</p>
<p>Depending on the problem, the pointers can:</p>
<ul>
<li><p>Start from both ends</p>
</li>
<li><p>Move through two different sequences</p>
</li>
<li><p>Work around a fixed element</p>
</li>
<li><p>Build a result from either direction</p>
</li>
</ul>
<hr />
<h1>Key Takeaway</h1>
<blockquote>
<p><strong>Before writing nested loops, ask yourself: Can two pointers reduce the number of comparisons?</strong></p>
</blockquote>
<p>Day 6 complete.</p>
]]></content:encoded></item><item><title><![CDATA[Day 5 of My 30-Day DSA Journey — Two Pointers]]></title><description><![CDATA[Day 5 of my 30 Days of DSA with JavaScript journey.
Today, I learned and practiced the Two Pointers pattern.
The two-pointer technique uses two indexes to traverse an array or string efficiently. Depe]]></description><link>https://abi-blog.hashnode.dev/day-5-of-my-30-day-dsa-journey-two-pointers</link><guid isPermaLink="true">https://abi-blog.hashnode.dev/day-5-of-my-30-day-dsa-journey-two-pointers</guid><category><![CDATA[DSA]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[leetcode]]></category><category><![CDATA[patterns]]></category><category><![CDATA[two pointers]]></category><category><![CDATA[algorithms]]></category><category><![CDATA[data structures]]></category><category><![CDATA[Solution]]></category><dc:creator><![CDATA[Abirami Sri]]></dc:creator><pubDate>Sat, 05 Sep 2026 17:11:03 GMT</pubDate><content:encoded><![CDATA[<p>Day 5 of my 30 Days of DSA with JavaScript journey.</p>
<p>Today, I learned and practiced the <strong>Two Pointers</strong> pattern.</p>
<p>The two-pointer technique uses two indexes to traverse an array or string efficiently. Depending on the problem, the pointers can move:</p>
<ul>
<li><p>Toward each other</p>
</li>
<li><p>In the same direction</p>
</li>
<li><p>At different speeds</p>
</li>
</ul>
<p>Today I solved four problems using this pattern.</p>
<h2>Problems Solved</h2>
<table>
<thead>
<tr>
<th>LeetCode</th>
<th>Problem</th>
<th>Pattern</th>
</tr>
</thead>
<tbody><tr>
<td>125</td>
<td>Valid Palindrome</td>
<td>Two Pointers</td>
</tr>
<tr>
<td>283</td>
<td>Move Zeroes</td>
<td>Two Pointers</td>
</tr>
<tr>
<td>26</td>
<td>Remove Duplicates from Sorted Array</td>
<td>Two Pointers</td>
</tr>
<tr>
<td>167</td>
<td>Two Sum II - Input Array Is Sorted</td>
<td>Two Pointers</td>
</tr>
</tbody></table>
<hr />
<h1>1. Valid Palindrome</h1>
<h2>Problem</h2>
<p>Given a string <code>s</code>, determine whether it is a palindrome after converting uppercase letters to lowercase and removing all non-alphanumeric characters.</p>
<p>A palindrome reads the same forward and backward.</p>
<h2>Example</h2>
<pre><code class="language-text">Input:
"A man, a plan, a canal: Panama"

Output:
true
</code></pre>
<p>After removing spaces and punctuation and converting to lowercase:</p>
<pre><code class="language-text">amanaplanacanalpanama
</code></pre>
<p>It reads the same from both directions.</p>
<h2>Approach</h2>
<p>Use two pointers:</p>
<pre><code class="language-text">i → starts from the beginning
j → starts from the end
</code></pre>
<p>If the character at <code>i</code> is not alphanumeric, move <code>i</code>.</p>
<p>If the character at <code>j</code> is not alphanumeric, move <code>j</code>.</p>
<p>Otherwise, compare both characters.</p>
<p>If they are different, return <code>false</code>.</p>
<p>If they are the same, move both pointers toward the center.</p>
<h2>Code</h2>
<pre><code class="language-javascript">var isPalindrome = function (s) {
    s = s.toLowerCase();

    let i = 0;
    let j = s.length - 1;

    while (i &lt; j) {
        if (!s[i].match(/[a-z0-9]/i)) {
            i++;
        } else if (!s[j].match(/[a-z0-9]/i)) {
            j--;
        } else if (s[i] === s[j]) {
            i++;
            j--;
        } else {
            return false;
        }
    }

    return true;
};
</code></pre>
<h2>How It Works</h2>
<p>For:</p>
<pre><code class="language-text">"A man, a plan, a canal: Panama"
</code></pre>
<p>The pointers compare valid characters from both ends:</p>
<pre><code class="language-text">a ↔ a
m ↔ m
a ↔ a
n ↔ n
...
</code></pre>
<p>Whenever a space or punctuation is encountered, that pointer skips it.</p>
<p>If every valid character matches, the string is a palindrome.</p>
<h2>Complexity</h2>
<ul>
<li><p>Time: O(n)</p>
</li>
<li><p>Space: O(n)</p>
</li>
</ul>
<p>The space is O(n) here because <code>toLowerCase()</code> creates a new string in JavaScript.</p>
<h2>Pattern</h2>
<p>Two Pointers</p>
<hr />
<h1>2. Move Zeroes</h1>
<h2>Problem</h2>
<p>Given an integer array, move all <code>0</code>s to the end while maintaining the relative order of the non-zero elements.</p>
<p>The operation must be performed in-place.</p>
<h2>Example</h2>
<pre><code class="language-text">Input:
[0,1,0,3,12]

Output:
[1,3,12,0,0]
</code></pre>
<h2>Approach</h2>
<p>Use a pointer <code>x</code> to represent the position where the next non-zero element should be placed.</p>
<p>Traverse the array with <code>i</code>.</p>
<p>Whenever we find a non-zero value:</p>
<pre><code class="language-js">nums[x] = nums[i];
x++;
</code></pre>
<p>After moving all non-zero values, fill the remaining positions with zeroes.</p>
<h2>Code</h2>
<pre><code class="language-javascript">var moveZeroes = function (nums) {
    let x = 0;

    for (let i = 0; i &lt; nums.length; i++) {
        if (nums[i] !== 0) {
            nums[x] = nums[i];
            x++;
        }
    }

    for (let i = x; i &lt; nums.length; i++) {
        nums[i] = 0;
    }
};
</code></pre>
<h2>How It Works</h2>
<p>For:</p>
<pre><code class="language-text">[0,1,0,3,12]
</code></pre>
<p>Non-zero values are moved toward the beginning:</p>
<pre><code class="language-text">[1,3,12,3,12]
</code></pre>
<p>Then the remaining positions are replaced with zero:</p>
<pre><code class="language-text">[1,3,12,0,0]
</code></pre>
<p>The important idea is that <code>x</code> tracks where the next non-zero element belongs.</p>
<h2>Complexity</h2>
<ul>
<li><p>Time: O(n)</p>
</li>
<li><p>Space: O(1)</p>
</li>
</ul>
<h2>Pattern</h2>
<p>Two Pointers / In-place Array Modification</p>
<hr />
<h1>3. Remove Duplicates from Sorted Array</h1>
<h2>Problem</h2>
<p>Given a sorted array, remove duplicates in-place so that each unique element appears only once.</p>
<p>Return the number of unique elements.</p>
<h2>Example</h2>
<pre><code class="language-text">Input:
[1,1,2]

Output:
2

Array becomes:
[1,2,_]
</code></pre>
<h2>Approach</h2>
<p>Because the array is sorted, duplicate values are next to each other.</p>
<p>Use:</p>
<ul>
<li><p><code>i</code> to scan the array</p>
</li>
<li><p><code>x</code> to track the position of the last unique element</p>
</li>
</ul>
<p>Whenever:</p>
<pre><code class="language-js">nums[i] !== nums[x]
</code></pre>
<p>we have found a new unique value.</p>
<p>Move <code>x</code> forward and store the new value there.</p>
<h2>Code</h2>
<pre><code class="language-javascript">var removeDuplicates = function (nums) {
    let x = 0;

    for (let i = 0; i &lt; nums.length; i++) {
        if (nums[i] !== nums[x]) {
            x++;
            nums[x] = nums[i];
        }
    }

    return x + 1;
};
</code></pre>
<h2>How It Works</h2>
<p>For:</p>
<pre><code class="language-text">[1,1,2,2,3]
</code></pre>
<p>Initially:</p>
<pre><code class="language-text">x = 0
</code></pre>
<p><code>1</code> is already at the correct position.</p>
<p>When we find <code>2</code>:</p>
<pre><code class="language-text">x = 1
nums[1] = 2
</code></pre>
<p>When we find <code>3</code>:</p>
<pre><code class="language-text">x = 2
nums[2] = 3
</code></pre>
<p>The beginning of the array becomes:</p>
<pre><code class="language-text">[1,2,3,...]
</code></pre>
<p>So the number of unique elements is:</p>
<pre><code class="language-text">x + 1 = 3
</code></pre>
<h2>Complexity</h2>
<ul>
<li><p>Time: O(n)</p>
</li>
<li><p>Space: O(1)</p>
</li>
</ul>
<h2>Pattern</h2>
<p>Two Pointers / Slow and Fast Pointer</p>
<hr />
<h1>4. Two Sum II - Input Array Is Sorted</h1>
<h2>Problem</h2>
<p>Given a 1-indexed array of integers that is already sorted in non-decreasing order, find two numbers that add up to a specific target.</p>
<p>Return their indices.</p>
<h2>Example</h2>
<pre><code class="language-text">Input:
numbers = [2,7,11,15]
target = 9

Output:
[1,2]
</code></pre>
<p>Because:</p>
<pre><code class="language-text">2 + 7 = 9
</code></pre>
<h2>Approach</h2>
<p>Since the array is sorted, use two pointers:</p>
<pre><code class="language-text">i → beginning
j → end
</code></pre>
<p>Calculate:</p>
<pre><code class="language-js">sum = nums[i] + nums[j]
</code></pre>
<p>There are three possibilities.</p>
<h3>If sum equals target</h3>
<p>Return the two indices.</p>
<h3>If sum is smaller than target</h3>
<p>Move <code>i</code> forward.</p>
<p>Why?</p>
<p>Because we need a larger sum, and the array is sorted.</p>
<h3>If sum is greater than target</h3>
<p>Move <code>j</code> backward.</p>
<p>Why?</p>
<p>Because we need a smaller sum.</p>
<h2>Code</h2>
<pre><code class="language-javascript">var twoSum = function (nums, target) {
    let i = 0;
    let j = nums.length - 1;

    while (i &lt; j) {
        let sum = nums[i] + nums[j];

        if (sum === target) {
            return [i + 1, j + 1];
        }

        if (sum &lt; target) {
            i++;
        } else {
            j--;
        }
    }

    return [];
};
</code></pre>
<h2>How It Works</h2>
<p>For:</p>
<pre><code class="language-text">numbers = [2,7,11,15]
target = 9
</code></pre>
<p>Initially:</p>
<pre><code class="language-text">i = 0 → 2
j = 3 → 15
</code></pre>
<p>Calculate:</p>
<pre><code class="language-text">2 + 15 = 17
</code></pre>
<p>Too large, so move <code>j</code>:</p>
<pre><code class="language-text">2 + 11 = 13
</code></pre>
<p>Still too large:</p>
<pre><code class="language-text">2 + 7 = 9
</code></pre>
<p>Target found.</p>
<p>Return:</p>
<pre><code class="language-text">[1,2]
</code></pre>
<h2>Why Does This Work?</h2>
<p>The array is sorted.</p>
<p>If:</p>
<pre><code class="language-text">nums[i] + nums[j] &lt; target
</code></pre>
<p>we need a larger value, so moving <code>i</code> right is useful.</p>
<p>If:</p>
<pre><code class="language-text">nums[i] + nums[j] &gt; target
</code></pre>
<p>we need a smaller value, so moving <code>j</code> left is useful.</p>
<p>This allows us to solve the problem without checking every pair.</p>
<h2>Complexity</h2>
<ul>
<li><p>Time: O(n)</p>
</li>
<li><p>Space: O(1)</p>
</li>
</ul>
<h2>Pattern</h2>
<p>Two Pointers</p>
<hr />
<h1>Understanding the Two Pointer Pattern</h1>
<p>There are different ways to use two pointers.</p>
<h2>1. Pointers Moving Toward Each Other</h2>
<p>Example:</p>
<pre><code class="language-text">Valid Palindrome
Two Sum II
</code></pre>
<pre><code class="language-text">i → → → 
← ← ← j
</code></pre>
<p>The pointers start at opposite ends and move toward the center.</p>
<h2>2. Pointers Moving in the Same Direction</h2>
<p>Example:</p>
<pre><code class="language-text">Move Zeroes
Remove Duplicates
</code></pre>
<p>One pointer scans the array while another pointer tracks where the next valid element should go.</p>
<p>This is sometimes described as the <strong>slow and fast pointer technique</strong>.</p>
<hr />
<h1>Pattern Recognition</h1>
<p>When should I think about Two Pointers?</p>
<p>Look for clues such as:</p>
<pre><code class="language-text">Sorted array
Palindrome
Pair of elements
In-place modification
Remove duplicates
Move elements
Compare elements from both ends
</code></pre>
<p>A useful mental checklist:</p>
<pre><code class="language-text">Is the input sorted?
        ↓
Can I avoid nested loops?
        ↓
Can two indexes represent the current state?
        ↓
Try Two Pointers
</code></pre>
<hr />
<h1>What I Learned Today</h1>
<h2>1. Two Pointers Can Reduce Nested Loops</h2>
<p>A brute-force pair search might use:</p>
<pre><code class="language-text">O(n²)
</code></pre>
<p>But when the array is sorted, two pointers can often reduce it to:</p>
<pre><code class="language-text">O(n)
</code></pre>
<h2>2. Sorted Data Gives Us Information</h2>
<p>In Two Sum II, the sorted order tells us which pointer to move.</p>
<p>This is an important problem-solving idea:</p>
<blockquote>
<p>Use the properties of the input to eliminate unnecessary work.</p>
</blockquote>
<h2>3. Two Pointers Are Useful for In-place Problems</h2>
<p>Move Zeroes and Remove Duplicates demonstrate how pointers can modify an array without creating another array.</p>
<h2>4. Pointer Movement Must Have a Reason</h2>
<p>Don't move a pointer randomly.</p>
<p>For every pointer movement, ask:</p>
<pre><code class="language-text">Why am I moving this pointer?
What information does this movement give me?
</code></pre>
<p>For example, in Two Sum II:</p>
<pre><code class="language-text">sum &lt; target
    ↓
Need a bigger value
    ↓
Move left pointer right
</code></pre>
<p>and:</p>
<pre><code class="language-text">sum &gt; target
    ↓
Need a smaller value
    ↓
Move right pointer left
</code></pre>
<h1>Day 5 Summary</h1>
<table>
<thead>
<tr>
<th>Problem</th>
<th>Pattern</th>
<th>Time</th>
<th>Space</th>
</tr>
</thead>
<tbody><tr>
<td>125. Valid Palindrome</td>
<td>Two Pointers</td>
<td>O(n)</td>
<td>O(n)</td>
</tr>
<tr>
<td>283. Move Zeroes</td>
<td>Two Pointers</td>
<td>O(n)</td>
<td>O(1)</td>
</tr>
<tr>
<td>26. Remove Duplicates</td>
<td>Two Pointers</td>
<td>O(n)</td>
<td>O(1)</td>
</tr>
<tr>
<td>167. Two Sum II</td>
<td>Two Pointers</td>
<td>O(n)</td>
<td>O(1)</td>
</tr>
</tbody></table>
<h1>Key Takeaway</h1>
<p>The biggest lesson from Day 5 is:</p>
<blockquote>
<p>Two pointers are not just about using two variables called <code>i</code> and <code>j</code>. The important part is understanding what each pointer represents and why it should move.</p>
</blockquote>
<p>Before using the pattern, ask:</p>
<ol>
<li><p>Is the data sorted?</p>
</li>
<li><p>Can I compare elements from both ends?</p>
</li>
<li><p>Can I use one pointer to scan and another to track a position?</p>
</li>
<li><p>Can pointer movement eliminate unnecessary comparisons?</p>
</li>
</ol>
<p>If the answer is yes, <strong>Two Pointers</strong> may be the right pattern.</p>
<p><strong>Day 5 / 30</strong></p>
]]></content:encoded></item><item><title><![CDATA[Day 4 of My 30-Day DSA Journey — Hashing Problems]]></title><description><![CDATA[Day 4 of my 30 Days of DSA with JavaScript journey.
Today, I continued practicing Hashing, Set, and Frequency Counting patterns.
The problems I solved today show how hash-based data structures can be ]]></description><link>https://abi-blog.hashnode.dev/day-4-of-my-30-day-dsa-journey-hashing-problems</link><guid isPermaLink="true">https://abi-blog.hashnode.dev/day-4-of-my-30-day-dsa-journey-hashing-problems</guid><category><![CDATA[DSA]]></category><category><![CDATA[leetcode]]></category><category><![CDATA[Hashing]]></category><category><![CDATA[frequency]]></category><category><![CDATA[#DSAJourney]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[algorithms]]></category><category><![CDATA[datastructure]]></category><dc:creator><![CDATA[Abirami Sri]]></dc:creator><pubDate>Thu, 03 Sep 2026 17:46:49 GMT</pubDate><content:encoded><![CDATA[<p>Day 4 of my 30 Days of DSA with JavaScript journey.</p>
<p>Today, I continued practicing <strong>Hashing, Set, and Frequency Counting</strong> patterns.</p>
<p>The problems I solved today show how hash-based data structures can be used for different purposes:</p>
<ul>
<li><p>Counting frequencies</p>
</li>
<li><p>Grouping similar elements</p>
</li>
<li><p>Detecting consecutive sequences</p>
</li>
<li><p>Tracking previously seen values</p>
</li>
<li><p>Validating rows, columns, and sub-boxes</p>
</li>
</ul>
<h2>Problems Solved</h2>
<table>
<thead>
<tr>
<th>LeetCode</th>
<th>Problem</th>
<th>Pattern</th>
</tr>
</thead>
<tbody><tr>
<td>169</td>
<td>Majority Element</td>
<td>Hashing + Frequency Counting</td>
</tr>
<tr>
<td>387</td>
<td>First Unique Character in a String</td>
<td>Hashing + Frequency Counting</td>
</tr>
<tr>
<td>49</td>
<td>Group Anagrams</td>
<td>Hashing + Sorting</td>
</tr>
<tr>
<td>128</td>
<td>Longest Consecutive Sequence</td>
<td>Hashing + Set</td>
</tr>
<tr>
<td>36</td>
<td>Valid Sudoku</td>
<td>Hashing + Set</td>
</tr>
</tbody></table>
<hr />
<h1>1. Majority Element</h1>
<h2>Problem</h2>
<p>Given an array <code>nums</code>, return the majority element.</p>
<p>The majority element is the element that appears more than <code>n / 2</code> times.</p>
<h2>Example</h2>
<pre><code class="language-text">Input:
[2,2,1,1,1,2,2]

Output:
2
</code></pre>
<p>The number <code>2</code> appears more than <code>n / 2</code> times.</p>
<h2>Approach</h2>
<p>Use a hash map to count the frequency of every number.</p>
<p>After building the frequency map, find the number with the highest frequency.</p>
<h2>Code</h2>
<pre><code class="language-javascript">var majorityElement = function (nums) {
    let map = new Map();

    for (let num of nums) {
        map.set(num, (map.get(num) || 0) + 1);
    }

    let majority = nums[0];
    let maxCount = 0;

    for (let [num, count] of map) {
        if (count &gt; maxCount) {
            maxCount = count;
            majority = num;
        }
    }

    return majority;
};
</code></pre>
<h2>How It Works</h2>
<p>For:</p>
<pre><code class="language-text">[2,2,1,1,1,2,2]
</code></pre>
<p>The frequency map becomes:</p>
<pre><code class="language-text">2 → 4
1 → 3
</code></pre>
<p>The element with the highest frequency is <code>2</code>.</p>
<h2>Complexity</h2>
<ul>
<li><p>Time: O(n)</p>
</li>
<li><p>Space: O(n)</p>
</li>
</ul>
<h2>Optimized Approach</h2>
<p>The problem can also be solved using the <strong>Boyer-Moore Voting Algorithm</strong>.</p>
<pre><code class="language-javascript">var majorityElement = function (nums) {
    let candidate = 0;
    let count = 0;

    for (let num of nums) {
        if (count === 0) {
            candidate = num;
        }

        if (num === candidate) {
            count++;
        } else {
            count--;
        }
    }

    return candidate;
};
</code></pre>
<h3>Complexity</h3>
<ul>
<li><p>Time: O(n)</p>
</li>
<li><p>Space: O(1)</p>
</li>
</ul>
<hr />
<h1>2. First Unique Character in a String</h1>
<h2>Problem</h2>
<p>Given a string <code>s</code>, find the first non-repeating character and return its index.</p>
<p>If no unique character exists, return <code>-1</code>.</p>
<h2>Example</h2>
<pre><code class="language-text">Input:
"leetcode"

Output:
0
</code></pre>
<p>The character <code>l</code> appears only once and is the first unique character.</p>
<h2>Approach</h2>
<p>Use a hash map to count the frequency of every character.</p>
<p>Then traverse the string again from left to right.</p>
<p>The first character whose frequency is <code>1</code> is the answer.</p>
<h2>Code</h2>
<pre><code class="language-javascript">var firstUniqChar = function (s) {
    let map = {};

    for (let char of s) {
        map[char] = (map[char] || 0) + 1;
    }

    for (let i = 0; i &lt; s.length; i++) {
        if (map[s[i]] === 1) {
            return i;
        }
    }

    return -1;
};
</code></pre>
<h2>How It Works</h2>
<p>For:</p>
<pre><code class="language-text">"leetcode"
</code></pre>
<p>The frequency map is:</p>
<pre><code class="language-text">l → 1
e → 3
t → 1
c → 1
o → 1
d → 1
</code></pre>
<p>We scan from left to right.</p>
<p><code>l</code> has a frequency of <code>1</code>, so we return index <code>0</code>.</p>
<h2>Complexity</h2>
<ul>
<li><p>Time: O(n)</p>
</li>
<li><p>Space: O(k)</p>
</li>
</ul>
<p>Where <code>k</code> is the number of distinct characters.</p>
<hr />
<h1>3. Group Anagrams</h1>
<h2>Problem</h2>
<p>Given an array of strings, group the anagrams together.</p>
<p>Two strings are anagrams if they contain the same characters with the same frequencies.</p>
<h2>Example</h2>
<pre><code class="language-javascript">Input:
["eat","tea","tan","ate","nat","bat"]

Output:
[
    ["eat","tea","ate"],
    ["tan","nat"],
    ["bat"]
]
</code></pre>
<h2>Approach</h2>
<p>The important observation is:</p>
<pre><code class="language-text">"eat"
"tea"
"ate"
</code></pre>
<p>If we sort the characters, all three become:</p>
<pre><code class="language-text">"aet"
</code></pre>
<p>So the sorted string can be used as the key in a hash map.</p>
<h2>Code</h2>
<pre><code class="language-javascript">var groupAnagrams = function (strs) {
    let map = {};

    for (let str of strs) {
        let sortedStr = str.split("").sort().join("");

        if (!map[sortedStr]) {
            map[sortedStr] = [str];
        } else {
            map[sortedStr].push(str);
        }
    }

    return Object.values(map);
};
</code></pre>
<h2>How It Works</h2>
<p>For:</p>
<pre><code class="language-text">["eat", "tea", "tan", "ate", "nat", "bat"]
</code></pre>
<p>The keys become:</p>
<pre><code class="language-text">eat → aet
tea → aet
tan → ant
ate → aet
nat → ant
bat → abt
</code></pre>
<p>The hash map becomes:</p>
<pre><code class="language-text">aet → ["eat", "tea", "ate"]
ant → ["tan", "nat"]
abt → ["bat"]
</code></pre>
<p>Then:</p>
<pre><code class="language-js">Object.values(map)
</code></pre>
<p>returns the grouped arrays.</p>
<h2>Complexity</h2>
<p>Let:</p>
<ul>
<li><p><code>n</code> = number of strings</p>
</li>
<li><p><code>k</code> = maximum length of a string</p>
</li>
</ul>
<p>Sorting each string takes <code>O(k log k)</code>.</p>
<p>Therefore:</p>
<ul>
<li><p>Time: O(n × k log k)</p>
</li>
<li><p>Space: O(n × k)</p>
</li>
</ul>
<h2>Pattern Recognition</h2>
<p>When you need to group anagrams, convert each string into a common representation.</p>
<pre><code class="language-text">eat → aet
tea → aet
ate → aet
</code></pre>
<p>The common representation becomes the hash map key.</p>
<hr />
<h1>4. Longest Consecutive Sequence</h1>
<h2>Problem</h2>
<p>Given an unsorted array of integers, find the length of the longest consecutive elements sequence.</p>
<p>The algorithm must run in O(n) time.</p>
<h2>Example</h2>
<pre><code class="language-text">Input:
[100,4,200,1,3,2]

Output:
4
</code></pre>
<p>The longest consecutive sequence is:</p>
<pre><code class="language-text">1 → 2 → 3 → 4
</code></pre>
<p>So the answer is <code>4</code>.</p>
<h2>Approach</h2>
<p>Put all numbers into a <code>Set</code>.</p>
<p>A number is the beginning of a sequence only if:</p>
<pre><code class="language-js">!set.has(num - 1)
</code></pre>
<p>For example:</p>
<pre><code class="language-text">1
</code></pre>
<p>is a starting point because <code>0</code> does not exist.</p>
<p>But:</p>
<pre><code class="language-text">2
</code></pre>
<p>is not a starting point because <code>1</code> exists.</p>
<p>From every starting number, keep checking:</p>
<pre><code class="language-text">num + 1
num + 2
num + 3
...
</code></pre>
<p>and count the sequence length.</p>
<h2>Code</h2>
<pre><code class="language-javascript">var longestConsecutive = function (nums) {
    let set = new Set(nums);
    let longest = 0;

    for (let num of set) {
        if (!set.has(num - 1)) {
            let curr = num;
            let count = 1;

            while (set.has(curr + 1)) {
                curr++;
                count++;
            }

            longest = Math.max(longest, count);
        }
    }

    return longest;
};
</code></pre>
<h2>How It Works</h2>
<p>For:</p>
<pre><code class="language-text">[100,4,200,1,3,2]
</code></pre>
<p>The set contains:</p>
<pre><code class="language-text">{100, 4, 200, 1, 3, 2}
</code></pre>
<p>Start with <code>1</code>.</p>
<p>Check:</p>
<pre><code class="language-text">0 → doesn't exist
</code></pre>
<p>So <code>1</code> is the beginning.</p>
<p>Then:</p>
<pre><code class="language-text">1 → 2 → 3 → 4
</code></pre>
<p>Count:</p>
<pre><code class="language-text">4
</code></pre>
<p>Then:</p>
<pre><code class="language-js">longest = 4;
</code></pre>
<h2>Why Do We Check <code>num - 1</code>?</h2>
<p>Suppose:</p>
<pre><code class="language-text">1, 2, 3, 4
</code></pre>
<p>If we start counting from every number, we would repeatedly scan the same sequence.</p>
<p>Instead:</p>
<pre><code class="language-js">if (!set.has(num - 1))
</code></pre>
<p>means:</p>
<blockquote>
<p>Only start counting if this number is the beginning of a sequence.</p>
</blockquote>
<p>Therefore:</p>
<pre><code class="language-text">1 → start
2 → don't start
3 → don't start
4 → don't start
</code></pre>
<p>This allows the solution to achieve expected O(n) time.</p>
<h2>Complexity</h2>
<ul>
<li><p>Time: O(n) expected</p>
</li>
<li><p>Space: O(n)</p>
</li>
</ul>
<hr />
<h1>5. Valid Sudoku</h1>
<h2>Problem</h2>
<p>Determine whether a partially filled 9 × 9 Sudoku board is valid.</p>
<p>A Sudoku board is valid if:</p>
<ul>
<li><p>Each row contains no repeated digit.</p>
</li>
<li><p>Each column contains no repeated digit.</p>
</li>
<li><p>Each 3 × 3 box contains no repeated digit.</p>
</li>
<li><p>Empty cells are represented by <code>.</code>.</p>
</li>
</ul>
<h2>Approach</h2>
<p>We need to keep track of three things:</p>
<pre><code class="language-text">Rows
Columns
3 × 3 Boxes
</code></pre>
<p>For each cell, check whether the value already exists in:</p>
<pre><code class="language-text">row
column
box
</code></pre>
<p>If it exists in any of them, the board is invalid.</p>
<p>Otherwise, add it to all three sets.</p>
<h2>Code</h2>
<pre><code class="language-javascript">var isValidSudoku = function (board) {
    let rows = Array.from({ length: 9 }, () =&gt; new Set());
    let columns = Array.from({ length: 9 }, () =&gt; new Set());
    let boxes = Array.from({ length: 9 }, () =&gt; new Set());

    for (let i = 0; i &lt; 9; i++) {
        for (let j = 0; j &lt; 9; j++) {
            let value = board[i][j];

            if (value === ".") {
                continue;
            }

            let boxIndex =
                Math.floor(i / 3) * 3 +
                Math.floor(j / 3);

            if (
                rows[i].has(value) ||
                columns[j].has(value) ||
                boxes[boxIndex].has(value)
            ) {
                return false;
            }

            rows[i].add(value);
            columns[j].add(value);
            boxes[boxIndex].add(value);
        }
    }

    return true;
};
</code></pre>
<h2>Understanding the Box Index</h2>
<p>The board has 9 boxes:</p>
<pre><code class="language-text">0 | 1 | 2
---------
3 | 4 | 5
---------
6 | 7 | 8
</code></pre>
<p>The formula is:</p>
<pre><code class="language-js">let boxIndex =
    Math.floor(i / 3) * 3 +
    Math.floor(j / 3);
</code></pre>
<p>For example:</p>
<pre><code class="language-text">i = 1
j = 4
</code></pre>
<p>Then:</p>
<pre><code class="language-text">Math.floor(1 / 3) = 0
Math.floor(4 / 3) = 1

0 × 3 + 1 = 1
</code></pre>
<p>So the cell belongs to box <code>1</code>.</p>
<h2>Complexity</h2>
<p>Because the Sudoku board is always 9 × 9:</p>
<ul>
<li><p>Time: O(1)</p>
</li>
<li><p>Space: O(1)</p>
</li>
</ul>
<p>For a generalized <code>n × n</code> board:</p>
<ul>
<li><p>Time: O(n²)</p>
</li>
<li><p>Space: O(n²)</p>
</li>
</ul>
<hr />
<h1>What I Learned Today</h1>
<h2>1. Hashing Is More Than Frequency Counting</h2>
<p>Hashing can be used for:</p>
<pre><code class="language-text">Frequency counting
Grouping
Fast lookup
Duplicate detection
Sequence detection
Validation
</code></pre>
<h2>2. Two-Pass Technique</h2>
<p>A useful pattern is:</p>
<pre><code class="language-text">First pass
    ↓
Collect information

Second pass
    ↓
Use that information to find the answer
</code></pre>
<p>We used this pattern in First Unique Character.</p>
<h2>3. Canonical Representation</h2>
<p>Group Anagrams taught me an important technique.</p>
<p>Different inputs can be converted into the same representation:</p>
<pre><code class="language-text">eat → aet
tea → aet
ate → aet
</code></pre>
<p>That common representation becomes the hash map key.</p>
<h2>4. Set for Fast Lookup</h2>
<p>Longest Consecutive Sequence showed why a Set is useful.</p>
<p>Instead of searching an array repeatedly:</p>
<pre><code class="language-js">set.has(value)
</code></pre>
<p>provides average O(1) lookup.</p>
<h2>5. Start From the Beginning of a Sequence</h2>
<p>For Longest Consecutive Sequence, this condition is extremely important:</p>
<pre><code class="language-js">if (!set.has(num - 1))
</code></pre>
<p>It prevents repeatedly processing the same sequence.</p>
<h2>6. Multiple Sets Can Track Multiple Constraints</h2>
<p>Valid Sudoku uses separate Sets for:</p>
<pre><code class="language-text">Rows
Columns
Boxes
</code></pre>
<p>This is useful when a problem has multiple independent constraints.</p>
<h1>Day 4 Summary</h1>
<table>
<thead>
<tr>
<th>Problem</th>
<th>Main Pattern</th>
<th>Time</th>
<th>Space</th>
</tr>
</thead>
<tbody><tr>
<td>169. Majority Element</td>
<td>Hashing + Frequency Counting</td>
<td>O(n)</td>
<td>O(n)</td>
</tr>
<tr>
<td>387. First Unique Character</td>
<td>Hashing + Frequency Counting</td>
<td>O(n)</td>
<td>O(k)</td>
</tr>
<tr>
<td>49. Group Anagrams</td>
<td>Hashing + Sorting</td>
<td>O(n × k log k)</td>
<td>O(n × k)</td>
</tr>
<tr>
<td>128. Longest Consecutive Sequence</td>
<td>Set + Lookup</td>
<td>O(n) expected</td>
<td>O(n)</td>
</tr>
<tr>
<td>36. Valid Sudoku</td>
<td>Multiple Sets</td>
<td>O(1)</td>
<td>O(1)</td>
</tr>
</tbody></table>
<h1>Day 4 Pattern Recognition</h1>
<pre><code class="language-text">Frequency
    ↓
HashMap / Frequency Counting

Group similar values
    ↓
HashMap + Common Key

Fast existence check
    ↓
Set

Consecutive sequence
    ↓
Set + Check Previous Number

Multiple validation constraints
    ↓
Multiple Sets / Maps
</code></pre>
<h1>Key Takeaway</h1>
<p>The main lesson from Day 4 is:</p>
<blockquote>
<p>Don't just ask "Which data structure should I use?" Ask "What information do I need to remember while traversing the input?"</p>
</blockquote>
<p>If I need to remember:</p>
<ul>
<li><p>how many times something appeared → HashMap</p>
</li>
<li><p>whether something exists → Set</p>
</li>
<li><p>a relationship between values → Map</p>
</li>
<li><p>information about multiple groups → Multiple Maps/Sets</p>
</li>
</ul>
<p>This helps me recognize the pattern before writing the code.</p>
<p><strong>Day 4 / 30</strong></p>
]]></content:encoded></item><item><title><![CDATA[Day 3 of My 30-Day DSA Journey — Hashing and Map/Set Patterns]]></title><description><![CDATA[1. Two Sum — LeetCode 1
Problem
Given an array of integers and a target, return the indices of two numbers whose sum equals the target.
Approach
For every number, I calculate the value I need:
needed ]]></description><link>https://abi-blog.hashnode.dev/day-3-of-my-30-day-dsa-journey-hashing-and-map-set-patterns</link><guid isPermaLink="true">https://abi-blog.hashnode.dev/day-3-of-my-30-day-dsa-journey-hashing-and-map-set-patterns</guid><category><![CDATA[DSA]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[leetcode]]></category><category><![CDATA[hashmap]]></category><category><![CDATA[Hashing]]></category><category><![CDATA[data structures]]></category><category><![CDATA[algorithms]]></category><category><![CDATA[coding interview]]></category><dc:creator><![CDATA[Abirami Sri]]></dc:creator><pubDate>Wed, 02 Sep 2026 17:21:36 GMT</pubDate><content:encoded><![CDATA[<h2>1. Two Sum — LeetCode 1</h2>
<h3>Problem</h3>
<p>Given an array of integers and a target, return the indices of two numbers whose sum equals the target.</p>
<h3>Approach</h3>
<p>For every number, I calculate the value I need:</p>
<pre><code class="language-text">needed = target - current number
</code></pre>
<p>Before storing the current number, I check whether the required value already exists in the Map.</p>
<p>If it exists, I have found the two numbers.</p>
<pre><code class="language-javascript">function twoSum(nums, target) {
    let map = new Map();

    for (let i = 0; i &lt; nums.length; i++) {
        let needed = target - nums[i];

        if (map.has(needed)) {
            return [map.get(needed), i];
        }

        map.set(nums[i], i);
    }

    return [];
}
</code></pre>
<h3>Example</h3>
<pre><code class="language-text">nums = [2, 7, 11, 15]
target = 9
</code></pre>
<pre><code class="language-text">i = 0
current = 2
needed = 9 - 2 = 7
7 is not in Map
store 2 → 0

i = 1
current = 7
needed = 9 - 7 = 2
2 is already in Map
</code></pre>
<p>Therefore:</p>
<pre><code class="language-text">[0, 1]
</code></pre>
<h3>Complexity</h3>
<ul>
<li><p>Time: <code>O(n)</code></p>
</li>
<li><p>Space: <code>O(n)</code></p>
</li>
</ul>
<h3>Pattern</h3>
<p><strong>HashMap / Complement Lookup</strong></p>
<hr />
<h2>2. Contains Duplicate — LeetCode 217</h2>
<h3>Problem</h3>
<p>Determine whether an array contains any duplicate value.</p>
<h3>Approach</h3>
<p>I use a <code>Set</code> to store the numbers I have already seen.</p>
<p>If the current number already exists in the Set, a duplicate has been found.</p>
<pre><code class="language-javascript">var containsDuplicate = function(nums) {
    let set = new Set();

    for (let num of nums) {
        if (set.has(num)) {
            return true;
        }

        set.add(num);
    }

    return false;
};
</code></pre>
<h3>Complexity</h3>
<ul>
<li><p>Time: <code>O(n)</code></p>
</li>
<li><p>Space: <code>O(n)</code></p>
</li>
</ul>
<h3>Pattern</h3>
<p><strong>Set / Seen Elements</strong></p>
<hr />
<h2>3. Intersection of Two Arrays — LeetCode 349</h2>
<h3>Problem</h3>
<p>Return the unique elements that appear in both arrays.</p>
<h3>Approach</h3>
<p>I store all elements of <code>nums2</code> in a Set.</p>
<p>Then I traverse <code>nums1</code>. If an element exists in the first Set, I add it to another Set called <code>result</code>.</p>
<p>Using a Set for the result automatically removes duplicates.</p>
<pre><code class="language-javascript">var intersection = function(nums1, nums2) {
    let set = new Set();
    let result = new Set();

    for (let num of nums2) {
        set.add(num);
    }

    for (let num of nums1) {
        if (set.has(num)) {
            result.add(num);
        }
    }

    return Array.from(result);
};
</code></pre>
<h3>Example</h3>
<pre><code class="language-text">nums1 = [1, 2, 2, 1]
nums2 = [2, 2]
</code></pre>
<p>Elements in <code>nums2</code>:</p>
<pre><code class="language-text">{2}
</code></pre>
<p>While traversing <code>nums1</code>, <code>2</code> is found.</p>
<p>Result:</p>
<pre><code class="language-text">[2]
</code></pre>
<h3>Complexity</h3>
<p>Let <code>n1</code> and <code>n2</code> be the lengths of the two arrays.</p>
<ul>
<li><p>Time: <code>O(n1 + n2)</code></p>
</li>
<li><p>Space: <code>O(n1 + n2)</code></p>
</li>
</ul>
<h3>Pattern</h3>
<p><strong>Set / Membership Lookup</strong></p>
<hr />
<h2>4. Ransom Note — LeetCode 383</h2>
<h3>Problem</h3>
<p>Determine whether the ransom note can be constructed using the characters available in the magazine.</p>
<p>Each character in the magazine can only be used once.</p>
<h3>Approach</h3>
<p>First, I count how many times each character appears in the magazine.</p>
<p>Then I traverse the ransom note and decrease the corresponding count.</p>
<p>If a required character doesn't have enough occurrences, I return false.</p>
<pre><code class="language-javascript">var canConstruct = function(ransomNote, magazine) {
    let count = {};

    for (let char of magazine) {
        count[char] = (count[char] || 0) + 1;
    }

    for (let char of ransomNote) {
        if (!count[char]) {
            return false;
        }

        count[char]--;
    }

    return true;
};
</code></pre>
<h3>Example</h3>
<pre><code class="language-text">ransomNote = "aa"
magazine = "aab"
</code></pre>
<p>Magazine frequency:</p>
<pre><code class="language-text">a → 2
b → 1
</code></pre>
<p>Process ransom note:</p>
<pre><code class="language-text">a → count becomes 1
a → count becomes 0
</code></pre>
<p>All required characters are available.</p>
<p>Result:</p>
<pre><code class="language-text">true
</code></pre>
<h3>Complexity</h3>
<p>If <code>m</code> is the ransom note length and <code>n</code> is the magazine length:</p>
<ul>
<li><p>Time: <code>O(m + n)</code></p>
</li>
<li><p>Space: <code>O(k)</code>, where <code>k</code> is the number of distinct characters.</p>
</li>
</ul>
<p>For the problem's fixed lowercase English alphabet, this can be considered <code>O(1)</code> auxiliary space.</p>
<h3>Pattern</h3>
<p><strong>Frequency Counting</strong></p>
<hr />
<h2>5. Isomorphic Strings — LeetCode 205</h2>
<h3>Problem</h3>
<p>Determine whether two strings are isomorphic.</p>
<p>Each character in the first string must map to exactly one character in the second string, and two different characters cannot map to the same character.</p>
<h3>Approach</h3>
<p>I need to maintain the mapping in both directions:</p>
<pre><code class="language-text">s → t
t → s
</code></pre>
<p>This prevents two different characters from mapping to the same character.</p>
<p>A <code>Map</code> is cleaner and safer than a plain object.</p>
<pre><code class="language-javascript">var isIsomorphic = function(s, t) {
    let mapStoT = new Map();
    let mapTtoS = new Map();

    for (let i = 0; i &lt; s.length; i++) {
        let charS = s[i];
        let charT = t[i];

        if (
            (mapStoT.has(charS) &amp;&amp; mapStoT.get(charS) !== charT) ||
            (mapTtoS.has(charT) &amp;&amp; mapTtoS.get(charT) !== charS)
        ) {
            return false;
        }

        mapStoT.set(charS, charT);
        mapTtoS.set(charT, charS);
    }

    return true;
};
</code></pre>
<h3>Example</h3>
<pre><code class="language-text">s = "egg"
t = "add"
</code></pre>
<p>Mappings:</p>
<pre><code class="language-text">e → a
g → d
</code></pre>
<p>The mapping remains consistent.</p>
<p>Therefore:</p>
<pre><code class="language-text">true
</code></pre>
<p>But:</p>
<pre><code class="language-text">s = "foo"
t = "bar"
</code></pre>
<p>We get:</p>
<pre><code class="language-text">f → b
o → a
</code></pre>
<p>Then the second <code>o</code> would need to map to <code>r</code>, which conflicts with:</p>
<pre><code class="language-text">o → a
</code></pre>
<p>Therefore:</p>
<pre><code class="language-text">false
</code></pre>
<h3>Complexity</h3>
<ul>
<li><p>Time: <code>O(n)</code></p>
</li>
<li><p>Space: <code>O(n)</code></p>
</li>
</ul>
<h3>Pattern</h3>
<p><strong>Two-Way HashMap / Character Mapping</strong></p>
<hr />
<h1>Day 3 Summary</h1>
<table>
<thead>
<tr>
<th>Problem</th>
<th>Pattern</th>
<th>Time</th>
<th>Space</th>
</tr>
</thead>
<tbody><tr>
<td>Two Sum</td>
<td>HashMap</td>
<td>O(n)</td>
<td>O(n)</td>
</tr>
<tr>
<td>Contains Duplicate</td>
<td>Set</td>
<td>O(n)</td>
<td>O(n)</td>
</tr>
<tr>
<td>Intersection of Two Arrays</td>
<td>Set</td>
<td>O(n1 + n2)</td>
<td>O(n1 + n2)</td>
</tr>
<tr>
<td>Ransom Note</td>
<td>Frequency Map</td>
<td>O(m + n)</td>
<td>O(k)</td>
</tr>
<tr>
<td>Isomorphic Strings</td>
<td>Two-Way Map</td>
<td>O(n)</td>
<td>O(n)</td>
</tr>
</tbody></table>
<hr />
<h1>What I Learned Today</h1>
<p>Today I started understanding <strong>Hashing as a problem-solving pattern</strong> rather than simply learning the <code>Map</code> or <code>Set</code> syntax.</p>
<p>The main ideas I practiced were:</p>
<pre><code class="language-text">Hashing
   ↓
Fast Lookup
   ↓
Complement Lookup
   ↓
Seen Elements
   ↓
Frequency Counting
   ↓
One-to-One Mapping
</code></pre>
<p>The most important question I want to ask myself when solving future problems is:</p>
<blockquote>
<p>"Do I need to remember something I have already seen?"</p>
</blockquote>
<p>If the answer is yes, a <code>Set</code> or <code>Map</code> may be useful.</p>
<hr />
<h1>Day 3 Key Takeaway</h1>
<p>The biggest lesson from today's problems is that <strong>Hashing can reduce repeated searching</strong>.</p>
<p>For example, in Two Sum, instead of checking every possible pair with <code>O(n²)</code> time, I can remember previous values in a Map and solve the problem in <code>O(n)</code> time.</p>
<p>This is the kind of pattern recognition I want to develop throughout this 30-day DSA journey.</p>
<p><strong>Day 3/30 completed.</strong></p>
]]></content:encoded></item><item><title><![CDATA[Day 2 of My 30-Day DSA Journey — Strings with JavaScript]]></title><description><![CDATA[Welcome to Day 2 of my 30 Days of DSA with JavaScript.
On Day 1, I started with basic array problems. Today, I moved into String problems and learned several important problem-solving patterns.
The ma]]></description><link>https://abi-blog.hashnode.dev/day-2-of-my-30-day-dsa-journey-strings-with-javascript</link><guid isPermaLink="true">https://abi-blog.hashnode.dev/day-2-of-my-30-day-dsa-journey-strings-with-javascript</guid><category><![CDATA[DSA]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[leetcode]]></category><category><![CDATA[Data Structures Algorithms]]></category><category><![CDATA[coding]]></category><category><![CDATA[interview]]></category><category><![CDATA[Problem Solving]]></category><category><![CDATA[#DSAJourney]]></category><dc:creator><![CDATA[Abirami Sri]]></dc:creator><pubDate>Tue, 01 Sep 2026 09:43:25 GMT</pubDate><content:encoded><![CDATA[<p>Welcome to <strong>Day 2 of my 30 Days of DSA with JavaScript</strong>.</p>
<p>On Day 1, I started with basic array problems. Today, I moved into <strong>String problems</strong> and learned several important problem-solving patterns.</p>
<p>The main patterns I practiced today were:</p>
<ul>
<li><p>Two Pointers</p>
</li>
<li><p>String Traversal</p>
</li>
<li><p>Frequency Counting</p>
</li>
<li><p>Hashing</p>
</li>
<li><p>Character-by-character comparison</p>
</li>
</ul>
<p>I solved 5 LeetCode problems:</p>
<table>
<thead>
<tr>
<th>#</th>
<th>Problem</th>
<th>Pattern</th>
</tr>
</thead>
<tbody><tr>
<td>344</td>
<td>Reverse String</td>
<td>Two Pointers</td>
</tr>
<tr>
<td>125</td>
<td>Valid Palindrome</td>
<td>Two Pointers</td>
</tr>
<tr>
<td>242</td>
<td>Valid Anagram</td>
<td>Frequency Map</td>
</tr>
<tr>
<td>387</td>
<td>First Unique Character in a String</td>
<td>Frequency Map</td>
</tr>
<tr>
<td>14</td>
<td>Longest Common Prefix</td>
<td>String Traversal</td>
</tr>
</tbody></table>
<hr />
<h1>1. Reverse String — LeetCode 344</h1>
<h2>Problem</h2>
<p>Given an array of characters, reverse the string <strong>in-place</strong>.</p>
<h3>Example</h3>
<pre><code class="language-text">Input:
["h","e","l","l","o"]

Output:
["o","l","l","e","h"]
</code></pre>
<h2>Approach</h2>
<p>I used the <strong>Two Pointer</strong> technique.</p>
<p>One pointer starts from the beginning and another starts from the end.</p>
<p>I swap the characters and move both pointers toward the center.</p>
<pre><code class="language-javascript">var reverseString = function(s) {
    let len = s.length;
    let halfLen = Math.floor(len / 2);

    for (let i = 0; i &lt; halfLen; i++) {
        let temp = s[i];
        s[i] = s[len - 1 - i];
        s[len - 1 - i] = temp;
    }
};
</code></pre>
<h2>Example</h2>
<pre><code class="language-text">["h","e","l","l","o"]

h ↔ o

["o","e","l","l","h"]

e ↔ l

["o","l","l","e","h"]
</code></pre>
<p>We only need to process half of the array because every swap handles two positions.</p>
<h2>Complexity</h2>
<ul>
<li><p><strong>Time:</strong> <code>O(n)</code></p>
</li>
<li><p><strong>Space:</strong> <code>O(1)</code></p>
</li>
</ul>
<h2>Pattern Learned</h2>
<p><strong>Two Pointers + In-place Modification</strong></p>
<hr />
<h1>2. Valid Palindrome — LeetCode 125</h1>
<h2>Problem</h2>
<p>Determine whether a string is a palindrome after:</p>
<ul>
<li><p>Converting uppercase letters to lowercase</p>
</li>
<li><p>Ignoring non-alphanumeric characters</p>
</li>
</ul>
<h3>Example</h3>
<pre><code class="language-text">Input:
"A man, a plan, a canal: Panama"

Output:
true
</code></pre>
<h2>Approach</h2>
<p>I used the <strong>Two Pointer</strong> technique again.</p>
<p>One pointer starts from the beginning and another from the end.</p>
<p>If the current character is not alphanumeric, I skip it.</p>
<p>If both characters are valid, I compare them.</p>
<p>If they don't match, the string cannot be a palindrome.</p>
<pre><code class="language-javascript">var isPalindrome = function(s) {
    s = s.toLowerCase();

    let i = 0;
    let j = s.length - 1;

    while (i &lt; j) {
        if (!s[i].match(/[a-z0-9]/i)) {
            ++i;
        }
        else if (!s[j].match(/[a-z0-9]/i)) {
            --j;
        }
        else if (s[i] === s[j]) {
            ++i;
            --j;
        }
        else {
            return false;
        }
    }

    return true;
};
</code></pre>
<h2>Example</h2>
<pre><code class="language-text">"A man, a plan, a canal: Panama"
</code></pre>
<p>Ignore spaces and punctuation:</p>
<pre><code class="language-text">amanaplanacanalpanama
</code></pre>
<p>Compare from both ends:</p>
<pre><code class="language-text">a == a
m == m
a == a
...
</code></pre>
<p>All characters match, so the answer is <code>true</code>.</p>
<h2>Complexity</h2>
<ul>
<li><p><strong>Time:</strong> <code>O(n)</code></p>
</li>
<li><p><strong>Space:</strong> <code>O(1)</code> auxiliary space</p>
</li>
</ul>
<h2>Pattern Learned</h2>
<p><strong>Two Pointers + Character Validation</strong></p>
<hr />
<h1>3. Valid Anagram — LeetCode 242</h1>
<h2>Problem</h2>
<p>Given two strings, determine whether one is an anagram of the other.</p>
<p>Two strings are anagrams if they contain the same characters with the same frequencies.</p>
<h3>Example</h3>
<pre><code class="language-text">Input:
s = "anagram"
t = "nagaram"

Output:
true
</code></pre>
<h2>Approach</h2>
<p>I used a <strong>frequency map</strong>.</p>
<p>First, I count how many times each character appears in <code>s</code>.</p>
<p>Then I traverse <code>t</code> and decrease the count for each character.</p>
<p>If a character doesn't exist or its count becomes invalid, I return <code>false</code>.</p>
<pre><code class="language-javascript">var isAnagram = function(s, t) {
    if (s.length !== t.length) return false;

    let map = {};

    for (let i = 0; i &lt; s.length; i++) {
        if (!map[s[i]]) {
            map[s[i]] = 1;
        } else {
            ++map[s[i]];
        }
    }

    for (let i = 0; i &lt; t.length; i++) {
        if (!map[t[i]] || map[t[i]] &lt; 0) {
            return false;
        } else {
            --map[t[i]];
        }
    }

    return true;
};
</code></pre>
<h2>Example</h2>
<p>For:</p>
<pre><code class="language-text">s = "aab"
</code></pre>
<p>Frequency map:</p>
<pre><code class="language-text">a → 2
b → 1
</code></pre>
<p>Now process:</p>
<pre><code class="language-text">t = "aba"
</code></pre>
<pre><code class="language-text">a → 1
b → 0
a → 0
</code></pre>
<p>Everything reaches zero, so it is an anagram.</p>
<h2>Complexity</h2>
<ul>
<li><p><strong>Time:</strong> <code>O(n)</code></p>
</li>
<li><p><strong>Space:</strong> <code>O(n)</code></p>
</li>
</ul>
<h2>Pattern Learned</h2>
<p><strong>Hashing + Frequency Counting</strong></p>
<hr />
<h1>4. First Unique Character in a String — LeetCode 387</h1>
<h2>Problem</h2>
<p>Find the index of the first character that appears only once.</p>
<h3>Example</h3>
<pre><code class="language-text">Input:
"leetcode"

Output:
0
</code></pre>
<p>Because <code>l</code> appears only once.</p>
<p>Another example:</p>
<pre><code class="language-text">Input:
"loveleetcode"

Output:
2
</code></pre>
<p>Because <code>v</code> is the first unique character.</p>
<h2>Approach</h2>
<p>I used a frequency map.</p>
<p>I need two traversals:</p>
<ol>
<li><p>Count the frequency of every character.</p>
</li>
<li><p>Traverse the string again and find the first character whose frequency is <code>1</code>.</p>
</li>
</ol>
<pre><code class="language-javascript">var firstUniqChar = function(s) {
    let map = {};

    for (let i = 0; i &lt; s.length; i++) {
        if (!map[s[i]]) {
            map[s[i]] = 1;
        } else {
            ++map[s[i]];
        }
    }

    for (let i = 0; i &lt; s.length; i++) {
        if (map[s[i]] === 1) {
            return i;
        }
    }

    return -1;
};
</code></pre>
<h2>Example</h2>
<pre><code class="language-text">s = "leetcode"
</code></pre>
<p>Frequency:</p>
<pre><code class="language-text">l → 1
e → 3
t → 1
c → 1
o → 1
d → 1
</code></pre>
<p>Traverse again:</p>
<pre><code class="language-text">l → frequency = 1
</code></pre>
<p>So we return:</p>
<pre><code class="language-text">0
</code></pre>
<h2>Complexity</h2>
<ul>
<li><p><strong>Time:</strong> <code>O(n)</code></p>
</li>
<li><p><strong>Space:</strong> <code>O(n)</code></p>
</li>
</ul>
<h2>Pattern Learned</h2>
<p><strong>Frequency Counting + Two Traversals</strong></p>
<hr />
<h1>5. Longest Common Prefix — LeetCode 14</h1>
<h2>Problem</h2>
<p>Given an array of strings, find the longest prefix shared by all strings.</p>
<h3>Example</h3>
<pre><code class="language-text">Input:
["flower", "flow", "flight"]

Output:
"fl"
</code></pre>
<h2>Approach</h2>
<p>I compare characters column by column using the first string as the reference.</p>
<p>For every character position:</p>
<ol>
<li><p>Check that every other string has that position.</p>
</li>
<li><p>Check whether the character is the same.</p>
</li>
<li><p>If there is a mismatch, return the prefix found so far.</p>
</li>
<li><p>Otherwise, add the character to the prefix.</p>
</li>
</ol>
<pre><code class="language-javascript">var longestCommonPrefix = function(strs) {
    let prefix = "";

    for (let j = 0; j &lt; strs[0].length; j++) {

        for (let i = 1; i &lt; strs.length; i++) {

            if (
                j &gt;= strs[i].length ||
                strs[0][j] !== strs[i][j]
            ) {
                return prefix;
            }
        }

        prefix += strs[0][j];
    }

    return prefix;
};
</code></pre>
<h2>Example</h2>
<pre><code class="language-text">["flower", "flow", "flight"]
</code></pre>
<p>Compare index <code>0</code>:</p>
<pre><code class="language-text">f
f
f
</code></pre>
<p>Match → <code>"f"</code></p>
<p>Compare index <code>1</code>:</p>
<pre><code class="language-text">l
l
l
</code></pre>
<p>Match → <code>"fl"</code></p>
<p>Compare index <code>2</code>:</p>
<pre><code class="language-text">o
o
i
</code></pre>
<p>Mismatch.</p>
<p>Therefore:</p>
<pre><code class="language-text">"fl"
</code></pre>
<p>is the longest common prefix.</p>
<h2>Complexity</h2>
<p>Let:</p>
<ul>
<li><p><code>m</code> = number of strings</p>
</li>
<li><p><code>n</code> = length of the shortest string</p>
</li>
</ul>
<p><strong>Time:</strong> <code>O(m × n)</code></p>
<p><strong>Auxiliary Space:</strong> <code>O(1)</code></p>
<p>The returned prefix itself can require up to <code>O(n)</code> space.</p>
<h2>Pattern Learned</h2>
<p><strong>String Traversal + Character Comparison</strong></p>
<hr />
<h1>What I Learned on Day 2</h1>
<p>Today's problems helped me identify some important DSA patterns.</p>
<h3>1. Two Pointers</h3>
<p>Used in:</p>
<ul>
<li><p>Reverse String</p>
</li>
<li><p>Valid Palindrome</p>
</li>
</ul>
<p>The general idea is:</p>
<pre><code class="language-text">left →              ← right
</code></pre>
<p>Process both ends and move toward the center.</p>
<hr />
<h3>2. Frequency Counting</h3>
<p>Used in:</p>
<ul>
<li><p>Valid Anagram</p>
</li>
<li><p>First Unique Character</p>
</li>
</ul>
<p>The general idea is:</p>
<pre><code class="language-text">character → frequency
</code></pre>
<p>For example:</p>
<pre><code class="language-text">a → 3
b → 1
c → 2
</code></pre>
<p>This is one of the most common patterns in string problems.</p>
<hr />
<h3>3. String Traversal</h3>
<p>Used in:</p>
<ul>
<li>Longest Common Prefix</li>
</ul>
<p>Instead of treating a string as one large value, I can process it character by character.</p>
<hr />
<h1>Day 2 Summary</h1>
<table>
<thead>
<tr>
<th>Problem</th>
<th>Pattern</th>
<th>Time</th>
<th>Space</th>
</tr>
</thead>
<tbody><tr>
<td>Reverse String</td>
<td>Two Pointers</td>
<td>O(n)</td>
<td>O(1)</td>
</tr>
<tr>
<td>Valid Palindrome</td>
<td>Two Pointers</td>
<td>O(n)</td>
<td>O(1)</td>
</tr>
<tr>
<td>Valid Anagram</td>
<td>Frequency Map</td>
<td>O(n)</td>
<td>O(n)</td>
</tr>
<tr>
<td>First Unique Character</td>
<td>Frequency Map</td>
<td>O(n)</td>
<td>O(n)</td>
</tr>
<tr>
<td>Longest Common Prefix</td>
<td>String Traversal</td>
<td>O(m × n)</td>
<td>O(1)*</td>
</tr>
</tbody></table>
<ul>
<li>Auxiliary space; the returned prefix itself can require <code>O(n)</code>.</li>
</ul>
<hr />
<h1>🚀 Day 2 Completed</h1>
<p>Today I moved from basic array problems into string-based problem solving.</p>
<p>The biggest takeaway from Day 2:</p>
<blockquote>
<p><strong>Don't just ask "How do I solve this problem?" Ask "Which pattern can I recognize here?"</strong></p>
</blockquote>
<p>Today's patterns:</p>
<pre><code class="language-text">String Problems
      ↓
Two Pointers
      ↓
Frequency Counting
      ↓
Hashing
      ↓
Character Comparison
</code></pre>
<p>#DSA #JavaScript #LeetCode #Algorithms #DataStructures #CodingInterview #ProblemSolving #DSAJourney</p>
]]></content:encoded></item><item><title><![CDATA[Day 1 of My 30-Day DSA Journey — Arrays with JavaScript 🚀]]></title><description><![CDATA[Today I started my 30 Days of DSA with JavaScript journey.
My goal is not just to solve LeetCode problems, but to understand the patterns behind the problems, analyze time and space complexity, and le]]></description><link>https://abi-blog.hashnode.dev/day-1-of-my-30-day-dsa-journey-arrays-with-javascript</link><guid isPermaLink="true">https://abi-blog.hashnode.dev/day-1-of-my-30-day-dsa-journey-arrays-with-javascript</guid><category><![CDATA[DSA]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[leetcode]]></category><category><![CDATA[algorithms]]></category><category><![CDATA[data structures]]></category><category><![CDATA[coding interview]]></category><dc:creator><![CDATA[Abirami Sri]]></dc:creator><pubDate>Mon, 31 Aug 2026 17:13:59 GMT</pubDate><content:encoded><![CDATA[<p>Today I started my <strong>30 Days of DSA with JavaScript</strong> journey.</p>
<p>My goal is not just to solve LeetCode problems, but to understand the <strong>patterns behind the problems</strong>, analyze time and space complexity, and learn how to explain my solutions in technical interviews.</p>
<p>For Day 1, I solved 5 Easy problems focused mainly on <strong>Array Traversal and Hashing</strong>.</p>
<h2>Problems Solved</h2>
<table>
<thead>
<tr>
<th>#</th>
<th>LeetCode Problem</th>
<th>Pattern</th>
</tr>
</thead>
<tbody><tr>
<td>1480</td>
<td>Running Sum of 1d Array</td>
<td>Array Traversal</td>
</tr>
<tr>
<td>1929</td>
<td>Concatenation of Array</td>
<td>Array Traversal</td>
</tr>
<tr>
<td>1470</td>
<td>Shuffle the Array</td>
<td>Index Manipulation</td>
</tr>
<tr>
<td>1672</td>
<td>Richest Customer Wealth</td>
<td>Nested Array Traversal</td>
</tr>
<tr>
<td>217</td>
<td>Contains Duplicate</td>
<td>Hashing / Set</td>
</tr>
</tbody></table>
<hr />
<h1>1. Running Sum of 1d Array — LeetCode 1480</h1>
<h3>Problem</h3>
<p>Given an array <code>nums</code>, calculate the running sum.</p>
<p>The running sum at index <code>i</code> is the sum of all elements from index <code>0</code> to <code>i</code>.</p>
<h3>Example</h3>
<pre><code class="language-text">Input:
[1, 2, 3, 4]

Output:
[1, 3, 6, 10]
</code></pre>
<h3>Approach</h3>
<p>I can solve this using the previous element.</p>
<p>At every index:</p>
<pre><code class="language-text">current value = current value + previous running sum
</code></pre>
<p>The previous index already contains the calculated running sum, so I can modify the array directly.</p>
<h3>JavaScript Solution</h3>
<pre><code class="language-javascript">var runningSum = function(nums) {
    for (let i = 1; i &lt; nums.length; i++) {
        nums[i] = nums[i] + nums[i - 1];
    }

    return nums;
};
</code></pre>
<h3>How It Works</h3>
<p>For:</p>
<pre><code class="language-text">[1, 2, 3, 4]
</code></pre>
<p>At <code>i = 1</code>:</p>
<pre><code class="language-text">2 + 1 = 3
[1, 3, 3, 4]
</code></pre>
<p>At <code>i = 2</code>:</p>
<pre><code class="language-text">3 + 3 = 6
[1, 3, 6, 4]
</code></pre>
<p>At <code>i = 3</code>:</p>
<pre><code class="language-text">4 + 6 = 10
[1, 3, 6, 10]
</code></pre>
<h3>Complexity</h3>
<ul>
<li><p><strong>Time:</strong> <code>O(n)</code> — we traverse the array once.</p>
</li>
<li><p><strong>Space:</strong> <code>O(1)</code> — no additional array is created.</p>
</li>
</ul>
<h3>Pattern Learned</h3>
<p><strong>Array Traversal + In-place Modification</strong></p>
<hr />
<h1>2. Concatenation of Array — LeetCode 1929</h1>
<h3>Problem</h3>
<p>Given an array <code>nums</code>, create an array containing the original array twice.</p>
<h3>Example</h3>
<pre><code class="language-text">Input:
[1, 2, 1]

Output:
[1, 2, 1, 1, 2, 1]
</code></pre>
<h3>Approach</h3>
<p>For every element at index <code>i</code>, I place it at:</p>
<pre><code class="language-text">i
i + n
</code></pre>
<p>where <code>n</code> is the length of the original array.</p>
<h3>JavaScript Solution</h3>
<pre><code class="language-javascript">var getConcatenation = function(nums) {
    let ans = [];
    let n = nums.length;

    for (let i = 0; i &lt; n; i++) {
        ans[i] = nums[i];
        ans[i + n] = nums[i];
    }

    return ans;
};
</code></pre>
<h3>How It Works</h3>
<p>If:</p>
<pre><code class="language-text">nums = [1, 2, 1]
n = 3
</code></pre>
<p>Then:</p>
<pre><code class="language-text">i = 0
ans[0] = 1
ans[3] = 1

i = 1
ans[1] = 2
ans[4] = 2

i = 2
ans[2] = 1
ans[5] = 1
</code></pre>
<p>Result:</p>
<pre><code class="language-text">[1, 2, 1, 1, 2, 1]
</code></pre>
<h3>Complexity</h3>
<ul>
<li><p><strong>Time:</strong> <code>O(n)</code></p>
</li>
<li><p><strong>Space:</strong> <code>O(n)</code> because we create a new array containing <code>2n</code> elements.</p>
</li>
</ul>
<h3>Pattern Learned</h3>
<p><strong>Array Traversal + Index Manipulation</strong></p>
<hr />
<h1>3. Shuffle the Array — LeetCode 1470</h1>
<h3>Problem</h3>
<p>The input contains two halves:</p>
<pre><code class="language-text">[x1, x2, ..., xn, y1, y2, ..., yn]
</code></pre>
<p>We need to return:</p>
<pre><code class="language-text">[x1, y1, x2, y2, ..., xn, yn]
</code></pre>
<h3>Example</h3>
<pre><code class="language-text">Input:
[2, 5, 1, 3, 4, 7]

n = 3

Output:
[2, 3, 5, 4, 1, 7]
</code></pre>
<h3>Approach</h3>
<p>The first half contains the <code>x</code> values and the second half contains the <code>y</code> values.</p>
<p>For every index <code>i</code>, I add:</p>
<pre><code class="language-text">nums[i]
nums[i + n]
</code></pre>
<p>to the result.</p>
<h3>JavaScript Solution</h3>
<pre><code class="language-javascript">var shuffle = function(nums, n) {
    let res = [];
    let i = 0;

    while (i &lt; n) {
        res.push(nums[i]);
        res.push(nums[i + n]);
        i++;
    }

    return res;
};
</code></pre>
<h3>Complexity</h3>
<ul>
<li><p><strong>Time:</strong> <code>O(n)</code></p>
</li>
<li><p><strong>Space:</strong> <code>O(n)</code> because we create the result array.</p>
</li>
</ul>
<h3>Pattern Learned</h3>
<p><strong>Array Traversal + Index Relationship</strong></p>
<hr />
<h1>4. Richest Customer Wealth — LeetCode 1672</h1>
<h3>Problem</h3>
<p>Each customer has money in multiple bank accounts.</p>
<p>We need to find the customer with the maximum total wealth.</p>
<h3>Example</h3>
<pre><code class="language-text">Input:
[
    [1, 2, 3],
    [3, 2, 1]
]

Output:
6
</code></pre>
<h3>Approach</h3>
<p>This is an array containing other arrays.</p>
<p>So I use:</p>
<ul>
<li><p>Outer loop → iterate through each customer</p>
</li>
<li><p>Inner loop → calculate that customer's total wealth</p>
</li>
<li><p><code>max</code> → store the maximum wealth</p>
</li>
</ul>
<h3>JavaScript Solution</h3>
<pre><code class="language-javascript">var maximumWealth = function(accounts) {
    let max = 0;

    for (let i = 0; i &lt; accounts.length; i++) {
        let sum = 0;

        for (let j = 0; j &lt; accounts[i].length; j++) {
            sum += accounts[i][j];
        }

        if (sum &gt; max) {
            max = sum;
        }
    }

    return max;
};
</code></pre>
<h3>How It Works</h3>
<p>For:</p>
<pre><code class="language-text">[
    [1, 2, 3],
    [3, 2, 1],
    [4, 5, 6]
]
</code></pre>
<p>We calculate:</p>
<pre><code class="language-text">Customer 1 → 1 + 2 + 3 = 6
Customer 2 → 3 + 2 + 1 = 6
Customer 3 → 4 + 5 + 6 = 15
</code></pre>
<p>Therefore:</p>
<pre><code class="language-text">Maximum wealth = 15
</code></pre>
<h3>Complexity</h3>
<p>If there are <code>m</code> customers and each customer has <code>n</code> accounts:</p>
<ul>
<li><p><strong>Time:</strong> <code>O(m × n)</code></p>
</li>
<li><p><strong>Space:</strong> <code>O(1)</code></p>
</li>
</ul>
<h3>Pattern Learned</h3>
<p><strong>Nested Array Traversal</strong></p>
<h3>Important Lesson</h3>
<p>Two loops do not automatically mean <code>O(n²)</code>.</p>
<p>We need to understand what each loop is traversing.</p>
<p>Here, one loop traverses customers and the other traverses accounts.</p>
<hr />
<h1>5. Contains Duplicate — LeetCode 217</h1>
<h3>Problem</h3>
<p>Given an integer array, determine whether any value appears at least twice.</p>
<h3>Example</h3>
<pre><code class="language-text">Input:
[1, 2, 3, 1]

Output:
true
</code></pre>
<h3>Approach</h3>
<p>I need to remember which numbers I have already seen.</p>
<p>A <code>Set</code> is useful because it allows me to check whether a value already exists.</p>
<h3>JavaScript Solution</h3>
<pre><code class="language-javascript">var containsDuplicate = function(nums) {
    let set = new Set();

    for (let num of nums) {
        if (set.has(num)) {
            return true;
        }

        set.add(num);
    }

    return false;
};
</code></pre>
<h3>How It Works</h3>
<p>For:</p>
<pre><code class="language-text">[1, 2, 3, 1]
</code></pre>
<p>We process each number:</p>
<pre><code class="language-text">1 → not present → add
2 → not present → add
3 → not present → add
1 → already present → return true
</code></pre>
<h3>Complexity</h3>
<ul>
<li><p><strong>Time:</strong> <code>O(n)</code></p>
</li>
<li><p><strong>Space:</strong> <code>O(n)</code></p>
</li>
</ul>
<p>The Set can store up to <code>n</code> unique elements.</p>
<h3>Important Mistake I Learned</h3>
<p>Initially, I considered the space complexity as <code>O(1)</code>.</p>
<p>But that was incorrect.</p>
<p>Since the Set can grow depending on the input size, the correct space complexity is:</p>
<pre><code class="language-text">O(n)
</code></pre>
<p>This reminded me that <strong>writing the solution is only one part of DSA. Understanding complexity is equally important.</strong></p>
<hr />
<h1>🎯 Day 1 — What I Learned</h1>
<p>Today I learned several important array patterns:</p>
<h3>1. Array Traversal</h3>
<p>Visit every element once.</p>
<h3>2. In-place Modification</h3>
<p>Modify the existing array instead of creating another array when possible.</p>
<h3>3. Index Manipulation</h3>
<p>Use relationships between indexes to rearrange elements.</p>
<h3>4. Nested Array Traversal</h3>
<p>Use nested loops when working with arrays containing other arrays.</p>
<h3>5. Hashing with Set</h3>
<p>Use a <code>Set</code> when I need to efficiently check whether I've already seen a value.</p>
<hr />
<h1>Interview Learning</h1>
<p>One of my goals with this DSA journey is not just to solve problems but to <strong>explain my solutions during interviews</strong>.</p>
<p>For every problem, I want to practice explaining:</p>
<pre><code class="language-text">1. What is the problem asking?
2. What is my approach?
3. Why does my approach work?
4. Can I optimize it?
5. What is the time complexity?
6. What is the space complexity?
</code></pre>
<p>I realized that being able to write code and being able to <strong>explain the code clearly</strong> are two different skills.</p>
<p>I want to improve both.</p>
<hr />
<h1>Day 1 Summary</h1>
<table>
<thead>
<tr>
<th>Problem</th>
<th>Pattern</th>
<th>Time</th>
<th>Space</th>
</tr>
</thead>
<tbody><tr>
<td>Running Sum</td>
<td>Array Traversal</td>
<td>O(n)</td>
<td>O(1)</td>
</tr>
<tr>
<td>Concatenation</td>
<td>Array Traversal</td>
<td>O(n)</td>
<td>O(n)</td>
</tr>
<tr>
<td>Shuffle</td>
<td>Index Manipulation</td>
<td>O(n)</td>
<td>O(n)</td>
</tr>
<tr>
<td>Richest Wealth</td>
<td>Nested Traversal</td>
<td>O(m × n)</td>
<td>O(1)</td>
</tr>
<tr>
<td>Contains Duplicate</td>
<td>Hashing / Set</td>
<td>O(n)</td>
<td>O(n)</td>
</tr>
</tbody></table>
<hr />
<h1>Final Takeaway</h1>
<p>Day 1 taught me that DSA is not about memorizing solutions.</p>
<p>The real goal is to recognize:</p>
<blockquote>
<p><strong>What pattern does this problem follow?</strong></p>
</blockquote>
<p>Today I started with simple array problems. From here, I'll gradually move towards more important patterns such as:</p>
<pre><code class="language-text">Arrays
↓
Two Pointers
↓
Sliding Window
↓
Hashing
↓
Stack &amp; Queue
↓
Linked List
↓
Binary Search
↓
Trees
↓
Graphs
↓
Dynamic Programming
</code></pre>
<p><strong>Day 1/30 completed. 🚀</strong></p>
<p>The journey has just started.</p>
<hr />
<h3>LeetCode Problems</h3>
<ul>
<li><p>LeetCode 1480 — Running Sum of 1d Array</p>
</li>
<li><p>LeetCode 1929 — Concatenation of Array</p>
</li>
<li><p>LeetCode 1470 — Shuffle the Array</p>
</li>
<li><p>LeetCode 1672 — Richest Customer Wealth</p>
</li>
<li><p>LeetCode 217 — Contains Duplicate</p>
</li>
</ul>
<p>#DSA #JavaScript #LeetCode #Algorithms #DataStructures #CodingInterview #ProblemSolving #100DaysOfCode</p>
]]></content:encoded></item></channel></rss>