<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: kanishkaisuru</title>
    <description>The latest articles on DEV Community by kanishkaisuru (@kanishkaisuru).</description>
    <link>https://dev.to/kanishkaisuru</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F665760%2F9e4874ba-d36a-44db-bc74-3fd51bef2213.jpeg</url>
      <title>DEV Community: kanishkaisuru</title>
      <link>https://dev.to/kanishkaisuru</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kanishkaisuru"/>
    <language>en</language>
    <item>
      <title>Problem Solving Patterns (Part 4): Divide and Conquer</title>
      <dc:creator>kanishkaisuru</dc:creator>
      <pubDate>Wed, 01 Jan 2025 02:23:52 +0000</pubDate>
      <link>https://dev.to/kanishkaisuru/problem-solving-patterns-part-4-divide-and-conquer-1gl5</link>
      <guid>https://dev.to/kanishkaisuru/problem-solving-patterns-part-4-divide-and-conquer-1gl5</guid>
      <description>&lt;h2&gt;
  
  
  Welcome Back!
&lt;/h2&gt;

&lt;p&gt;Welcome back to the "Problem Solving Patterns" series! In this series, we explore different patterns to enhance your problem-solving skills and algorithmic thinking. Here’s a quick recap of the patterns we’ve covered so far:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recap&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 1: Frequency Counter Pattern&lt;/strong&gt; - &lt;a href="https://dev.to/kanishkaisuru/problem-solving-patterns-54f8"&gt;Read here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 2: Multiple Pointers Pattern&lt;/strong&gt; - &lt;a href="https://dev.to/kanishkaisuru/problem-solving-patterns-3pf8"&gt;Read here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 3: Sliding Window Pattern&lt;/strong&gt; - &lt;a href="https://dev.to/kanishkaisuru/problem-solving-patterns-2je1"&gt;Read here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you missed these posts, check them out to build a strong foundation for the series!&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Concepts of Divide and Conquer
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Divide:&lt;/strong&gt; Split the problem into smaller sub-problems that are easier to solve.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conquer:&lt;/strong&gt; Solve each sub-problem recursively. If the sub-problems are small enough, solve them directly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Combine:&lt;/strong&gt; Merge the solutions of the sub-problems to solve the original problem.&lt;/p&gt;

&lt;p&gt;This approach works best for problems that can be recursively divided and where combining the solutions is relatively straightforward.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Examples of Divide and Conquer
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Binary Search&lt;/li&gt;
&lt;li&gt;Merge Sort&lt;/li&gt;
&lt;li&gt;Quick Sort&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finding the maximum and minimum in an array&lt;/p&gt;




&lt;h2&gt;
  
  
  Example: Binary Search
&lt;/h2&gt;

&lt;p&gt;Let’s implement a simple binary search algorithm using the Divide and Conquer pattern. Binary search is used to find the position of a target value within a sorted array.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem Statement&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Given a sorted array and a target value, return the index of the target value. If the target does not exist, return -1.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Steps to Solve&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Divide the array into two halves by calculating the middle index.&lt;/li&gt;
&lt;li&gt;Compare the target value with the middle element:

&lt;ul&gt;
&lt;li&gt;If the target is equal to the middle element, return the index.&lt;/li&gt;
&lt;li&gt;If the target is less than the middle element, repeat the search 
on the left half.&lt;/li&gt;
&lt;li&gt;If the target is greater than the middle element, repeat the 
search on the right half.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Conquer by recursively solving the smaller sub-problems until the target is found or the array is fully traversed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function binarySearch(arr, target) {
    let left = 0;
    let right = arr.length - 1;

    while (left &amp;lt;= right) {
        const mid = Math.floor((left + right) / 2);
        if (arr[mid] === target) {
            return mid;
        } else if (arr[mid] &amp;lt; target) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }

    return -1; // Target not found
}

// Example Usage
const sortedArray = [1, 3, 5, 7, 9, 11];
const target = 5;
const result = binarySearch(sortedArray, target);
console.log(result); // Output: 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Explanation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Initial Step:&lt;/strong&gt; The array is divided into two halves.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recursive Check:&lt;/strong&gt; The middle element is compared with the target value.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Combine:&lt;/strong&gt; The result is obtained by determining whether the target exists in the left or right sub-array.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Use Divide and Conquer?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Efficiency:&lt;/strong&gt; It reduces the problem size exponentially at each step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scalability:&lt;/strong&gt; Works well for large datasets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simplicity:&lt;/strong&gt; Many complex problems can be broken down into smaller, manageable parts.&lt;/p&gt;




&lt;h2&gt;
  
  
  Applications in Real Life
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Sorting Algorithms:&lt;/strong&gt; Merge Sort and Quick Sort use Divide and Conquer to efficiently sort data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Searching Algorithms:&lt;/strong&gt; Binary Search significantly reduces the time complexity of searching operations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Optimization Problems:&lt;/strong&gt; Dynamic programming often builds upon the Divide and Conquer principle.&lt;/p&gt;




&lt;h2&gt;
  
  
  Practice Problem
&lt;/h2&gt;

&lt;p&gt;Try implementing a mergeSort algorithm using the Divide and Conquer pattern. Here’s a quick outline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Divide the array into two halves.&lt;/li&gt;
&lt;li&gt;Recursively sort each half.&lt;/li&gt;
&lt;li&gt;Merge the sorted halves into a single sorted array.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;Stay tuned for the next post in this series, where we’ll dive into the Dynamic Programming Pattern. It’s a game-changer for solving optimization problems efficiently!&lt;/p&gt;

&lt;p&gt;The Divide and Conquer pattern is a cornerstone of algorithm design. By mastering it, you’ll gain the ability to tackle complex problems more efficiently and with greater confidence.&lt;/p&gt;

&lt;p&gt;Happy coding! Let me know your thoughts and experiences with this pattern in the comments below.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Problem Solving Patterns (Part 3)</title>
      <dc:creator>kanishkaisuru</dc:creator>
      <pubDate>Sun, 01 Sep 2024 06:39:44 +0000</pubDate>
      <link>https://dev.to/kanishkaisuru/problem-solving-patterns-2je1</link>
      <guid>https://dev.to/kanishkaisuru/problem-solving-patterns-2je1</guid>
      <description>&lt;p&gt;&lt;strong&gt;Welcome Back to the Problem Solving Patterns Series&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In our journey to become more efficient problem solvers, we've already explored two fundamental patterns: &lt;strong&gt;Frequency Counters&lt;/strong&gt; and &lt;strong&gt;Multiple Pointers&lt;/strong&gt;. These patterns have given us tools to approach and solve problems with greater clarity and efficiency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recap of Previous Patterns&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Frequency Counters&lt;/strong&gt; (&lt;a href="https://dev.to/kanishkaisuru/problem-solving-patterns-54f8"&gt;Part1&lt;/a&gt;): We learned how to use objects or sets to keep track of frequencies in problems where counting or checking for uniqueness is crucial.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multiple Pointers&lt;/strong&gt; (&lt;a href="https://dev.to/kanishkaisuru/problem-solving-patterns-3pf8"&gt;Part2&lt;/a&gt;): We explored how using pointers to represent different positions in a data structure can help solve problems that involve sequences or pairs, often in a more space-efficient way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Introducing the Sliding Window Pattern&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now, let's move on to the third pattern in our series: the Sliding &lt;strong&gt;Window&lt;/strong&gt;. This pattern is particularly useful for solving problems involving a contiguous subset of elements in an array or string. Whether it's finding the maximum sum of a subarray of fixed size or checking for the existence of a specific sequence, the Sliding Window technique can significantly reduce time complexity compared to a brute-force approach.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deep Dive into the Sliding Window Pattern&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Sliding Window pattern is an incredibly efficient technique used when dealing with problems involving a subset of data elements that are contiguous in nature, such as subarrays or substrings. Instead of recalculating for each possible subset, we "slide" a window across the data to find our solution in a more optimized way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example Problem: Maximum Sum Subarray of Size K&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem Statement&lt;/strong&gt;: Given an array of integers and a number k, find the maximum sum of a subarray of size k.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: arr = [2, 1, 5, 1, 3, 2], k = 3
Output: 9
Explanation: Subarray with maximum sum is [5, 1, 3].
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function maxSubArraySum(arr, num){
    if(num &amp;gt; arr.length){
        return null;
    }

    var max = -Infinity;

    for (let i = 0; i &amp;lt; arr.length - num + 1; i++) {
        temp = 0;
        for (let j = 0; j &amp;lt; num; j++) {
            temp += arr[i+j]
        }
        if(temp &amp;gt; max){
            max = temp
        }
    }
    return max
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;Time Complexity - O(N^2)&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step-by-Step Guide using Sliding Window Pattern:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Understanding the Brute Force Approach:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;In a &lt;strong&gt;brute-force&lt;/strong&gt; solution, we would calculate the sum of every possible subarray of size &lt;code&gt;k&lt;/code&gt; and keep track of the maximum sum.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This approach has a time complexity of &lt;strong&gt;O(n * k)&lt;/strong&gt;, where n is the length of the array. For large arrays, this becomes inefficient.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Space Complexity: O(1) since we only use a few extra variables for calculation.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Introducing the Sliding Window Approach:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Instead of recalculating the sum for each subarray, we maintain a running sum of the current window of size k.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;As we slide the window by one element, we subtract the element that is leaving the window and add the element that is entering the window.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Implementing the Sliding Window Approach:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s walk through the problem step by step in JavaScript.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function maxSubarraySum(arr, k) {
    let maxSum = 0;
    let windowSum = 0;
    let windowStart = 0;

    for (let windowEnd = 0; windowEnd &amp;lt; arr.length; windowEnd++) {
        windowSum += arr[windowEnd];                // Add the next element to the window

        // Slide the window, we don't need to slide if we've not hit the required window size of 'k'
        if (windowEnd &amp;gt;= k - 1) {
            maxSum = Math.max(maxSum, windowSum);  // Update the maximum sum
            windowSum -= arr[windowStart];         // Subtract the element going out
            windowStart += 1;                      // Slide the window ahead
        }
    }

    return maxSum;
}

// Test the function
const arr = [2, 1, 5, 1, 3, 2];
const k = 3;
console.log(maxSubarraySum(arr, k));              // Output: 9
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Breaking Down the Code:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Initialize Variables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;maxSum&lt;/code&gt;: Tracks the maximum sum encountered.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;windowSum&lt;/code&gt;: Stores the sum of the current window.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;windowStart&lt;/code&gt;: The index where the window starts.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Sliding the Window:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We iterate over the array, adding each element to the 
&lt;code&gt;windowSum&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Once the window reaches size &lt;code&gt;k&lt;/code&gt;, we check if the current 
&lt;code&gt;windowSum&lt;/code&gt;.
is greater than &lt;code&gt;maxSum&lt;/code&gt; and update &lt;code&gt;maxSum&lt;/code&gt; accordingly.&lt;/li&gt;
&lt;li&gt;We then slide the window by subtracting the element that is going 
out and incrementing &lt;code&gt;windowStart&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Sliding Window pattern is a versatile and powerful technique that can be applied to a variety of problems involving contiguous subarrays or substrings. By understanding and mastering this pattern, you'll be better equipped to tackle more complex challenges efficiently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stay tuned!&lt;/strong&gt; In the next chapter of this series, we will dive into the &lt;strong&gt;Divide and Conquer pattern&lt;/strong&gt;, a fundamental strategy that breaks down complex problems into simpler sub-problems to solve them more effectively.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Problem Solving Patterns (Part 2)</title>
      <dc:creator>kanishkaisuru</dc:creator>
      <pubDate>Sun, 18 Aug 2024 11:59:32 +0000</pubDate>
      <link>https://dev.to/kanishkaisuru/problem-solving-patterns-3pf8</link>
      <guid>https://dev.to/kanishkaisuru/problem-solving-patterns-3pf8</guid>
      <description>&lt;p&gt;&lt;strong&gt;Welcome back to our blog series on problem solving in modern software engineering!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://dev.to/kanishkaisuru/problem-solving-patterns-54f8"&gt;Part 1&lt;/a&gt;, we explored the &lt;strong&gt;Frequency Counter Pattern&lt;/strong&gt;, a powerful technique for optimizing algorithms by efficiently counting the frequency of elements. If you missed it or want a quick refresher, feel free to check it out before continuing.&lt;/p&gt;

&lt;p&gt;In this part, we’ll be diving into another essential pattern: the Multipointer Pattern. This pattern is invaluable when dealing with scenarios where multiple elements need to be compared, searched, or traversed simultaneously. Let’s explore how it works and where you can apply it to improve your code’s efficiency.&lt;/p&gt;

&lt;h2&gt;
  
  
  02. Multipointer Pattern
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The Multipointer Pattern&lt;/strong&gt; is a technique used in algorithm design where multiple pointers (or iterators) are employed to traverse data structures like arrays or linked lists. Instead of relying on a single pointer or loop, this pattern uses two or more pointers that move through the data at different speeds or from different starting points.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example Problem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Write a function called &lt;strong&gt;sumZero&lt;/strong&gt; that accepts a &lt;strong&gt;sorted&lt;/strong&gt; array of integers. The function should find the &lt;strong&gt;first pair&lt;/strong&gt; where the sum is zero. If such a pair exists, return an array that includes both values; otherwise, return &lt;strong&gt;undefined&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sumZero([-3,-2,-1,0,1,2,3]) //output: [-3, 3]
sumZero([-2,0,1,3]) //output: undefined
sumZero([-4, -3, -2, -1, 0, 1, 2, 5]) //output: [-2, 2]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function sumZero(arr){
    for (let i = 0; i &amp;lt; arr.length; i++) {
        for (let j = i+1; j &amp;lt; arr.length; j++) {
            if (arr[i] + arr[j] === 0) {
                console.log(arr[i] + arr[j])
                return [arr[i], arr[j]]
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;&lt;strong&gt;Time Complexity - O(N^2)&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution using Multipointer Pattern&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;step 1: Understand the problem&lt;br&gt;
We need to find two numbers in a **sorted&lt;/strong&gt; array that add up to zero. Since the array is sorted, we can take advantage of this order to find the solution more efficiently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;step 2: Initialize Two Pointers&lt;/strong&gt;&lt;br&gt;
Set up two pointers: one (&lt;strong&gt;left&lt;/strong&gt;) starting at the beginning of the array, and the other (&lt;strong&gt;right&lt;/strong&gt;) starting at the end.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Array: [-4, -3, -2, -1, 0, 1, 2, 5]
Left Pointer (L): -4
Right Pointer (R): 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Calculate the Sum of the Values at the Pointers&lt;/strong&gt;&lt;br&gt;
Add the values at the left and right pointers to get the sum&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Sum = -4 + 5 = 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4: Compare the Sum with Zero&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;If the sum is greater than zero:&lt;/strong&gt; Move the right pointer one step to the left to decrease the sum.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Sum is 1 &amp;gt; 0, so move the right pointer left:

Array: [-4, -3, -2, -1, 0, 1, 2, 5]
Left Pointer (L): -4
Right Pointer (R): 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;If the sum is less than zero:&lt;/strong&gt; Move the left pointer one step to the right to increase the sum.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;New Sum = -4 + 2 = -2
Sum is -2 &amp;lt; 0, so move the left pointer right:

Array: [-4, -3, -2, -1, 0, 1, 2, 5]
Left Pointer (L): -3
Right Pointer (R): 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 5: Repeat the Process&lt;/strong&gt;&lt;br&gt;
Continue moving the pointers and calculating the sum until they meet or a pair is found.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;New Sum = -3 + 2 = -1
Sum is -1 &amp;lt; 0, so move the left pointer right:

Array: [-4, -3, -2, -1, 0, 1, 2, 5]
Left Pointer (L): -2
Right Pointer (R): 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The sum is zero, so the function returns [-2, 2].&lt;/p&gt;

&lt;p&gt;If the loop completes without finding such a pair, return &lt;strong&gt;undefined&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Final Code&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function sumZero(arr) {
  let left = 0;                         // Initialize the left pointer at the start of the array
  let right = arr.length - 1;           // Initialize the right pointer at the end of the array

  while (left &amp;lt; right) {                // Continue until the pointers meet
    const sum = arr[left] + arr[right]; // Calculate the sum of the values at the pointers

    if (sum === 0) {                    // If the sum is zero, return the pair
      return [arr[left], arr[right]];
    } else if (sum &amp;gt; 0) {               // If the sum is greater than zero, move the right pointer left
      right--;
    } else {                            // If the sum is less than zero, move the left pointer right
      left++;
    }
  }

  return undefined;                     // If no pair is found, return undefined
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NOTE:&lt;br&gt;
&lt;strong&gt;Time Complexity: O(n)&lt;/strong&gt; – The function is efficient and scales linearly with the size of the array.&lt;br&gt;
&lt;strong&gt;Space Complexity: O(1)&lt;/strong&gt; – The function uses a minimal amount of additional memory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Multipointer Pattern is a powerful technique for solving problems that involve searching, comparing, or manipulating elements in a sorted data structure. By using multiple pointers that move towards each other, we can significantly improve the efficiency of algorithms, reducing time complexity from O(n²) to O(n) in many cases. This pattern is versatile and can be applied to a wide range of problems, making it an essential strategy for optimizing performance in your code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stay tuned for our next post&lt;/strong&gt;, where we’ll dive into the &lt;strong&gt;Sliding Window Pattern&lt;/strong&gt; another essential tool for tackling problems involving dynamic data segments. It’s an incredibly useful pattern that can help you solve even more complex challenges with ease!&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>Problem Solving Patterns (Part 1)</title>
      <dc:creator>kanishkaisuru</dc:creator>
      <pubDate>Sun, 04 Aug 2024 09:07:15 +0000</pubDate>
      <link>https://dev.to/kanishkaisuru/problem-solving-patterns-54f8</link>
      <guid>https://dev.to/kanishkaisuru/problem-solving-patterns-54f8</guid>
      <description>&lt;p&gt;This blog series is designed for beginner to intermediate programmers who want to improve their problem-solving skills in algorithmic challenges. By the end of this series, you'll be familiar with several key patterns that can help you approach coding problems more effectively.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;br&gt;
When tackling coding challenges, recognizing common problem-solving patterns can help you develop efficient solutions quickly. This blog post is designed for beginner to intermediate programmers who are looking to improve their problem-solving skills in algorithmic challenges. Here are 7 fundamental patterns: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Frequency Counters&lt;/li&gt;
&lt;li&gt;Multiple Pointers&lt;/li&gt;
&lt;li&gt;Sliding Window&lt;/li&gt;
&lt;li&gt;Divide and Conquer&lt;/li&gt;
&lt;li&gt;Dynamic Programming Pattern&lt;/li&gt;
&lt;li&gt;Greedy Pattern&lt;/li&gt;
&lt;li&gt;Backtracking Pattern&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;along with simple examples to illustrate each.&lt;/p&gt;

&lt;p&gt;Today, we'll start with the Frequency Counter Pattern, a fundamental technique that is essential for comparing data and solving problems involving frequencies.&lt;/p&gt;
&lt;h2&gt;
  
  
  01. Frequency Counters
&lt;/h2&gt;

&lt;p&gt;The frequency counter pattern uses objects or sets to collect frequencies of values. This can often avoid the need for nested loops or O(N^2) operations with arrays or strings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example Problem&lt;/strong&gt;&lt;br&gt;
Write a function named &lt;strong&gt;"same"&lt;/strong&gt; that takes two arrays as input. The function should return &lt;strong&gt;"true"&lt;/strong&gt; if every value in the first array has its corresponding value squared in the second array. Additionally, the frequency of the squared values must match the frequency of the original values.&lt;/p&gt;

&lt;p&gt;Example&lt;br&gt;
Input: &lt;code&gt;[1, 2, 3]&lt;/code&gt; and &lt;code&gt;[1, 4, 9]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Output: true&lt;br&gt;
Explanation: Each value in the first array has its corresponding squared value in the second array: &lt;br&gt;
1^2 = 1, 2^2 = 4, 3^3 = 9&lt;/p&gt;

&lt;p&gt;Input: &lt;code&gt;[1, 2, 3]&lt;/code&gt; and &lt;code&gt;[1, 9, 4]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Output: true&lt;br&gt;
Explanation: The second array contains the squared values of the first array, even if they are not in the same order.&lt;/p&gt;

&lt;p&gt;Input: &lt;code&gt;[1, 2, 3]&lt;/code&gt; and &lt;code&gt;[1, 4, 4]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Output: false&lt;br&gt;
Explanation: The second array does not contain the squared value of 3.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function same(arr1, arr2){

    if(arr1.length !== arr2.length){
        return false;
    }
    for(let i=0; i &amp;lt; arr1.length; i++){
        let correctIndex = arr2.indexOf(arr1[i] ** 2)
        if(correctIndex === -1){
            return false;
        }
        arr2.splice(correctIndex,1);
    }
    return true;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most developers use this solution without thinking about this pattern.&lt;br&gt;
&lt;em&gt;&lt;strong&gt;Time Complexity - O(N^2)&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution using Frequency Counter pattern&lt;/strong&gt;&lt;br&gt;
Lets See Step by Step&lt;/p&gt;

&lt;p&gt;I. &lt;strong&gt;Check Lengths&lt;/strong&gt;: First, the function checks if the lengths of the two arrays are different. If they are, it returns false because they cannot have the same frequency of values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function same(arr1, arr2){
  if(arr1.length !== arr2.length){
    return false;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;II. &lt;strong&gt;Count Frequencies&lt;/strong&gt;: The function then counts the frequency of each value in the first array and stores it in &lt;code&gt;frequency_counter1&lt;/code&gt;. Similarly, it counts the frequency of each value in the second array and stores it in &lt;code&gt;frequency_counter2&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function same(arr1, arr2){
  if(arr1.length !== arr2.length){
    return false;
  }

 let frequencyCounter1 = {}
 let frequencyCounter2 = {}

 for(let val of arr1){
   frequencyCounter1[val] = (frequencyCounter1[val] || 0) + 1
 }

 for(let val of arr2){
   frequencyCounter2[val] = (frequencyCounter2[val] || 0) + 1
 }

 console.log(frequencyCounter1, frequencyCounter2)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you put this example&lt;br&gt;
&lt;code&gt;same([1,2,3,2], [9,1,4,4])&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;result is : &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F276io9qoj8bojqqrbt6n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F276io9qoj8bojqqrbt6n.png" alt="Image description" width="800" height="215"&gt;&lt;/a&gt;&lt;br&gt;
We can get each value frequency like the above.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; : Using two separate loops instead of a nested loop reduces the time complexity of quadratic 𝑂(N^2) to linear O(N). This makes the algorithm more efficient, especially for large inputs, as the number of operations is significantly lower.&lt;/p&gt;

&lt;p&gt;III. Compare Frequencies: Finally, the function compares the frequency of each value in frequency_counter1 with the frequency of its squared value in frequency_counter2. If any value does not match, the function returns false. and Return &lt;strong&gt;True&lt;/strong&gt;: If all values match, the function returns true.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function same(arr1, arr2){
  if(arr1.length !== arr2.length){
    return false;
  }

 let frequencyCounter1 = {}
 let frequencyCounter2 = {}

 for(let val of arr1){
   frequencyCounter1[val] = (frequencyCounter1[val] || 0) + 1
 }

 for(let val of arr2){
   frequencyCounter2[val] = (frequencyCounter2[val] || 0) + 1
 }

 console.log(frequencyCounter1, frequencyCounter2)

 for (let key in frequencyCounter1) {
     if (!(key ** 2 in frequencyCounter2)) {
         return false
     }
     if(frequencyCounter2[key ** 2] !== frequencyCounter1[key]) {
         return false
     }
 }
 return true

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;Time Complexity - O(N)&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br&gt;
The Frequency Counter Pattern is a powerful tool for solving problems that involve comparing data or counting frequencies. By using this pattern, you can tackle a wide range of algorithmic challenges more effectively. Practice using this pattern with different problems to enhance your problem-solving skills.&lt;/p&gt;

&lt;p&gt;Stay tuned for the next post in our series, where we'll explore the Multiple Pointers Pattern. If you have any questions or examples to share, feel free to leave a comment below!&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
