<?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: Michael Stromberg</title>
    <description>The latest articles on DEV Community by Michael Stromberg (@mjstromberg).</description>
    <link>https://dev.to/mjstromberg</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%2F994807%2F4490cefa-a3a8-40f0-8cb7-b5c35344f59e.jpeg</url>
      <title>DEV Community: Michael Stromberg</title>
      <link>https://dev.to/mjstromberg</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mjstromberg"/>
    <language>en</language>
    <item>
      <title>How to Create a Memoization Function in JavaScript</title>
      <dc:creator>Michael Stromberg</dc:creator>
      <pubDate>Sun, 22 Dec 2024 19:30:54 +0000</pubDate>
      <link>https://dev.to/mjstromberg/how-to-create-a-memoization-function-in-javascript-2pg1</link>
      <guid>https://dev.to/mjstromberg/how-to-create-a-memoization-function-in-javascript-2pg1</guid>
      <description>&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%2Fag4jjyn3425w1nneb627.jpg" 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%2Fag4jjyn3425w1nneb627.jpg" alt="An old file cabinet with organized cards in a drawer" width="800" height="532"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Memoization?
&lt;/h2&gt;

&lt;p&gt;In software programming, memoization is a technique used to make applications run faster. If you have a function with high time complexity that blocks execution for too long, or your application has a function that is invoked frequently such that a small optimization in time complexity results in a much faster overall runtime, memoization can shorten execution times and improve user experiences.&lt;/p&gt;

&lt;p&gt;Outside of software engineering, there are many examples in the real world that are analogous to memoization. Frequently Asked Question (FAQ) pages are a perfect example of where certain questions are asked so often that sites will dedicate resources to preemptively provide those answers to their users so they don’t have to search for them.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Memoization Optimization Works
&lt;/h2&gt;

&lt;p&gt;In software, optimization often comes in two forms: reducing superfluous complexity or substituting one complexity for another. Memoization optimizes for runtime by utilizing more memory. Therefore, memoization often decreases the time complexity of an algorithm by increasing the space complexity.&lt;/p&gt;

&lt;p&gt;Under the hood, the logic is actually quite simple. For any memoized function, we first check if that function has been invoked with the current parameters. If it hasn’t, we compute the resultant value, store the input/output pair in a cache, and return the value from the function. On the other hand, if the function has already been invoked with the given parameters, the resultant value will already be cached. So in this case, the function will simply return the cached value without recomputing.&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%2Fdu58ngfp71ltkanupjod.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%2Fdu58ngfp71ltkanupjod.png" alt="An illustration of memoization logic" width="800" height="362"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;An illustration of memoization logic&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the illustration above, the left side shows how the basic flow logic of a function invocation while the right side illustrates memoization. Without memoization, the flow logic for each function invocation is identical: invoke, compute, then return. In contrast, with memoization, there is an intermediate step involving the cache. If the function has yet to be invoked with the parameter permutation, the flow logic is: invoke, check cache, compute, cache result, then return. However, if the function has already encountered these parameters previously, the flow simplifies to: invoke, check cache, then return. Notice that the expensive “compute” step is bypassed on the second invocation. That is the crux of memoization; if the function is computationally expensive, memoization will bypass that step on subsequent invocations.&lt;/p&gt;

&lt;p&gt;The logic behind memoization is actually quite simple itself, but it builds upon a few important concepts that are fundamental.&lt;/p&gt;
&lt;h3&gt;
  
  
  Deterministic Functions
&lt;/h3&gt;

&lt;p&gt;In mathematics and computer science, a function is considered deterministic if the function repeatably produces the same result for a given set of parameters. If a function is not deterministic, memoization can’t be used because the cached value would only reflect the first invocation for a given parameter set. A nondeterministic function is one that depends on something that changes to produce its resultant value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function deterministicFunc(x) {
  return x + 2;
}

function nonDeterministicFunc(x) {
  return x + Date.now();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Examples of a deterministic function and a non-deterministic function&lt;/p&gt;

&lt;p&gt;In the example above, the &lt;code&gt;deterministicFunc&lt;/code&gt; function will always produce the same result for the same given parameter (and the same runtime environment). For example, when &lt;code&gt;deterministicFunc&lt;/code&gt; is passed &lt;code&gt;x = 2&lt;/code&gt;, it will always return &lt;code&gt;4&lt;/code&gt;. However, the &lt;code&gt;nonDeterministicFunc&lt;/code&gt; function doesn’t work the same way. Because the &lt;code&gt;Date.now&lt;/code&gt; invocation will return the current timestamp in milliseconds, this function will return a new value each time. Go ahead and try it out; if you’re in a Chrome browser, hit &lt;code&gt;command + option + j&lt;/code&gt; to open the dev tools (&lt;code&gt;control + shift + j&lt;/code&gt; on a PC), paste in the functions, and invoke them with a parameter.&lt;/p&gt;

&lt;h3&gt;
  
  
  Function Closures
&lt;/h3&gt;

&lt;p&gt;Function closures are a fundamental pillar of computer science and a powerful feature of JavaScript where an inner function retains access to variables from its outer (enclosing) function, even after that outer function has finished executing. This works because JavaScript functions create their own scope, and closures let inner functions access variables from their parent scope. Closures are crucial for data encapsulation, maintaining state, and creating more sophisticated constructs like memoization.&lt;/p&gt;

&lt;p&gt;When a function is returned from another function, it “closes over” the variables in its scope, preserving their values. This behavior enables developers to maintain private variables and state within functions, which is useful for tasks such as caching results or handling asynchronous operations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function outerFunction() {
  let counter = 0; // This variable is part of the closure
  return function innerFunction() {
    counter++;
    console.log(`Counter value: ${counter}`);
  };
}

const incrementCounter = outerFunction(); // Create a closure
incrementCounter(); // Output: Counter value: 1
incrementCounter(); // Output: Counter value: 2

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

&lt;/div&gt;



&lt;p&gt;An example of a function closure in JavaScript&lt;/p&gt;

&lt;p&gt;In this example, the &lt;code&gt;outerFunction&lt;/code&gt; defines a local variable &lt;code&gt;counter&lt;/code&gt;, the &lt;code&gt;innerFunction&lt;/code&gt; is returned and maintains access to the &lt;code&gt;counter&lt;/code&gt; variable through a closure, and even though &lt;code&gt;outerFunction&lt;/code&gt; has finished executing, the &lt;code&gt;counter&lt;/code&gt; variable remains accessible whenever &lt;code&gt;incrementCounter&lt;/code&gt; is called. Closures are particularly useful for memoization because they allow functions to “remember” previous inputs and outputs, enabling efficient caching.&lt;/p&gt;

&lt;h3&gt;
  
  
  Higher Order Functions
&lt;/h3&gt;

&lt;p&gt;Higher order functions are those that take one or more functions as arguments, return another function, or do both. This concept is a cornerstone of functional programming, enabling flexible, reusable, and composable code. Higher-order functions treat functions as first-class citizens, meaning functions can be stored in variables, passed as arguments, and returned from other functions.&lt;/p&gt;

&lt;p&gt;Higher-order functions and closures are foundational to implementing memoization in JavaScript. They enable memoization by wrapping a function with caching logic without changing its core behavior. A memoization function takes another function as input, adds caching, and returns an optimized version for reuse across multiple scenarios.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function applyOperation(array, operation) {
  // Applies the passed function to each element
  return array.map(operation);
}

// Example usage
const numbers = [1, 2, 3, 4];
const square = (x) =&amp;gt; x * x;

const squaredNumbers = applyOperation(numbers, square);
console.log(squaredNumbers); // Output: [1, 4, 9, 16]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An example of a higher order function in JavaScript&lt;/p&gt;

&lt;p&gt;Here, the &lt;code&gt;applyOperation&lt;/code&gt; function is a higher-order function because it takes another function (&lt;code&gt;operation&lt;/code&gt;) as an argument. The &lt;code&gt;operation&lt;/code&gt; function is applied to each element of the &lt;code&gt;array&lt;/code&gt; using the &lt;code&gt;map&lt;/code&gt; method. By passing a specific operation like &lt;code&gt;square&lt;/code&gt;, we can easily customize the behavior of &lt;code&gt;applyOperation&lt;/code&gt; without changing its implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Memoization Implementation in JavaScript
&lt;/h2&gt;

&lt;p&gt;In software development, we usually try to avoid reinventing the wheel. However, in software interviews, we’re often tasked with doing exactly that. Let’s reinforce our understanding of memoization through JavaScript examples.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Basic Implementation of a Memoization Function
&lt;/h3&gt;

&lt;p&gt;At its core, a memoization function needs to track if a function has been invoked with the same given parameters previously and return that cached value if it has. Let’s create a function in JavaScript that does exactly that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function memoize(fn) {
  const cache = new Map();

  return function (...args) {
    const key = JSON.stringify(args);

    if (cache.has(key)) {
      return cache.get(key);
    } else {
      const result = fn(...args);
      cache.set(key, result);
      return result;
    }
  };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are four main aspects of this function that warrant discussion:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Cache Storage: The &lt;code&gt;Map&lt;/code&gt; object is used to store cached results, with keys derived from the function arguments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key Generation&lt;/strong&gt; : The arguments are converted to a unique string key using &lt;code&gt;JSON.stringify&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache Check&lt;/strong&gt; : If the key exists in the cache, the function retrieves and returns the cached result.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;New Computations&lt;/strong&gt; : If the key isn’t found in the &lt;code&gt;Map&lt;/code&gt; lookup, the result is computed, cached, and returned.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This approach makes the function reusable and efficient, especially for computationally expensive tasks with repeated inputs.&lt;/p&gt;

&lt;h3&gt;
  
  
  An Advanced Implementation of a Memoization Function
&lt;/h3&gt;

&lt;p&gt;The simple implementation works great if our function only accepts simple parameters, like primitives. If we want our memoization function to work with more complex parameters like objects, we’ll need to adjust how we handle these parameters.&lt;/p&gt;

&lt;p&gt;However, attempting to memoize functions that accept complex data structures as parameters is more complicated than it may seem initially. This is because data structures are usually mutable — they are often used to dynamically store data — and if the output of your memoized function depends on those data structure properties, you’ll need to serialize all of those to see if they’ve changed between invocations.&lt;/p&gt;

&lt;p&gt;So, while memoization is not reliable for data structures that are storing data dynamically, there are scenarios where memoization makes sense for object parameters. Examples of this are when you know your object won’t be mutated, or if an object is immutable like when using &lt;code&gt;Object.freeze()&lt;/code&gt; for static data. Let’s take a look at the implementation of the enhanced memoization function to handle object types.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function memoize(fn) {
  const cache = new Map();

  return function (...args) {
    let currentCache = cache;

    for (const arg of args) {
      const key = typeof arg === 'object' &amp;amp;&amp;amp; arg !== null
        ? arg
        : JSON.stringify(arg);

      if (!currentCache.has(key)) {
        currentCache.set(key, new Map());
      }

      currentCache = currentCache.get(key);
    }

    if (currentCache.has('result')) {
      return currentCache.get('result');
    } else {
      const result = fn(...args);
      currentCache.set('result', result);
      return result;
    }
  };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key improvements of this enhanced version are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Nested &lt;code&gt;Map&lt;/code&gt; Structure&lt;/strong&gt; : Arguments are stored hierarchically in nested &lt;code&gt;Map&lt;/code&gt; objects, avoiding reliance on stringifying objects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Object Keys&lt;/strong&gt; : Objects are directly used as keys when possible, leveraging JavaScript’s ability to store object references in &lt;code&gt;Map&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved Cache Robustness&lt;/strong&gt; : Handles complex arguments and avoids issues with &lt;code&gt;JSON.stringify&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Memoization is a powerful programming technique that optimizes function performance by caching the results of expensive computations and reusing them when the same inputs occur. This approach significantly improves efficiency, especially for functions with repetitive and deterministic calculations, by reducing redundant processing.&lt;/p&gt;

&lt;p&gt;Memoization is most effective for computationally expensive operations with repeated inputs, such as recursive algorithms or data-heavy tasks. However, it may not be suitable for functions with highly dynamic inputs or when memory usage is a concern, as caching can increase memory consumption.&lt;/p&gt;

&lt;p&gt;When working with data structures like &lt;code&gt;Map&lt;/code&gt;, &lt;code&gt;Set&lt;/code&gt;, or objects as parameters, memoization faces limitations. Cache consistency depends on whether inputs are handled by reference or through serialization. Using references limits reuse to identical instances, while serialization can be computationally expensive and may not handle complex cases like circular references. Understanding these trade-offs helps determine when memoization is the right tool for the job.&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://codingbootcampguides.com/how-to-create-a-memoization-function-in-javascript/" rel="noopener noreferrer"&gt;How to Create a Memoization Function in JavaScript&lt;/a&gt; first appeared on &lt;a href="https://codingbootcampguides.com" rel="noopener noreferrer"&gt;Coding Bootcamp Guides&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>fundamentals</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Solving the “Longest Increasing Subsequence” Problem in JavaScript</title>
      <dc:creator>Michael Stromberg</dc:creator>
      <pubDate>Mon, 18 Nov 2024 04:07:46 +0000</pubDate>
      <link>https://dev.to/mjstromberg/solving-the-longest-increasing-subsequence-problem-in-javascript-1p6g</link>
      <guid>https://dev.to/mjstromberg/solving-the-longest-increasing-subsequence-problem-in-javascript-1p6g</guid>
      <description>&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%2Fe4bz40fq22rxmsxie8d0.jpg" 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%2Fe4bz40fq22rxmsxie8d0.jpg" alt="A bird's-eye view of a spiral staircase" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Photo by Thomas Serer on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Tackling algorithmic challenges is a crucial part of coding interviews, particularly for software engineering roles at top tech companies such as Google, Meta, and Amazon. Although these problems may not represent the daily tasks of an engineer, or reliably forecast long-term performance, thorough preparation remains essential.&lt;/p&gt;

&lt;p&gt;Regular practice, familiarity with common problem-solving strategies, and the ability to explain the pros and cons of your solutions are vital for securing job offers in a competitive market or being accepted into a respected coding bootcamp. Mastering time and space complexity analysis, and clearly communicating your approach will set you apart in these evaluations.&lt;/p&gt;
&lt;h2&gt;
  
  
  The “Longest Increasing Subsequence” Problem on LeetCode in JavaScript
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://leetcode.com/problems/longest-increasing-subsequence/description/" rel="noopener noreferrer"&gt;Longest Increasing Subsequence&lt;/a&gt; problem on LeetCode says that: given an integer array &lt;code&gt;nums&lt;/code&gt;, return the length of the longest strictly increasing subsequence. In this instance, a subsequence is an array that can be derived from another array by deleting zero or more elements without changing the order of the remaining elements.&lt;/p&gt;

&lt;p&gt;For example, given the array &lt;code&gt;[10, 9, 2, 5, 3, 7, 101, 18]&lt;/code&gt;, one of the longest increasing subsequences is &lt;code&gt;[2, 3, 7, 101]&lt;/code&gt;, and the length of this subsequence is 4.&lt;/p&gt;
&lt;h2&gt;
  
  
  Solving the Longest Increasing Subsequence Problem Using A Brute Force Approach
&lt;/h2&gt;

&lt;p&gt;The first approach that comes to mind is an iterative, dynamic programming solution where we compare each element with all previous elements. If the current element is larger than a previous one, it might contribute to forming a longer subsequence. We’ll keep track of the length of the longest increasing subsequence that ends at each index of the given array, and after we finish iterating through every possible subsequence, we’ll circle back and report the length of the largest one we found.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Building a Mental Model for the Brute Force Approach&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Sometimes building a mental model for dynamic programming algorithms can be a little difficult. Let’s take a look at a visual representation to make this algorithm more mentally digestible.&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%2F4zj7g8qg70oeu74jq8e4.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%2F4zj7g8qg70oeu74jq8e4.png" alt="A visual representation of a brute force approach to solving the Longest Increasing Subsequence problem" width="800" height="495"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A visual representation of a brute force approach to solving the Longest Increasing Subsequence problem&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;A JavaScript Implementation of a Brute Force Solution to the Longest Increasing Subsequence Problem&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Now that our mental model is solidified, let’s see what this looks like in code. I always recommend working through a mental model prior to coding because it removes a layer of complexity while you’re designing your algorithm.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function lengthOfLIS(nums) {
    if (nums.length === 0) return 0;

    const maxSubsequenceLengths = new Array(nums.length).fill(1);

    for (let i = 1; i &amp;lt; nums.length; i++) {
        for (let j = 0; j &amp;lt; i; j++) {
            if (nums[i] &amp;gt; nums[j]) {
                const currentMax = maxSubsequenceLengths[i];
                const newMaxCandidate = maxSubsequenceLengths[j] + 1;

                maxSubsequenceLengths[i] = Math.max(
                  currentMax,
                  newMaxCandidate
                );
            }
        }
    }

    return Math.max(...maxSubsequenceLengths);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Handle empty array:&lt;/strong&gt;
Our base algorithm isn’t set up to handle an empty &lt;code&gt;nums&lt;/code&gt; array parameter, so we’ll add the &lt;code&gt;if&lt;/code&gt; statement at the beginning of the function to short-circuit the algorithm and return &lt;code&gt;0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Initialize our maximum subsequence counter&lt;/strong&gt; :
Here, we instantiate a new array with a length that matches the length of the incoming &lt;code&gt;nums&lt;/code&gt; array. Then, we fill it with &lt;code&gt;1&lt;/code&gt; values so as to initialize every maximum subsequence length to be &lt;code&gt;1&lt;/code&gt;—the smallest possible subsequence length.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Setting up the iteration parameters&lt;/strong&gt; :
In this part of the algorithm, we set up our loops such that we iterate through the entire &lt;code&gt;nums&lt;/code&gt; array, and for each step in that loop, we also march through each item in the array from index 0 up to the current item in the array. So, for each subsequent step in the outer loop, we’re iterating through a large subset of the array.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conditionally updating the maximum subsequence counter:&lt;/strong&gt;
This is the heart of the algorithm and potentially the most important. We check if the current item from the outer loop is greater than the current item from the inner loop. If so, we know that the longest subsequence is at least as long as one more than the longest subsequence that was possible at the inner loop index. Let that sink in. If the current value is larger than the value at the inner loop index, that means that we can add the new value onto the longest subsequence at the inner loop index. After, we’ll update our counter at that index to be the larger of the existing value there and the length of the subsequence we just calculated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Final results:&lt;/strong&gt;
Finally, we can find the largest subsequence length in our counter array and return that.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Time and Space Complexity&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This solution has a time complexity of &lt;code&gt;O(n²)&lt;/code&gt; where &lt;code&gt;n&lt;/code&gt; is the number of elements in the input array &lt;code&gt;nums&lt;/code&gt;. This is because we have a nested loop: the outer loop runs through each element, and the inner loop compares it with all previous elements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solving the Longest Increasing Subsequence Problem Using An Optimized Approach
&lt;/h2&gt;

&lt;p&gt;Although the dynamic programming approach works, there’s an even more optimized solution using a combination of binary search and dynamic programming that can bring the time complexity down even further.&lt;/p&gt;

&lt;p&gt;Use a helper array (sub) that will store the smallest possible tail value for increasing subsequences of different lengths. For each element in &lt;code&gt;nums&lt;/code&gt;, use binary search to find its position in the &lt;code&gt;sub&lt;/code&gt; array and either replace an existing value or append the new value, ensuring that sub always remains sorted.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Building a Mental Model for the Optimized Approach&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Again, building a mental model is important step in algorithm design, so we’ll build one in a similar style to prior one so we can compare.&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%2F0dy3lr6g7t30xcqua1d2.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%2F0dy3lr6g7t30xcqua1d2.png" alt="A visual representation of an optimized approach to solving the Longest Increasing Subsequence problem" width="800" height="502"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A visual representation of an optimized approach to solving the Longest Increasing Subsequence problem&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;A JavaScript Implementation of an Optimized Solution to the Longest Increasing Subsequence Problem&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Admittedly, it’s a little difficult to illustrate the entire algorithm in our mental model diagram. While we could have easily added the binary search portion of the routine to the illustration, it might have reduced overall clarity and been counterproductive. Instead, let’s look at the code and we’ll address the binary search routine below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function lengthOfLIS(nums) {
  const sub = [];

  for (let num of nums) {
    // Find the position of 'num' in the sub array using binary search
    let left = 0, right = sub.length;
    while (left &amp;lt; right) {
        let mid = Math.floor((left + right) / 2);

        if (sub[mid] &amp;lt; num) {
          left = mid + 1;
        } else {
          right = mid;
        }
    }

    // If 'num' is larger than any element in sub, append it to the end
    // Otherwise, replace the element at position 'left'
    if (left &amp;gt;= sub.length) {
      sub.push(num);
    } else {
      sub[left] = num;
    }
  }

  return sub.length;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;sub&lt;/code&gt; array
We’ll instantiate an array to store our ongoing longest increasing subsequence. As an aside, you’ll notice we instantiate the array using the &lt;code&gt;const&lt;/code&gt; keyword instead of &lt;code&gt;let&lt;/code&gt; or &lt;code&gt;var&lt;/code&gt;. Although, we’ll push items into the array and potentially overwrite items as we go along, we’ll never reassign the variable, and therefore, we can use &lt;code&gt;const&lt;/code&gt; for a bit of static testing.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;for&lt;/code&gt; loop
This may seem a bit obvious, but there’s no way around iterating through the entire array. Because each subsequent item in the array could be larger in value, we’ll need to check every single item.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;while&lt;/code&gt; loop
In order to optimize the runtime of this algorithm, we can’t use nested &lt;code&gt;for&lt;/code&gt; loops like in our brute force approach. Instead, our inner loop will be a &lt;code&gt;while&lt;/code&gt; loop that implements a binary search to find where the current &lt;code&gt;num&lt;/code&gt; value would be sorted into our &lt;code&gt;sub&lt;/code&gt; array. Because our binary search eliminates half of the items from consideration on each iteration, our &lt;code&gt;while&lt;/code&gt; loop will be less than &lt;code&gt;O(n)&lt;/code&gt; time complexity.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;num&lt;/code&gt; placement
This is where the magic happens. The &lt;code&gt;sub&lt;/code&gt; array keeps track of potential end values of increasing subsequences of different lengths, and by replacing the values using binary search, we efficiently find the best place for each element in the subsequence. This ensures that we are able to maintain a valid increasing subsequence while reducing the overall complexity.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Time and Space Complexity&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Time Complexity&lt;/strong&gt;
Because a binary search is performed on &lt;code&gt;n&lt;/code&gt; elements, the time complexity of this algorithm is &lt;code&gt;O(n x log n)&lt;/code&gt;. That is to say, for all &lt;code&gt;n&lt;/code&gt; elements of the &lt;code&gt;nums&lt;/code&gt; array, we perform an &lt;code&gt;O(log n)&lt;/code&gt; operation, and therefore, the total time complexity becomes &lt;code&gt;O(n x log n)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Space Complexity&lt;/strong&gt;
Similarly to the brute force approach, the space complexity is &lt;code&gt;O(n)&lt;/code&gt;because we store information of length &lt;code&gt;n&lt;/code&gt;—the same length as the &lt;code&gt;nums&lt;/code&gt;array.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Edge Cases to Consider
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Empty Array&lt;/strong&gt;
When the &lt;code&gt;nums&lt;/code&gt; array is empty (i.e. has a length of &lt;code&gt;0&lt;/code&gt;), the algorithm should return &lt;code&gt;0&lt;/code&gt;. Our algorithms handle this by initializing the &lt;code&gt;sub&lt;/code&gt; array as an empty array and returning the length of that array.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;All Array Items Are Equal&lt;/strong&gt;
In the event that all items in the &lt;code&gt;nums&lt;/code&gt; array for equal (e.g. &lt;code&gt;[7, 7, 7, 7]&lt;/code&gt;), the algorithm needs produce &lt;code&gt;1&lt;/code&gt;, since that is the longest subsequence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Array Contains Negative Numbers&lt;/strong&gt;
Negative numbers are valid, and the algorithm should handle them correctly.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Variants of the Number of Islands Problem
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Length of the longest decreasing subsequence&lt;/strong&gt;
Exactly as it sounds, this variant asks you to find the longest decreasing subsequence instead of increasing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Find the longest increasing subsequence itself, not just the length&lt;/strong&gt;
In this case, the brute force approach will not work and you will need to track the actual subsequence like in the optimized approach.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  When To Use Brute Force Versus an Optimized Solution
&lt;/h2&gt;

&lt;p&gt;When solving the Longest Increasing Subsequence problem, the choice between the brute force solution and the optimized solution depends on the context, including the input size, performance constraints, and whether the goal is simply to understand the problem or to solve it efficiently. For large input arrays or where performance is critical, implementing the optimized solution makes sense. If performance isn’t critical and simplicity and clarity are more important, using the brute force solution may be advantageous.&lt;/p&gt;

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

&lt;p&gt;We’ve covered two approaches to solving the “Longest Increasing Subsequence” problem: the dynamic programming solution with a time complexity of &lt;code&gt;O(n²)&lt;/code&gt; and the optimized binary search approach that reduced the time complexity to &lt;code&gt;O(n x log n)&lt;/code&gt;. Both of these approaches use similar memory (&lt;code&gt;O(n)&lt;/code&gt;), but which approach you choose depends on your specific scenario. If you’re asked this question in an interview or any other high-pressure scenario, implement the solution that you’re most comfortable with. Happy coding!&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://codingbootcampguides.com/solving-the-longest-increasing-subsequence-problem-in-javascript/" rel="noopener noreferrer"&gt;Solving the “Longest Increasing Subsequence” Problem in JavaScript&lt;/a&gt; first appeared on &lt;a href="https://codingbootcampguides.com" rel="noopener noreferrer"&gt;Coding Bootcamp Guides&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>algorithmdesignbreak</category>
      <category>algorithmdesign</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Solving the “Number of Islands” Problem in JavaScript</title>
      <dc:creator>Michael Stromberg</dc:creator>
      <pubDate>Sat, 19 Oct 2024 17:26:34 +0000</pubDate>
      <link>https://dev.to/mjstromberg/solving-the-number-of-islands-problem-in-javascript-2oke</link>
      <guid>https://dev.to/mjstromberg/solving-the-number-of-islands-problem-in-javascript-2oke</guid>
      <description>&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%2F841dr6iroqp3azfetck1.jpeg" 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%2F841dr6iroqp3azfetck1.jpeg" alt="A series of islands" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Photo by Cyrus Crossan on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Algorithmic problem-solving is central to coding interviews, especially for software engineering roles at major tech companies like Google, Facebook, and Amazon. While these challenges might not fully reflect day-to-day engineering work or predict long-term success, preparing for them is critical.&lt;/p&gt;

&lt;p&gt;Consistent practice, recognizing common problem-solving patterns, and being able to explain the efficiency and trade-offs of your solutions are key to landing a job offer in a competitive hiring environment or gaining admissions to a reputable coding bootcamp. Demonstrating a clear understanding of time and space complexity and articulating your approach effectively will help you excel in these assessments.&lt;/p&gt;

&lt;h2&gt;
  
  
  The “Number of Islands” Problem on LeetCode in JavaScript
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://leetcode.com/problems/number-of-islands/description/" rel="noopener noreferrer"&gt;Number of Islands&lt;/a&gt; problem on Leetcode asks you to determine the number of distinct islands in a 2D grid, where each island is represented by connected groups of “1”s (land), and “0”s represent water. Two pieces of land are connected if they are adjacent either horizontally or vertically (i.e. diagonal adjacency doesn’t count). The toy problem requires you to count how many separate islands exist in this grid.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem Description
&lt;/h2&gt;

&lt;p&gt;Given an &lt;code&gt;m x n&lt;/code&gt; 2D binary &lt;code&gt;grid&lt;/code&gt; which represents a map of &lt;code&gt;'1'&lt;/code&gt;s (land) and &lt;code&gt;'0'&lt;/code&gt;s (water), return the number of islands.&lt;/p&gt;

&lt;p&gt;An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solving the Number of Islands Problem Using Depth First Search (DFS)
&lt;/h3&gt;

&lt;p&gt;Since we’ll need to check every cell in the matrix while also comparing the relative positions of cells (i.e. if a land cell adjacent to another land cell), using graph traversal will come in handy. Every cell has adjacent cells, and those cells have their own adjacent cells, so designing this algorithm around a graph structure will be optimal. I find DFS easier to conceptualize and more intuitive than Breadth First Search (BFS), so we’ll begin there.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Building a Mental Model for the Depth First Search Solution&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Although graph traversal can be a little intimidating at first, having a strong mental model can make things a lot easier. I like to visualize the algorithm with diagrams.&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%2Fnoa6aw9ug33azfam5xmu.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%2Fnoa6aw9ug33azfam5xmu.png" alt="A diagram illustrating a depth-first search solution to the Number of Islands problem" width="800" height="481"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A diagram illustrating a depth-first search solution to the Number of Islands problem&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In our DFS implementation, we’ll iterate through each row of the matrix until we find a land cell — or a cell with a value of &lt;code&gt;“1”&lt;/code&gt;. We’ll then increment our island count by one and change that cell’s value to “0” to indicate that we’ve already checked it. Then, we’ll recursively check that cell’s adjacent cells — up, down, left, and right — to see if those cells contain land. We’ll continue to recursively check for land until all directions lead to water.&lt;/p&gt;

&lt;p&gt;From there, we’ll continue to iterate through the matrix from where we left off, checking for land along the way. We’ll use the same steps as before when we encounter land, and the algorithm will terminate once we have no cells left to check.&lt;/p&gt;

&lt;h4&gt;
  
  
  A JavaScript Implementation of Depth First Solution to the Number of Islands Problem
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function calculateIsWaterCell(grid, rowIndex, columnIndex) {
  const rowCount = grid.length;
  const columnCount = grid[0].length;
  const isRowOutOfBounds = rowIndex &amp;lt; 0 || rowIndex &amp;gt;= rowCount;
  const isColumnOutOfBounds =
    columnIndex &amp;lt; 0 ||
    columnIndex &amp;gt;= columnCount;
  const isWaterCell =
    isRowOutOfBounds ||
    isColumnOutOfBounds ||
    grid[rowIndex][columnIndex] === '0';

  return isWaterCell;
}

function searchGridForLand(grid, rowIndex, columnIndex) {
  const isWaterCell = calculateIsWaterCell(grid, rowIndex, columnIndex);

  if (!isWaterCell) {
    grid[rowIndex][columnIndex] = '0';

    searchGridForLand(grid, rowIndex - 1, columnIndex);
    searchGridForLand(grid, rowIndex + 1, columnIndex);
    searchGridForLand(grid, rowIndex, columnIndex - 1);
    searchGridForLand(grid, rowIndex, columnIndex + 1);
  }
}

function countIslands(grid) {
  let islandCount = 0;

  if (grid.length &amp;gt; 0) {
    for (let i = 0; i &amp;lt; grid.length; i++) {
      for (let j = 0; j &amp;lt; grid[0].length; j++) {
        const cell = grid[i][j];
        if (cell === '1') {
          islandCount += 1;
          searchGridForLand(grid, i, j);
        }
      }
    }
  }

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

&lt;/div&gt;



&lt;p&gt;Once our mental model is solidified, codifying this algorithm becomes much easier. For clarity, I’ve abstracted out the algorithm logic into three sections:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;calculateIsWaterCell&lt;/strong&gt;
This function is solely focused on determining whether or not a cell is a water cell. Most of the logic is concerned with checking if the cell is out of bounds (outside the body of the grid) because the problem states that the grid itself is surrounded by water. The function also checks if the current cell’s value is &lt;code&gt;“0”&lt;/code&gt;. One could make an argument that this function should not have knowledge of the grid at all, and the function should be further abstracted. I generally agree with that notion, however, readability is important in a tutorial and excessive abstraction works against that goal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;searchGridForLand&lt;/strong&gt;
Again, we are mixing concerns about grids and what constitutes a water cell here, but this is done for clarity. That aside, we’re primarily focused on recursion with this function. The logic checks for land, and if the current cell is land, it will toggle that cell to be water to indicate we’ve already traversed it and then it will recursively check all four directions for adjacent land. Subsequently, if any of those recursive calls also find land, they will continue down the graph with more recursive calls of &lt;code&gt;searchGridForLand&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;countIslands&lt;/strong&gt;
This is the entry point to the algorithm, and it is responsible for counting islands and iterating through the cell matrix. When we do encounter land, we’ll increment our &lt;code&gt;islandCount&lt;/code&gt; variable and then recursively check for adjacent land cells.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Time and Space Complexity
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Time Complexity&lt;/strong&gt;
The time complexity of this solution is considered &lt;code&gt;O(m × n)&lt;/code&gt;, where &lt;code&gt;m&lt;/code&gt; is the number of rows and &lt;code&gt;n&lt;/code&gt; is the number of columns in the grid. For clarity, you can think of this complexity as &lt;code&gt;O(n²)&lt;/code&gt; because &lt;code&gt;m&lt;/code&gt; and &lt;code&gt;n&lt;/code&gt; are effectively equal as they both approach infinity. In the worst case, we may need to visit all cells, and each cell is visited only once, so the complexity is proportional to the number of cells.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Space Complexity&lt;/strong&gt;
This algorithm is considered to have &lt;code&gt;O(m × n)&lt;/code&gt; space complexity. Due to the recursion stack used by DFS — particularly if the grid is filled with land cells forming a single large island — the stack depth could equal the total number of cells.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Solving the Number of Islands Problem Using Breadth First Search (BFS)
&lt;/h3&gt;

&lt;p&gt;Breadth First Search (BFS) is an important concept to learn and can be a useful tool in certain situations, but I find it more complicated to understand and unnecessary in most cases. Nonetheless, we’ll take this opportunity to show you the difference and examine its efficiency.&lt;/p&gt;

&lt;h4&gt;
  
  
  Building a Mental Model for the Breadth First Search Solution
&lt;/h4&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%2Fmduei0jparosccnlbblo.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%2Fmduei0jparosccnlbblo.png" alt="A diagram illustrating a breadth-first search solution to the Number of Islands problem" width="800" height="480"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A diagram illustrating a breadth-first search solution to the Number of Islands problem&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Similarly to the DFS implementation, we’ll start by iterating through each row of the matrix until we find a land cell (&lt;code&gt;“1”&lt;/code&gt;). We also increment our island count at this level, but you’ll notice we check the entire “level” — also sometimes “layer” or “depth” — and we enqueue each of those cells before we dive deeper into them to check their descendants for land.&lt;/p&gt;

&lt;h4&gt;
  
  
  A JavaScript Implementation of Breadth First Solution to the Number of Islands Problem
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function calculateIsWaterCell(grid, rowIndex, columnIndex) {
    const rowCount = grid.length;
    const columnCount = grid[0].length;
    const isRowOutOfBounds = rowIndex &amp;lt; 0 || rowIndex &amp;gt;= rowCount;
    const isColumnOutOfBounds = columnIndex &amp;lt; 0 || columnIndex &amp;gt;= columnCount;
    const isCellWater = 
        isRowOutOfBounds ||
        isColumnOutOfBounds ||
        grid[rowIndex][columnIndex] === '0';

    return isCellWater;
}

function searchGridForLand(grid, rowIndex, columnIndex) {
    const queue = [[rowIndex, columnIndex]];
    grid[rowIndex][columnIndex] = '0';

    while (queue.length &amp;gt; 0) {
        const [i, j] = queue.shift();
        const newCellsToCheck = [
            [i - 1, j],
            [i + 1, j],
            [i, j - 1],
            [i, j + 1]
        ];

        for (let [newI, newJ] of newCellsToCheck) {
            const isCellWater = calculateIsWaterCell(grid, newI, newJ);

            if (!isCellWater) {
                queue.push([newI, newJ]);
                grid[newI][newJ] = '0';
            }
        }
    }
}

function countIslands(grid) {
    let islandCount = 0;

    if (grid.length &amp;gt; 0) {
        for (let i = 0; i &amp;lt; grid.length; i++) {
            for (let j = 0; j &amp;lt; grid[0].length; j++) {
                const cell = grid[i][j];
                if (cell === '1') {
                    islandCount += 1;
                    searchGridForLand(grid, i, j);
                }
            }
        }
    }

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

&lt;/div&gt;



&lt;p&gt;You’ll notice in this implementation that the code for the &lt;code&gt;countIslands&lt;/code&gt; and &lt;code&gt;calculateIsWaterCell&lt;/code&gt; functions are identical to their respective DFS versions. That is because I purposefully separated concerns and abstracted out the core responsibilities into isolated functions. Now, it makes it easier to swap out the graph traversal logic — the code body inside of the &lt;code&gt;searchGridForLand&lt;/code&gt; function — and for others to easily read and digest the algorithm.&lt;/p&gt;

&lt;p&gt;Let’s break down the logic piece by piece:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First, we create a bare-bones &lt;code&gt;queue&lt;/code&gt; and initialize it with the indices of the current cell we’re examining. A queue is a linear data structure that follows the First-In-First-Out (FIFO) principle — where elements are added at the back (enqueue) and removed from the front (dequeue) — ensuring that the first element inserted is the first one to be processed. We also mark this cell as already traversed by setting its value to &lt;code&gt;“0”&lt;/code&gt; like we did in our DFS implementation.&lt;/li&gt;
&lt;li&gt;Next we loop through the contents of the queue, check all adjacent cells for land, and enqueue any new land cells we find along the way. Since our logic is constructed using a &lt;code&gt;while&lt;/code&gt; loop, we can keep enqueuing more cells to check and the algorithm will continue until the queue is not empty. In this portion of the function, we also dequeue each cell as we go along so that are &lt;code&gt;while&lt;/code&gt; loop knows when to conclude and we also mark visited cells as water like before.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Time and Space Complexity
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Time Complexity&lt;/strong&gt;
Similarly to the DFS solution, the time complexity of this solution is considered &lt;code&gt;O(m × n)&lt;/code&gt;, where &lt;code&gt;m&lt;/code&gt; is the number of rows and &lt;code&gt;n&lt;/code&gt; is the number of columns in the grid. This is because we still need to iterate through all of the cells, and there isn’t any reason to believe that checking each level completely first before examining their descendant nodes would be any faster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Space Complexity&lt;/strong&gt;
This algorithm is considered to have &lt;code&gt;O(m × n)&lt;/code&gt; space complexity. Due to the recursion stack used by DFS — particularly if the grid is filled with land cells forming a single large island — the stack depth could equal the total number of cells.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Edge Cases to Consider
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Empty Grid&lt;/strong&gt;
If the grid is empty, the number of islands should be 0. This is handled by checking if the grid length is 0 at the start.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;All Water&lt;/strong&gt;
If the grid contains no &lt;code&gt;“1”&lt;/code&gt;s, the function should return 0 since there are no islands to count.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;All Land&lt;/strong&gt;
If the grid consists entirely of land, the algorithm should handle this case by correctly counting either one island.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Variants of the Number of Islands Problem
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Number of Closed Islands&lt;/strong&gt;
A close variant of the Number of Islands problem is where an island is only counted if it is completely surrounded by water on all four sides. This is an awesome variant to practice because it involves using the returned values from the recursive calls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Number of Distinct Islands&lt;/strong&gt;
Another variant where islands that have the same shape (regardless of their orientation) are considered identical and counted only once.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  When To Use Depth First Search Versus Breadth First Search
&lt;/h3&gt;

&lt;p&gt;Choosing between DFS and BFS depends on the problem at hand and the structure of the graph or tree you are traversing. DFS is well-suited for problems where you need to explore all possible paths or “dig deep” into one branch before backtracking. It’s commonly used in scenarios like finding connected components in a graph, solving maze or puzzle problems, or performing topological sorting on a Directed Acyclic Graph (DAG). A real-world example is web crawling, where DFS can explore a website’s structure deeply before moving on to other pages.&lt;/p&gt;

&lt;p&gt;On the other hand, BFS excels when the shortest path or minimum number of steps is important. BFS explores nodes level by level, making it ideal for shortest path problems in unweighted graphs, such as finding the minimum distance between two points in a grid or map. It’s often used in real-world scenarios like GPS navigation systems, where you want the shortest route to a destination, or in social network analysis to find the shortest connection between people. In general, use BFS when proximity is important and DFS when deep exploration or pathfinding is needed.&lt;/p&gt;

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

&lt;p&gt;This problem is an excellent introduction to graph traversal techniques like DFS and BFS, often used in interviews to test a candidate’s understanding of recursive algorithms and grid-based problem-solving.&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://codingbootcampguides.com/solving-the-number-of-islands-problem-in-javascript/" rel="noopener noreferrer"&gt;Solving the “Number of Islands” Problem in JavaScript&lt;/a&gt; first appeared on &lt;a href="https://codingbootcampguides.com" rel="noopener noreferrer"&gt;Coding Bootcamp Guides&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>algorithmdesignbreak</category>
      <category>algorithmdesign</category>
      <category>datastructures</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Solving the “Two Sum” Problem in JavaScript</title>
      <dc:creator>Michael Stromberg</dc:creator>
      <pubDate>Thu, 03 Oct 2024 23:28:50 +0000</pubDate>
      <link>https://dev.to/mjstromberg/solving-the-two-sum-problem-in-javascript-30am</link>
      <guid>https://dev.to/mjstromberg/solving-the-two-sum-problem-in-javascript-30am</guid>
      <description>&lt;p&gt;&lt;a href="https://media.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%2Fo6gggjnda1id76xgo99f.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fo6gggjnda1id76xgo99f.jpeg" alt="An old-school calculator" width="800" height="1072"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Photo by Ben Wicks on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Algorithm design plays a crucial role in coding interviews, especially for software engineering roles. While some companies place more emphasis on algorithmic challenges than others, they are particularly important for larger tech companies like Google, Facebook, and Amazon. Even though solving algorithm problems during an interview may not fully represent your day-to-day performance as an engineer or predict long-term career success, it’s essential to prepare thoroughly.&lt;/p&gt;

&lt;p&gt;To succeed, you must practice regularly, familiarize yourself with common patterns and principles, and be able to articulate the efficiency and trade-offs of your solutions. Understanding how to approach these problems, explain your reasoning, and discuss time and space complexities is a key component of standing out in competitive technical interviews.&lt;/p&gt;

&lt;h2&gt;
  
  
  The “Two Sum” Problem on LeetCode in JavaScript
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://leetcode.com/problems/two-sum/description/" rel="noopener noreferrer"&gt;Two Sum&lt;/a&gt; problem is one of the most popular coding interview questions and is a great introduction to working with arrays, hashing, and optimization in algorithms. The problem is defined as follows:&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem Description
&lt;/h2&gt;

&lt;p&gt;Given an array of integers &lt;code&gt;nums&lt;/code&gt; and an integer &lt;code&gt;target&lt;/code&gt;, return indices of the two numbers such that they add up to &lt;code&gt;target&lt;/code&gt;. You may assume that each input would have exactly one solution, and you may not use the same element twice. You can return the answer in any order.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solving the Two Sum Problem Using Brute Force
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Building a Mental Model for the Brute Force Solution
&lt;/h3&gt;

&lt;p&gt;There are multiple ways to solve the Two Sum problem, but the most optimal solution involves using a hash map (or an object in JavaScript) to track the indices of the elements we’ve seen so far, allowing us to check for the complement of each number efficiently. We’ll walk through this solution as well as the brute force solution for comparison.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fllq8akgju784ckz1k815.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fllq8akgju784ckz1k815.jpeg" alt="A diagram illustrating a brute force method to solving the Two Sum problem" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A diagram illustrating a brute force method to solving the Two Sum problem&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Much like all brute force method solutions, this implementation indiscriminately iterates through every number pair combination. At each iteration, the sum of each pair will be checked to see if it equals &lt;code&gt;target&lt;/code&gt;, and if it does, the algorithm should return the indices of those two numbers.&lt;/p&gt;

&lt;p&gt;The idea is simple enough, so let’s take a look at an JavaScript implementation of this solution.&lt;/p&gt;

&lt;h3&gt;
  
  
  A JavaScript Implementation of a Brute Force Solution to the Two Sum Problem
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fkkfu01u1y8vo3ib43xa5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fkkfu01u1y8vo3ib43xa5.png" alt="JavaScript code for the brute force solution to the Two Sum problem" width="800" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s walk through the code. In this implementation, I chose to use &lt;code&gt;for&lt;/code&gt; loops to iterate through the array of numbers. While it may be considered more idiomatic to use array methods like &lt;code&gt;array.prototype.forEach&lt;/code&gt; here, the 2nd loop in this case is looping through a smaller and smaller subset of the original &lt;code&gt;nums&lt;/code&gt; array each iteration. This means that I would need to perform some operation on the array to shorten it on each step, or I would need to iterate through the entire array in the second loop. Both of these add time complexity.&lt;/p&gt;

&lt;p&gt;Note that you could potentially break out of the nested &lt;code&gt;forEach&lt;/code&gt; calls by throwing an exception, but I would argue that is more complex and difficult to understand than the &lt;code&gt;for&lt;/code&gt; loop solution, and therefore defeats one the main purposes of idiomatic programming.&lt;/p&gt;

&lt;h3&gt;
  
  
  Time and Space Complexity of the Brute Force Solution
&lt;/h3&gt;

&lt;p&gt;With regards to time complexity, this solution is considered &lt;code&gt;O(n²)&lt;/code&gt; because it the typical and worst-case scenarios, the algorithm needs to iterate through the length of the &lt;code&gt;nums&lt;/code&gt; array in a nested fashion. Even if our &lt;code&gt;target&lt;/code&gt; pair is found midway through the array, as &lt;code&gt;n&lt;/code&gt; approaches infinity, &lt;code&gt;n / 2&lt;/code&gt; is still infinity. While this is definitely a brute force solution, one benefit of this solution is that its space complexity is constant, or &lt;code&gt;O(1)&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Solving the Two Sum Problem Optimized for Time&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Now, that we’ve worked through the brute force solution, let’s examine an optimization to speed up the algorithm. If you’re in an interview and you have time left after solving a toy problem, your interviewer will sometimes ask you if there is a more efficient way to implement your algorithm. It’s always a good idea to be prepared to discuss the efficiency of your solution and the possibility of making it better.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building a Mental Model for the Optimized Solution
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fllq8akgju784ckz1k815.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fllq8akgju784ckz1k815.jpeg" alt="A diagram illustrating an optimized method to solving the Two Sum problem" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here, our mental model requires us to visualize how our &lt;code&gt;map&lt;/code&gt; works. On each iteration through our array, we do a lookup on our &lt;code&gt;map&lt;/code&gt; for the matching value needed to sum to our &lt;code&gt;target&lt;/code&gt; value. If it doesn’t exist, we’ll add the current value and its index to the &lt;code&gt;map&lt;/code&gt;, and continue on with the next array iteration. We continue this process until we find a matching sum. When we find it, we return the corresponding indices.&lt;/p&gt;

&lt;h3&gt;
  
  
  A JavaScript Implementation of a Brute Force Solution to the Two Sum Problem
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.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%2F6z1kt7alfayd4cwr89kq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F6z1kt7alfayd4cwr89kq.png" alt="JavaScript code for an optimized solution to the Two Sum problem" width="800" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s analyze the JavaScript implementation to make sure all of the details are clear.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a &lt;code&gt;map&lt;/code&gt; object that we can use to map values to indices. As described previously, we’ll use this to track which values we’ve already encountered.&lt;/li&gt;
&lt;li&gt;Iterate through the array, and for each number, compute the “complement” (&lt;code&gt;target &lt;/code&gt;— &lt;code&gt;num&lt;/code&gt;). The compliment is the value needed to pair with the current number so that the sum equals the &lt;code&gt;target&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Check if the complement exists in the &lt;code&gt;map&lt;/code&gt;. If it does exist, return the current index and the stored index of the complement. However, if it doesn’t exist, add the current number and its index in the &lt;code&gt;map&lt;/code&gt; for future reference.&lt;/li&gt;
&lt;li&gt;Continue this process until you find the pair.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Time and Space Complexity of the Optimized Solution
&lt;/h3&gt;

&lt;p&gt;This approach leverages the efficiency of hash maps, allowing us to solve the problem in one pass through the array and reducing the time complexity of our algorithm to &lt;code&gt;O(n)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However, this improved time efficiency comes at a cost. Since we are storing a reference to the current index for every iteration that doesn’t produce a match, we are increasing our space complexity to &lt;code&gt;O(n)&lt;/code&gt;, or linear.&lt;/p&gt;

&lt;h2&gt;
  
  
  Edge Cases to Consider
&lt;/h2&gt;

&lt;p&gt;Whether working on production code or solving toy problems during an interview, it’s always important to handle edge cases.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;If no solution exists&lt;/strong&gt;
The problem explicitly states that there is always exactly one solution, so we don’t need to handle the case of no solution. However, if this weren’t guaranteed, you should consider handling that scenario. This type of variation might be incorporated in an interview.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Negative numbers and zeroes&lt;/strong&gt;
The algorithm handles negative numbers and zeroes naturally since it treats all integers the same when calculating the complement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Duplicate numbers&lt;/strong&gt;
If the array contains duplicate numbers, the algorithm will still function correctly as it tracks indices, not just values. Keep in mind, it will report the first occurrence of the solution.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Variants of the Two Sum Problem
&lt;/h2&gt;

&lt;p&gt;The Two Sum problem has several common variants, each of which requires slight modifications to the approach. Below are some examples you should consider practicing, or at the vary least, conceptualize how you would solve them as a thought exercise.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Two Sum With the Input Array Sorted&lt;/strong&gt;
In this variant, the input array is already sorted, allowing us to use a two-pointer technique to reduce the space complexity to &lt;code&gt;O(1)&lt;/code&gt; while maintaining the linear time complexity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Three Sum&lt;/strong&gt;
Here, the task is to find three numbers in the array that add up to a target. This can be solved using nested loops like our brute force scenario or a two-pointer technique that can obtain &lt;code&gt;O(n²)&lt;/code&gt; time complexity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Four Sum&lt;/strong&gt;
Similar to the Three Sum problem, the Four Sum problem can be solved using the same techniques. The time complexity for the optimal solution is &lt;code&gt;O(n³)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Two Sum Less Than K&lt;/strong&gt;
Instead of finding an exact sum, this variant asks for the pair whose sum is the largest but less than a given target &lt;code&gt;K&lt;/code&gt;. It can also be solved using sorting and a two-pointer approach.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  When To Use Brute Force Versus the Optimized Solution
&lt;/h2&gt;

&lt;p&gt;Ultimately, deciding which approach to use depends on your specific scenario. If you’re developing a solution in a real-world, production application, you should consider the bounds of your problem. How large can &lt;code&gt;n&lt;/code&gt; be? Is speed critical in this feature or are will this algorithm run in the background? Does the elegant solution compromise readability for your other developers that may need to work on your code in the future?&lt;/p&gt;

&lt;p&gt;Most frequently, however, you’ll only encounter this particular challenge in a contrived environment like an interview. In this case, do what you feel confident in completing in the short timeframe that you have. If you don’t feel comfortable implementing the time-optimized solution, state that to your interviewer. Complete the brute force solution and explain that you believe you can optimize that solution to reduce time complexity by tracking the values you’ve already iterated through. This will go a long way with your interviewer.&lt;/p&gt;

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

&lt;p&gt;The Two Sum problem, like many toy problems, can be solved in multiple ways. It’s worthwhile to try implementing a brute force solution as well as a more optimized one. Trading off space efficiency for time efficiency is a common practice in toy problems and in production code, so familiarizing yourself with the practice will set you up for success.&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://codingbootcampguides.com/solving-the-two-sum-problem-in-javascript/" rel="noopener noreferrer"&gt;Solving the “Two Sum” Problem in JavaScript&lt;/a&gt; first appeared on &lt;a href="https://codingbootcampguides.com" rel="noopener noreferrer"&gt;Coding Bootcamp Guides&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>algorithmdesignbreak</category>
    </item>
    <item>
      <title>Recursion Explained in JavaScript</title>
      <dc:creator>Michael Stromberg</dc:creator>
      <pubDate>Sat, 07 Sep 2024 19:50:05 +0000</pubDate>
      <link>https://dev.to/mjstromberg/recursion-explained-in-javascript-5a62</link>
      <guid>https://dev.to/mjstromberg/recursion-explained-in-javascript-5a62</guid>
      <description>&lt;p&gt;&lt;a href="https://media.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%2Fxn8hpw9dkgkzli54ktpl.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fxn8hpw9dkgkzli54ktpl.jpeg" alt="An infinity mirror in a hallway" width="800" height="800"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Image generated using Google Gemini&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Recursion is a programming technique where a function calls itself to solve a particular problem. It’s especially effective for problems that can be divided into smaller, similar subproblems. By breaking down a complex problem in this way, recursion can often lead to elegant and concise solutions.&lt;/p&gt;

&lt;p&gt;A recursive function repeatedly calls itself with smaller versions of the problem until it reaches a simple, solvable base case. This self-referential approach is a powerful tool for tackling problems that have a recursive structure.&lt;/p&gt;
&lt;h2&gt;
  
  
  A Real-Life Analogy of Recursion
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.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%2Ff0jwphyk655r036jssrq.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Ff0jwphyk655r036jssrq.jpeg" alt="An incomplete jigsaw puzzle on a table" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Photo by Alicia Christin Gerald on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;While the concept can be challenging to grasp, recursion can be likened to solving a jigsaw puzzle. Some puzzle solvers might start by connecting a few pieces together that have similar colors, and they might do so until they have a few groupings of puzzle pieces. They might then connect those groupings into one larger grouping. This strategy can go on until the entire puzzle is completed.&lt;/p&gt;
&lt;h2&gt;
  
  
  Recursion Fundamentals
&lt;/h2&gt;

&lt;p&gt;For some, it can be easier to learn by reading code, but before we can demonstrate recursion by programming out an example, we need to explain some fundamental concepts of recursion.&lt;/p&gt;

&lt;p&gt;In recursion, “cases” are the different scenarios that dictate how a recursive function behaves. These cases logically guide the function on whether to continue recursing or to terminate. Correctly identifying and implementing these cases is essential to ensuring that a recursive function works as intended and doesn’t fall into an infinite loop.&lt;/p&gt;

&lt;p&gt;There are typically two primary cases in recursion: the base case and the recursive case.&lt;/p&gt;
&lt;h3&gt;
  
  
  Base Case
&lt;/h3&gt;

&lt;p&gt;The base case is the condition under which the recursive function stops calling itself. It is the simplest instance of the problem that can be solved directly without further recursion, and it is critical because it prevents infinite recursion by providing a stopping point. The base case stops the recursion when the problem has been reduced to its simplest form or has reached the end of the sequence.&lt;/p&gt;
&lt;h3&gt;
  
  
  Recursive Case
&lt;/h3&gt;

&lt;p&gt;The recursive case is the condition under which the function continues to call itself with modified arguments. In these scenarios, the function makes progress towards the base case by simplifying or reducing the problem with each recursive call. The recursive case helps to break the problem into smaller sub-problems that have the same structure as the original problem, but with simpler or reduced inputs.&lt;/p&gt;
&lt;h2&gt;
  
  
  Recursion in JavaScript
&lt;/h2&gt;

&lt;p&gt;Let’s recreate the &lt;code&gt;Math.pow&lt;/code&gt; method, which calculates the power of a number, using recursion in JavaScript. The &lt;code&gt;Math.pow(base, exponent)&lt;/code&gt; function computes the result of raising the&lt;code&gt;base&lt;/code&gt; value to the power of an &lt;code&gt;exponent&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Recursive &lt;code&gt;Math.pow&lt;/code&gt; Implementation
&lt;/h3&gt;

&lt;p&gt;To implement this method using recursion, we’ll use two main cases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Base Case:&lt;/strong&gt; If the exponent is &lt;code&gt;0&lt;/code&gt;, the result is &lt;code&gt;1&lt;/code&gt; because any number raised to the power of 0 is 1.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recursive Case:&lt;/strong&gt; Multiply the base by the result of the function with the exponent decremented by 1.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here’s the JavaScript implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;recursivePow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;exponent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;exponent&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;exponent&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nf"&gt;recursivePow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;exponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;recursivePow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;exponent&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Explanation of the Code
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Base Case:&lt;/strong&gt; If the &lt;code&gt;exponent&lt;/code&gt; is &lt;code&gt;0&lt;/code&gt;, the function returns &lt;code&gt;1&lt;/code&gt;. This stops the recursion from continuing indefinitely.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Edge Case:&lt;/strong&gt; If the &lt;code&gt;exponent&lt;/code&gt; is negative, the function inverts the &lt;code&gt;base&lt;/code&gt; (i.e. calculates &lt;code&gt;1 / base&lt;/code&gt;) and calls itself with the positive value of the &lt;code&gt;exponent&lt;/code&gt;. This allows the function to correctly compute the result for negative exponents.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recursive Case:&lt;/strong&gt; If the &lt;code&gt;exponent&lt;/code&gt; is positive and greater than &lt;code&gt;0&lt;/code&gt;, the function multiplies the &lt;code&gt;base&lt;/code&gt; by the result of calling itself with the &lt;code&gt;exponent&lt;/code&gt; decremented by &lt;code&gt;1&lt;/code&gt;. The decrementing by one is critical because this causes the recursive calls to home in on base case (i.e. reducing the &lt;code&gt;exponent&lt;/code&gt; by &lt;code&gt;1&lt;/code&gt; until it reaches &lt;code&gt;0&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How the Recursion Unfolds
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fjyf9mfkfaz9fdis86qjo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fjyf9mfkfaz9fdis86qjo.png" alt="A flow diagram visualizing a recursive implementation of Math.pow" width="800" height="624"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A flow diagram visualizing a recursive implementation of Math.pow&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let’s walk through an example where we invoke the recursive power function with a base of &lt;code&gt;2&lt;/code&gt; and a power of &lt;code&gt;3&lt;/code&gt; (&lt;code&gt;recursivePow(2, 3)&lt;/code&gt;). Note, in the illustration above, I’ve omitted the edge case logic for visual clarity.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;recursivePow(2, 3)&lt;/code&gt; returns &lt;code&gt;2 * recursivePow(2, 2)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;recursivePow(2, 2)&lt;/code&gt; returns &lt;code&gt;2 * recursivePow(2, 1)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;recursivePow(2, 1)&lt;/code&gt; returns &lt;code&gt;2 * recursivePow(2, 0)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;recursivePow(2, 0)&lt;/code&gt; returns &lt;code&gt;1&lt;/code&gt; (base case)&lt;/li&gt;
&lt;li&gt;As the call stack unwinds and the function invocations return their values, the result is equivalent to: &lt;code&gt;2 * 2 * 2 * 1 = 8&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This implementation of &lt;code&gt;Math.pow&lt;/code&gt; using recursion is a great way to illustrate the power of recursion by breaking down problems into smaller sub-problems, solving them recursively, and combining the results to obtain the final solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Pros and Cons of Using Recursion
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Pros of Using Recursion
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Optimal Technique:&lt;/strong&gt; For problems that involve manipulating or iterating through dynamic data structures—such as traversing through a tree or linked list—or while designing solutions that involve sorting or using a divide-and-conquer strategy, recursion naturally lends itself to elegant implementations in these scenarios.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Brevity:&lt;/strong&gt; Recursion can often require fewer lines of code compared to their equivalent iterative solutions, which can make the codebase less verbose and cleaner.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons of Using Recursion
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Performance Overhead:&lt;/strong&gt; Recursion can be less memory-efficient than iterative solutions due to the overhead of multiple function calls. Each recursive call adds a new frame to the call stack, which can lead to excessive memory usage and a higher space complexity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Risk of Stack Overflow:&lt;/strong&gt; Anyone first learning about recursion has probably caused a stack overflow. If the recursion depth becomes too deep, it can lead to a stack overflow error, especially in languages with limited stack size. This happens when there are too many nested function calls before reaching the base case. While tail call optimization —where the recursive case is in the tail position and therefore could optimized to not grow the call stack—few JavaScript engines have implemented support for this ECMAScript 6 feature.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debugging Difficulty:&lt;/strong&gt; Recursive functions can be harder to debug and trace, especially if the base case is not correctly defined, leading to infinite recursion.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When to Use Recursion
&lt;/h2&gt;

&lt;p&gt;Recursion is particularly useful when dealing with problems that have a natural recursive structure, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tree Traversal:&lt;/strong&gt; Traversing hierarchical data structures like binary trees or graphs is more intuitive with recursion.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Divide and Conquer Algorithms:&lt;/strong&gt; Algorithms like QuickSort and MergeSort benefit from recursion as they divide the problem into smaller subproblems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Programming:&lt;/strong&gt; Some dynamic programming problems, such as calculating Fibonacci numbers, can be solved using recursion (though they may require memoization to optimize performance).&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Recursion is a powerful tool in a programmer’s toolkit that allows for elegant and concise solutions to complex problems. However, it’s essential to understand when and how to use recursion effectively, considering both its advantages and potential pitfalls. By carefully structuring recursive functions and being mindful of base cases and stack depth, you can harness the full potential of recursion in your software projects.&lt;/p&gt;




&lt;p&gt;If you enjoyed this article, check out &lt;a href="https://codingbootcampguides.com/how-to-build-a-hash-table-in-javascript/" rel="noopener noreferrer"&gt;How to Build a Hash Table in JavaScript&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://codingbootcampguides.com/recursion-explained-in-javascript/" rel="noopener noreferrer"&gt;Recursion Explained in JavaScript&lt;/a&gt; first appeared on &lt;a href="https://codingbootcampguides.com" rel="noopener noreferrer"&gt;Coding Bootcamp Guides&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>fundamentals</category>
      <category>algorithmdesign</category>
      <category>interview</category>
      <category>javascript</category>
    </item>
    <item>
      <title>10 Things I Learned as a Coding Bootcamp Grad</title>
      <dc:creator>Michael Stromberg</dc:creator>
      <pubDate>Mon, 02 Sep 2024 22:01:37 +0000</pubDate>
      <link>https://dev.to/mjstromberg/10-things-i-learned-as-a-coding-bootcamp-grad-1hfc</link>
      <guid>https://dev.to/mjstromberg/10-things-i-learned-as-a-coding-bootcamp-grad-1hfc</guid>
      <description>&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%2F9v076jrxvv7yomgvr4zs.jpg" 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%2F9v076jrxvv7yomgvr4zs.jpg" alt="Coders working side by side at desks." width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Photo by Hack Capital on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I was working in the hard disk drive industry as a Senior Research and Development Engineer when I knew that I wanted to work on software. I had a degree in Mechanical Engineering and an established career with six years of experience, but the idea of switching careers this late in the game was daunting. Could I really handle going back to school? Is it a bad idea to leave my old career behind and start again from the beginning? These are questions that were racing through my head as I was trying to figure out my future.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I needed to figure out what it is that I wanted, and only then figure out how I was going to get there.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I decided to make the switch, but it wasn’t easy. Big life decisions require lots of thought and research, but they also require you to follow your heart. My background in engineering prepared me for problems of this magnitude. I had learned over the years that the best way to tackle a large project or problem is to break it down into its components. And if possible, make these components independent of each other so that you can work on them separately.&lt;/p&gt;

&lt;p&gt;So I decided to split up my large, daunting decision into two smaller, manageable decisions. I needed to figure out what it is that I wanted, and only then figure out how I was going to get there. I wanted to make a career out of working on software projects I cared about. So once I decided that’s what I was going to do, a huge weight was lifted off of my shoulders. I was now energized to figure out how I was going to reach that goal.&lt;/p&gt;

&lt;p&gt;Fast forward to now, I’m a Senior Software Engineer with about 5 years of experience under my belt. At the time, my journey to becoming a software engineer by attending a coding bootcamp was very new and uncommon. Today, it’s a much more popular route, and so I’d like to share a few things I learned along the way.&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%2Femxqa2qxji63sr8swty3.jpg" 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%2Femxqa2qxji63sr8swty3.jpg" alt="A single student sitting in an empty lecture hall" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Photo by Philippe Bout on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Bootcamps can help you learn what you’re capable of
&lt;/h2&gt;

&lt;p&gt;Throughout my life, I’ve always pushed myself to work hard and achieve my goals. I graduated with honors in three years with my Mechanical Engineering degree. I started an apparel printing small business for fun while in grad school. I successfully flipped a property with no prior experience in carpentry or real estate. But completing the &lt;a href="https://codingbootcampguides.com/coding-bootcamp-guides/a-complete-guide-to-the-hack-reactor-coding-bootcamp/" rel="noopener noreferrer"&gt;Hack&lt;/a&gt;&lt;a href="https://codingbootcampguides.com/a-complete-guide-to-the-hack-reactor-coding-bootcamp/" rel="noopener noreferrer"&gt;R&lt;/a&gt;&lt;a href="https://www.hackreactor.com/#" rel="noopener noreferrer"&gt;eactor&lt;/a&gt; bootcamp may have been the most challenging of them all.&lt;/p&gt;

&lt;p&gt;On average, I was in class or studying for 12 to 14 hours per day, 6 days per week, for 3 months straight. Every 2 days we learned about a new technology and how to use it. It was mentally and physically exhausting, while also testing you emotionally. Being away from your friends, family, and normal life for 3 months is no joke. Even if you’re doing a full remote bootcamp, you have almost no free time.&lt;/p&gt;

&lt;p&gt;Bootcamps put you under somewhat artificial pressure by using aggressive deadlines and pushing lofty goals. This pressure will make or break you. I’ve seen a few people fold under the pressure, but for the most part, students are generally able to rise to the challenge and come out well-equipped to handle anything.&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%2F9cxfado2zxx6m68sgmmy.jpg" 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%2F9cxfado2zxx6m68sgmmy.jpg" alt="A man looking out a snowy window at the sea" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Photo by Noah Silliman on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Bootcamps are not for everyone
&lt;/h2&gt;

&lt;p&gt;Not everyone is meant to be a software engineer, and I think that needs to be said. While I think that given enough time and resources everyone can learn to code, that doesn’t mean that everyone should. Being a software engineer means shifting your mindset to programmatic thinking. If that’s a big, unnatural shift for you, you’re probably not going to have a smooth career trajectory.&lt;/p&gt;

&lt;p&gt;Even more so, not everyone is going to be able to successfully complete and thrive in a coding bootcamp. This is because as I mentioned before, bootcamps are physically, mentally, and emotionally demanding. This type of fast-paced, rapidly changing environment can be difficult in general, not just for people trying to break into software development. Some current software engineers wouldn’t thrive in this type of scenario, and similarly, if this format were applied to a different profession, I think it would also prove to be challenging for many.&lt;/p&gt;

&lt;p&gt;The inherent complexity of software engineering curriculum combined with the strenuous nature of the bootcamp format produces an entirely new dimension of education difficulty. It’s not for everyone, but for whom it does appeal to, it can easily be the best option to crack into software development.&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%2Ftsd3jukyq2andrmbbkg9.jpg" 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%2Ftsd3jukyq2andrmbbkg9.jpg" alt="A woman with a book covering her face standing in front of a brick wall" width="800" height="525"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Photo by Siora Photography on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Bootcamps don’t really teach you much and that’s okay
&lt;/h2&gt;

&lt;p&gt;Syllabi vary from bootcamp to bootcamp, but to become a passable software engineer, you have to code. A lot. You have to code all day, every day. That’s one thing that all bootcamps have in common: they know how much you need to code. That doesn’t leave a lot of time for lecturing, one-on-one tutoring, or much of anything else.&lt;/p&gt;

&lt;p&gt;Hack Reactor was structured with 2-day “sprints” for the first half of the bootcamp. For the most part, the beginning of each sprint began with a short lecture where a new technology or concept was introduced. The rest was coding. And these introductions weren’t deep dives, they were just enough to get you going or to point you in the right direction. The value of the bootcamp isn’t in its lecture time or its world-renowned staff. The primary value is derived from two different sources: the brand name and the power to produce autonomous engineers.&lt;/p&gt;

&lt;p&gt;At first, the brand name didn’t mean much. Without a Computer Science (CS) degree, you were going to have a difficult time getting an interview anywhere. As bootcamps kept producing quality engineers, the brand name became another layer of authentication. Now employers know if you graduate from Hack Reactor, you’ve been put through the wringer.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Given enough time and resources, you can learn anything.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Bootcamps can help you become autonomous. Along the journey you’ll get stuck, you’ll feel lost or burnt out, and you’ll likely get a heavy dose of &lt;a href="https://en.wikipedia.org/wiki/Impostor_syndrome" rel="noopener noreferrer"&gt;impostor syndrome&lt;/a&gt;. But with small nudges in the right direction, you’ll realize the answer is always in the code, you’ll be able to Google your way out of dead-ends, and you’ll start to use computer science principles to write better code. At the end of the bootcamp, you’ll start to understand that given enough time and resources, you can learn anything.&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%2Frdag2pagh7p5tzaso88d.jpg" 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%2Frdag2pagh7p5tzaso88d.jpg" alt="A chess board and set with one pawn a different color than the others" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Photo by Randy Fath on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Imposter Syndrome is real and never really goes away
&lt;/h2&gt;

&lt;p&gt;Most people will experience imposter syndrome at some point in their lives. There will always be someone smarter or who knows the subject matter better than you, and it will make you feel like an imposter. Bootcamps are no exception. In fact, they are little imposter syndrome factories.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Bootcamps help you become comfortable with being uncomfortable.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The nature of a bootcamp is to move fast and figure things out as you go. So you’re essentially guaranteed to feel uncomfortable, and that’s by design. There is always something else to learn, and the assignments always have stretch goals for you to take on if you finish early. Bootcamps help you become comfortable with being uncomfortable.&lt;/p&gt;

&lt;p&gt;So when you land your first job and all of the engineers around you know more than you, you feel like an impostor. But you don’t sweat it because you’ve been there before and you can handle much more than being a little uncomfortable. Imposter syndrome doesn’t go away, it just changes its appearance.&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%2Fw6hnsyweqrlh08d1nco4.jpg" 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%2Fw6hnsyweqrlh08d1nco4.jpg" alt="Plant seedlings in a starter container" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Photo by Markus Spiske on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. New software technologies emerge often and curriculum needs to adapt to keep up
&lt;/h2&gt;

&lt;p&gt;Getting a traditional university Computer Science degree is a great way to land a software engineering job. They help you build a strong technical foundation from the ground up, and the prestige associated with several of the programs out there will give you a leg up on the competition.&lt;/p&gt;

&lt;p&gt;However, universities move at the speed of universities: slow. To be accredited, colleges have to teach certain curriculum standards and meet other comprehensive requirements. CS programs also don’t typically have a lot of incentive to innovate and reevaluate their standards frequently. They historically only really compete amongst other university programs, and the prestige of a program is often established by its research and famous faculty.&lt;/p&gt;

&lt;p&gt;Coding bootcamps operate on a different model. They look to fill the void that traditional CS programs left behind by teaching and stressing technologies that are often only touched upon in elective classes at university. The general CS degree model is to teach fundamentals and use optional elective classes to explore new technologies and trends. Bootcamps invert that model. They stress new technologies and trends and only briefly touch upon fundamentals. This model has proven to be successful because bootcamp graduates:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;have proven they can flourish in a stressful environment,&lt;/li&gt;
&lt;li&gt;have tons of hands-on experience with in-demand technologies, and&lt;/li&gt;
&lt;li&gt;are entering a field that has a rapidly growing demand for their skillset.&lt;/li&gt;
&lt;/ol&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%2Fedj3y0dxsqnzrmqmvfej.jpg" 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%2Fedj3y0dxsqnzrmqmvfej.jpg" alt="A man looking out a window with the blinds open" width="800" height="517"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Photo by Ethan Sykes on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Some bootcamps will fail you and kick you out
&lt;/h2&gt;

&lt;p&gt;When I attended Hack Reactor’s onsite bootcamp in San Francisco, I had no idea you could fail and get kicked out. I knew there was a midterm exam at the halfway point of the course, but I didn’t know the gravity of the situation.&lt;/p&gt;

&lt;p&gt;Along the way, I saw some of my classmates burn out from the extreme pace of the program. I saw another get sick, miss one day, and be so far behind that he never caught up and ended up dropping out. I saw another classmate be told that she didn’t have what it took to succeed in interviews, failed after the midterm exam, only to be reinstated after she complained to them about their assessment of her.&lt;/p&gt;

&lt;p&gt;Overall, I had a great experience at Hack Reactor, and the program went a long way to set me up for success afterward. However, it was frankly unethical to not emphasize the possibility of failure and expulsion from the program before we accepted our invitations. Hopefully, they’ve changed their process and this is no longer a problem.&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%2Fsi9ja6ldj21uahwn7o6h.jpg" 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%2Fsi9ja6ldj21uahwn7o6h.jpg" alt="Arms pointing at a laptop" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Photo by John Schnobrich on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Communication is key
&lt;/h2&gt;

&lt;p&gt;Software engineers are often portrayed in mainstream media as introverted lone wolves that exude a quiet genius as they work on cutting-edge systems. While that may be accurate in some cases, that couldn’t be further from the truth for the majority of software engineers. Yes, a disproportionate amount of software engineers might be introverted, but that doesn’t mean they don’t have to effectively communicate. Communication is essential in software engineering, and successful coding bootcamps are acutely aware of this.&lt;/p&gt;

&lt;p&gt;The first half of the Hack Reactor program is entirely &lt;a href="https://martinfowler.com/articles/on-pair-programming.html" rel="noopener noreferrer"&gt;pair programming&lt;/a&gt;, where they take the “driver and navigator” approach. This helps you practice translating your thoughts to speech and also translating someone else’s direction into code. This provides you the opportunity to practice critiquing someone else’s work which can be difficult to do without stepping on toes or hurting egos.&lt;/p&gt;

&lt;p&gt;The second half of the Hack Reactor program consists of mostly group projects. You get to establish team member roles, dole out responsibilities, practice an effective version management workflow, and many other aspects of working on a team. There is a big difference between working by yourself on a project and working on a team, and in most professional settings you’ll be working on a team.&lt;/p&gt;

&lt;p&gt;Additionally, all along the way, you’re practicing &lt;a href="https://en.wikipedia.org/wiki/Whiteboarding" rel="noopener noreferrer"&gt;whiteboarding&lt;/a&gt;. The practice of simultaneously thinking about how to solve a problem, verbalizing those thoughts, and writing them on a whiteboard feels very unnatural. Hack Reactor provided lots of whiteboarding practice time which not only helped prepare me for interviews but made me a more effective communicator.&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%2Fn9ojijmu09m3et9auefo.jpg" 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%2Fn9ojijmu09m3et9auefo.jpg" alt="A man writing with a pen on papers" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Photo by Scott Graham on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Outcomes are just as important as learning to code
&lt;/h2&gt;

&lt;p&gt;Don’t get me wrong, it will be nearly impossible to land a software engineering job if you don’t know how to code. But let’s consider the scenario where two programmers land entry-level job offers at similar companies. The first is a very talented programmer but doesn’t know their worth nor is an effective negotiator. The second programmer is an average entry-level developer but has been coached on their worth and compensation negotiation. Now let’s imagine they accept approximately the same compensation package as the other. Would you consider this a success for the talented programmer?&lt;/p&gt;

&lt;p&gt;Outcomes are just as important as learning to code. By reframing the goal from “becoming a software engineer” to “becoming an appropriately compensated software engineer”, bootcamps can set you up for long-term success that you didn’t even know you cared about.&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%2Fs8vzgr1e180rjzqdc0ir.jpg" 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%2Fs8vzgr1e180rjzqdc0ir.jpg" alt="A view of a road with several elevation changes" width="800" height="480"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Photo by Matt Duncan on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  9. The bootcamp is just the beginning
&lt;/h2&gt;

&lt;p&gt;Graduating from a coding bootcamp was one of the most validating experiences I’ve had in my lifetime. It took a lot of willpower, and I assumed a lot of risk, but it paid off exactly how I imagined it. However, the bootcamp was just the beginning.&lt;/p&gt;

&lt;p&gt;Most bootcamp students are looking to land a job after they graduate. Software engineering interviews are some of the most stressful and comprehensive interviews in the job market today. You’ll likely have algorithm questions, whiteboarding, system design questions, and behavioral interviews just to start. You might have take-home projects, purposefully arbitrary riddle-like questions, and much more. This means that you have to study a lot. Bootcamps often prepare you for these sorts of interviews, but it takes practice to become good at them.&lt;/p&gt;

&lt;p&gt;Even after you land a job, you’re likely still an entry-level engineer with zero years of experience and a porous knowledge of computer science fundamentals at best. Your intense journey will continue well into your first year on the job. You’ll need to strengthen your core understanding of well-established programming principles that you only truly understand once you have experience not following them. Concepts like &lt;a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself" rel="noopener noreferrer"&gt;Don’t Repeat Yourself (DRY)&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Single-responsibility_principle" rel="noopener noreferrer"&gt;Single-Responsibility Principle (SRP)&lt;/a&gt;, and &lt;a href="https://en.wikipedia.org/wiki/Single_source_of_truth" rel="noopener noreferrer"&gt;Single Source of Truth (SSOT)&lt;/a&gt; are just a few that don’t really hit home until you’ve seen their benefits take shape firsthand.&lt;/p&gt;

&lt;p&gt;Things change once you get a year of experience under your belt. A tidal wave of recruiters will drop upon you like you couldn’t imagine, and lots of doors will open for you. You’ve been battle-tested and are starting to proactively learn and improve your skillset like a more senior engineer. But after all of this, your journey is still ongoing. Software engineers are always learning and keeping up with the latest technologies and trends.&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%2F5q8favwnzvxmqt79a7vr.jpg" 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%2F5q8favwnzvxmqt79a7vr.jpg" alt="A man coding at his laptop near a window during sunset" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Photo by Simon Abrams on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Coding bootcamps are here to stay
&lt;/h2&gt;

&lt;p&gt;When I first started my journey to become a software engineer, I was very skeptical of coding bootcamps. How could one possibly learn enough from an unaccredited school to become a software engineer in 3 months? How could bootcamp grads compete with candidates who have 4-year computer science degrees? It turns out that the answer to both of those questions is “demand”.&lt;/p&gt;

&lt;p&gt;Software is always on the cutting edge and often disrupting the status quo. New technologies and patterns emerge all of the time. Just during my short time on this journey, I’ve already seen the rise of &lt;a href="https://en.wikipedia.org/wiki/Single-page_application" rel="noopener noreferrer"&gt;Single-Page Applications&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Microservices" rel="noopener noreferrer"&gt;Microservices&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Cryptocurrency" rel="noopener noreferrer"&gt;Cryptocurrencies&lt;/a&gt;, &lt;a href="https://www.theverge.com/22310188/nft-explainer-what-is-blockchain-crypto-art-faq" rel="noopener noreferrer"&gt;Non-Fungible Tokens (NFTs)&lt;/a&gt;, and &lt;a href="https://martinfowler.com/articles/micro-frontends.html" rel="noopener noreferrer"&gt;Micro-Frontends&lt;/a&gt; just to name a few. The rise in these new technologies means there must also be a proportional rise in demand for people to develop using those technologies. If the demand isn’t being fulfilled by traditional routes, alternative education solutions will arise to fill in that void.&lt;/p&gt;

&lt;p&gt;Bootcamps are also a part of a larger trend of moving away from universities and their traditional education models. Universities are expensive, bulky, and generally slow to react to the latest demands. Sure they develop new curriculum and periodically review their standards, but software moves much faster than most other industries. On top of that, universities force you to satisfy several different general education requirements. Maybe these requirements help you become a more well-rounded human being and give you a perspective you might not otherwise achieve in your lifetime. But is it absolutely necessary to become a software engineer? No, it’s not. The more economical solution to meet the growing demand is to train people directly in the areas they need to learn to get a job. This vocational school approach is gaining more popularity as universities continue to become financially out of reach for most people.&lt;/p&gt;

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

&lt;p&gt;Bootcamps can help you transform your career in a way that hasn’t been seen before. They move fast and work along the cutting edge of the software engineering industry. Bootcamps are fueled by the rising demand for software engineers that isn’t being satiated elsewhere. While not for everyone, they can provide a more logical and economical approach to education than you might otherwise be afforded.&lt;/p&gt;




&lt;p&gt;If you’re thinking about joining a coding bootcamp and are starting to study, check out some of these &lt;a href="https://codingbootcampguides.com/tutorials/" rel="noopener noreferrer"&gt;tutorials&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://codingbootcampguides.com/10-things-i-learned-as-a-coding-bootcamp-grad/" rel="noopener noreferrer"&gt;10 Things I Learned as a Coding Bootcamp Grad&lt;/a&gt; first appeared on &lt;a href="https://codingbootcampguides.com" rel="noopener noreferrer"&gt;Coding Bootcamp Guides&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>blog</category>
      <category>career</category>
      <category>codingbootcamp</category>
      <category>hackreactor</category>
    </item>
    <item>
      <title>Understanding Imperative vs. Declarative Programming in JavaScript</title>
      <dc:creator>Michael Stromberg</dc:creator>
      <pubDate>Thu, 22 Aug 2024 04:28:33 +0000</pubDate>
      <link>https://dev.to/mjstromberg/understanding-imperative-vs-declarative-programming-in-javascript-b93</link>
      <guid>https://dev.to/mjstromberg/understanding-imperative-vs-declarative-programming-in-javascript-b93</guid>
      <description>&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%2F495cgzajm28ui0yraj78.jpeg" 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%2F495cgzajm28ui0yraj78.jpeg" alt="Lines of arbitrary, minified JavaScript code" width="800" height="522"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Photo by Markus Spiske on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the world of software engineering, understanding different programming paradigms is crucial for writing efficient and maintainable code. One of the most fundamental paradigm decisions to make is the choice between using imperative versus declarative programming. While both approaches can achieve the same outcomes, they do so in fundamentally different ways. We’ll explore the differences between these two patterns, with a focus on JavaScript, and provide examples to illustrate the pros and cons of each.&lt;/p&gt;

&lt;h2&gt;
  
  
  Imperative vs. Declarative: A Real World Example
&lt;/h2&gt;

&lt;p&gt;Understanding the benefits and drawbacks of these programming concepts is best achieved through hands-on experience. Imagine the challenges of debugging complex, imperatively written code, or the frustration of navigating over-engineered, overly abstract solutions. While these experiences can be invaluable, a real-world analogy can provide a helpful starting point for understanding the differences between imperative and declarative programming.&lt;/p&gt;

&lt;p&gt;The first analogy I heard to describe the imperative/declarative relationship was using an automobile’s air conditioner control panel, so let’s explore that in depth.&lt;/p&gt;

&lt;h3&gt;
  
  
  Imperative Design of an Automobile A/C Control Panel
&lt;/h3&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%2Fzbt01u2gxl205u5t2xmp.jpeg" 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%2Fzbt01u2gxl205u5t2xmp.jpeg" alt="A 1970 Chevrolet A/C Control Panel" width="800" height="470"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;1970 Chevrolet A/C Control Panel | Source: ChevyHardcore.com&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Description:&lt;/strong&gt; In the past, some cars’ A/C controls used imperative design, where the user set a fan level, selected a vent, and decided a heating/cooling level.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Usage:&lt;/strong&gt; Using this system isn’t too complicated, but it requires an understanding of how all three settings work and how different combinations of settings translate to getting the car to the desired temperature. Not only that, but if the weather or conditions change, the user needs to adjust the settings according. If the weather gets colder or hotter, or if the driver takes a weekend trip out of town, those settings might not be appropriate. Heating the car while on a trip to the desert or cooling the car in the cold mornings don’t make much sense.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In other words:&lt;/strong&gt; The user tells the car &lt;em&gt;how&lt;/em&gt; to cool or heat the vehicle.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Declarative Design of an Automobile A/C Control Panel
&lt;/h3&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%2F0bmj5of61igx42jkqggg.jpeg" 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%2F0bmj5of61igx42jkqggg.jpeg" alt="A Tesla Model 3 Control Panel" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A Tesla Model 3 Control Panel | Source: Motor Trend&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Description:&lt;/strong&gt; Modern cars, like the Tesla Model 3, have more declarative temperature controls. While the user may dive in and adjust the A/C settings more granularly, the main control is a just a left arrow, a right arrow, and the temperature display.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Usage:&lt;/strong&gt; By providing controls to adjust the temperature, the user gets to focus on the desired output rather than the underlying mechanics. The user sets the cabin temperature and the car’s sensors and controllers will adjust the underlying settings to maintain the desired output. The user only needs to be concerned about concepts they understand, like comfortable temperatures, and can allow the car to be concerned with vents, fans, and HVAC.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In other words:&lt;/strong&gt; The user tells the car &lt;em&gt;what&lt;/em&gt; temperature they want.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is Imperative Programming?
&lt;/h2&gt;

&lt;p&gt;As discussed above in the analogy, imperative programming is a paradigm that focuses on &lt;em&gt;how&lt;/em&gt; to achieve a particular task. It involves explicitly giving the runtime a sequence of commands or steps to follow in order to reach the desired outcome. In imperative programming, you often define the control flow and manage the state of your program as you go.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Declarative Programming?
&lt;/h2&gt;

&lt;p&gt;Declarative programming, on the other hand, focuses on &lt;em&gt;what&lt;/em&gt; you want to achieve rather than the intricate details of how to achieve it. In this paradigm, you describe the desired outcome, and the underlying system takes care of the rest. The control flow and state management — the parts of the algorithm that can be made generic and reused elsewhere—are often abstracted away from the algorithm at hand.&lt;/p&gt;

&lt;h2&gt;
  
  
  An Example of Imperative Programming in JavaScript
&lt;/h2&gt;

&lt;p&gt;Let’s look at a classic example, one that many beginning programmers learn in their early software journeys. Say we want to sum all the numbers in an array. An imperative approach in JavaScript would look like the following:&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%2Fx1ar13bg6adn03eth3gz.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%2Fx1ar13bg6adn03eth3gz.png" alt="An example of imperative code written in JavaScript" width="800" height="284"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;An example of imperative code written in JavaScript&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the example above, we explicitly define every step of the algorithm:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Initialize a &lt;code&gt;sum&lt;/code&gt; variable&lt;/li&gt;
&lt;li&gt;Loop through each number in the array&lt;/li&gt;
&lt;li&gt;Add each number to the &lt;code&gt;sum&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  An Example of Declarative Programming in JavaScript
&lt;/h3&gt;

&lt;p&gt;Let’s look at a declarative approach to achieve the same desired output. Using the same example of summing numbers in an array, a declarative approach in JavaScript might use the &lt;code&gt;reduce&lt;/code&gt; method on the array prototype:&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%2F7sevvs327g1ki4n33u0s.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%2F7sevvs327g1ki4n33u0s.png" alt="An example of declarative code written in JavaScript" width="800" height="196"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;An example of declarative code written in JavaScript&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here, instead of describing the steps to achieve the sum, we declare that we want to reduce the array to a single value by summing its elements. The reduce method abstracts away the loop and state management.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros of Imperative Programming
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Control:&lt;/strong&gt; You have precise control over the flow of your program, which can be useful in complex scenarios where you need to manage the state closely.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance:&lt;/strong&gt; Imperative code can sometimes be optimized for performance, as you can fine-tune every step of the process.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons of Imperative Programming
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Verbosity:&lt;/strong&gt; Because you must define each step, imperative code can very quickly become verbose, more difficult to read, and even more difficult to code review. These difficulties compound as complexity increases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error-Prone:&lt;/strong&gt; Managing the state manually can lead to bugs, particularly in complicated programs or when operating in lower-level programming languages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testing Difficulty:&lt;/strong&gt; Writing unit tests can sometimes become, by definition, impossible because concerns are intermixed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pros of Declarative Programming
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simplicity:&lt;/strong&gt; Declarative code is often more concise, easier to understand, and easier to read, as it abstracts away the underlying mechanics.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintainability:&lt;/strong&gt; Because you’re focusing on what you want to achieve, the code is typically easier to maintain and less prone to bugs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reviewability:&lt;/strong&gt; Declarative code can be more readable, especially for those who are familiar with the abstractions used. This can make it much easier for code reviews.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testability:&lt;/strong&gt; Writing declarative code often involves separating concerns. This allows for individual features to be isolated and tested easily.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons of Declarative Programming
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Less Control:&lt;/strong&gt; You have less control over how the task is executed, which can be a drawback if you need fine-tuned performance optimizations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Over-Abstraction:&lt;/strong&gt; The abstractions provided by declarative methods might introduce overhead or may not be suitable for all scenarios, particularly when performance is critical.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Choosing between imperative and declarative programming is not a simple choice and often involves consideration. Imperative code can give you a lot of control but often at the expense of simplicity, abstracted code that easy to read and maintain. When you need precise control or performance is an primary focus, an imperative approach might make sense. Most other times it probably makes the most sense to use a declarative approach that can lead to cleaner code. With the advent of bundlers, minification, and other optimization tools, small performance improvements become less impactful. As developers, it’s beneficial to be versatile and comfortable with both paradigms, using each where it best fits the problem at hand.&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://codingbootcampguides.com/understanding-imperative-vs-declarative-programming-in-javascript/" rel="noopener noreferrer"&gt;Understanding Imperative vs. Declarative Programming in JavaScript&lt;/a&gt; first appeared on &lt;a href="https://codingbootcampguides.com" rel="noopener noreferrer"&gt;Coding Bootcamp Guides&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>fundamentals</category>
    </item>
    <item>
      <title>How to Build a Hash Table in JavaScript</title>
      <dc:creator>Michael Stromberg</dc:creator>
      <pubDate>Fri, 02 Dec 2022 22:35:59 +0000</pubDate>
      <link>https://dev.to/mjstromberg/how-to-build-a-hash-table-in-javascript-14o2</link>
      <guid>https://dev.to/mjstromberg/how-to-build-a-hash-table-in-javascript-14o2</guid>
      <description>&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%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AzFmdm_g5T_2AvXBr" 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%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AzFmdm_g5T_2AvXBr" alt="An image of pins on a map" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Photo by Z on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Whether you’re interviewing for an entry-level software engineering position or building enterprise software at scale, data structures are going to be integral to your success. They are a fundamental pillar of programming and can sometimes be a little tricky to navigate. Data structures are like the tools in your toolbox, you need to know how each tool works in order to decide which one is appropriate for your use case.&lt;/p&gt;

&lt;p&gt;JavaScript rose to popularity by being the de facto scripting language of web browsers from very early on. As such, JavaScript was not a fully featured programming language but rather created to add a little bit of dynamic interaction to websites. Its popularity then exploded after cross-JavaScript runtime environments like &lt;a href="https://nodejs.org/en/" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; allowed developers to build native applications outside of the browser. JavaScript evolved as its use cases evolved, so as time went on, JavaScript began expanding its native data structure support.&lt;/p&gt;

&lt;p&gt;While it doesn’t have a native implementation of a pure hash table, JavaScript has a &lt;code&gt;Map&lt;/code&gt; class that has similar characteristics. However, the hash table is an incredibly important data structure in software engineering, and understanding how it works will help be essential to have a successful career in software development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hash Table
&lt;/h2&gt;

&lt;p&gt;A hash table, also known as a hash map, is a data structure that maps keys to values. They use hashing functions to do the mapping, and in some implementations, the keys can be any arbitrary type. Hash tables have many different uses, most often behind the scenes. They are sometimes used in cache implementations and as the underlying logic to build a &lt;a href="https://en.wikipedia.org/wiki/Set_%28abstract_data_type%29" rel="noopener noreferrer"&gt;set data structure&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Moving forward, we’ll examine the basic anatomy of a hash table, its efficiency, and how to implement one in JavaScript.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hashing Functions
&lt;/h3&gt;

&lt;p&gt;Hash tables are incredible data structures because not only do they have the benefit of efficient property lookup, but on average, they also have efficient insertion. The way this is accomplished is in part by using a hashing function. The hashing function coerces your key to an index in a way that is repeatable and uniformly distributable. It also reduces a key universe of arbitrary size down to an index universe of fixed size, with a negligible time penalty.&lt;/p&gt;

&lt;p&gt;Let’s explain repeatability. A repeatable hashing function is a function that produces the same output every time, given the same input. For example, a function that uses the length of a string input as the output would be considered repeatable. Conversely, a function that adds the length of the string input with the current calendar month number to calculate the output index would not be repeatable. This is because if you invoke the function in January, and then invoke it in February, the indices would be different.&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%2Ft49qk8hz185dnd1ap8dr.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%2Ft49qk8hz185dnd1ap8dr.png" alt="An illustration explaining a repeatable hashing function" width="800" height="369"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;An illustration explaining a repeatable hashing function&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As mentioned above, a hashing function’s ability to uniformly distribute its output indices is another critical role it serves. Uniform index distribution means that the output indices have roughly the same probability of landing within any part of the output range as any other. This is to avoid index collisions as much as possible because collisions are expensive to resolve. Let’s illustrate this point, further.&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%2Frlmf1hu1n2a5ixa7vfkw.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%2Frlmf1hu1n2a5ixa7vfkw.png" alt="An illustration explaining the uniform distribution of a hashing function" width="800" height="435"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;An illustration explaining the uniform distribution of a hashing function&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Collision Resolution
&lt;/h3&gt;

&lt;p&gt;Of course, at a certain point, index collisions are inevitable because you’re reducing a potentially large key universe down to a fixed size. So as your number of properties approaches your total index range, the marginal likelihood of a collision increases. Fortunately, some brilliant people have already thought about this, and there are some techniques to help resolve collisions.&lt;/p&gt;

&lt;p&gt;One common method is called “separate chaining”. Instead of inserting a value at the computed index for that key, when there is a collision, those key-value pairs are inserted into a linked list (or another data structure) located at that same index. Then when doing a look-up or insertion at that index, the linked list is linearly traversed until the key is found. If the target key is not found, then the property does not exist in the hash table.&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%2Fh6um632cnyo0s64zwggp.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%2Fh6um632cnyo0s64zwggp.png" alt="An illustration of Separate Chaining as a collision resolution method" width="764" height="457"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;An illustration of Separate Chaining as a collision resolution method&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Another popular method for collision resolution in hash tables is called “open addressing”. In this approach, all values are stored in the hash table itself instead of additional linked list data structures. When a collision occurs, an algorithm is used to probe for the next available space to insert the value. Often, this algorithm is just another pass through the hashing function, known as “double hashing,” but there are other algorithms out there as well. Double hashing has the benefit of being fairly optimized against clustering.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dynamic Resizing
&lt;/h3&gt;

&lt;p&gt;The more index collisions that your hash table needs to resolve, the more costly it becomes to operate your hash table. Thus, it becomes beneficial to resize hash tables when they reach a certain capacity, also known as the “load factor.” While resolving index collisions can be relatively computationally expensive, so is hash table resizing because it involves rehashing all or some of the existing table properties. Additionally, preemptively resizing your hash table to maintain a minimal load factor can unnecessarily consume memory. Thus, dynamic resizing can be required to make the table larger, as well as smaller.&lt;/p&gt;

&lt;p&gt;The simplest way to resize a hash table is to completely rehash all existing properties. When the desired load factor is reached, the existing properties are rehashed to a new hash table with the new, appropriate size.&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%2Fpz1rkwxc8t6d8dtp79bk.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%2Fpz1rkwxc8t6d8dtp79bk.png" alt="An illustration of complete rehashing during hash table resizing" width="800" height="434"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;An illustration of complete rehashing during hash table resizing&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Sometimes it may not be practical to do a complete rehash of all existing properties when dynamically resizing a hash table. In some real-time applications where time is critical and hash table sizes can be enormous, it can be unacceptable to rehash all properties at once. Instead, incremental rehashing can be a more practical solution. This typically involves creating a new hash table alongside the old hash table, inserting incoming properties into the new hash table, and then incrementally moving a small number of old properties to the new table on every operation. This still has the benefit of amortized efficiency, but it means that during the resizing process, each operation (i.e. insert, find, and remove) may potentially require looking up properties in both tables.&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%2Fpa9bvi9bebvyg46udo55.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%2Fpa9bvi9bebvyg46udo55.png" alt="An illustration of incremental rehashing during hash table resizing" width="800" height="372"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;An illustration of incremental rehashing during hash table resizing&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Efficiency
&lt;/h3&gt;

&lt;p&gt;When working with any data structure, the primary concern should always be efficiency. There are many different data structures and subsequent variants of those data structures, all of which could potentially be consumed in any given use case, but often times there is a particular data structure that will fit best considering your concerns.&lt;/p&gt;

&lt;p&gt;In order to understand how efficient a data structure is, you’ll need to understand the language of efficiency. &lt;a href="https://en.wikipedia.org/wiki/Big_O_notation" rel="noopener noreferrer"&gt;Big O notation&lt;/a&gt; is the standard by which efficiency is determined and it is often used to convey how a data structure will behave in different conditions. When it comes to time complexity, the worst-case and average scenarios are the primary conditions that most engineers will be interested in when deciding which data structure to use for their use case. Space complexity does come into play sometimes, but most data structures have linear space complexity (i.e. &lt;code&gt;O(n)&lt;/code&gt;) and memory usage can often easily be scaled, so this is typically overlooked.&lt;/p&gt;

&lt;p&gt;In a well-dimensioned hash table, the average time complexity for each lookup, insertion, and deletion is independent of the number of elements stored in the table. In Big O terms, this would be considered &lt;code&gt;O(1)&lt;/code&gt;, or constant time complexity. This is what makes hash tables so powerful, but the key here is the term “well-dimensioned”. It means that the hash table is sized adequately so that resizing happens rarely. When resizing does occur, it can absorb precious runtime. However, this additional cost can be thought to be amortized across all insertions and deletions and therefore be considered negligible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation in JavaScript
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Hashing Function
&lt;/h3&gt;

&lt;p&gt;First things first, we’ll need a hashing function. As I described earlier, the hashing function is the foundation of this data structure because it coerces your key to an index with effectively no time penalty. We’ll reserve a deep dive into how hashing functions work for another article. For now, take a look at the code below that converts a string to an index in JavaScript.&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%2Fioj519qgashdlry1ktc7.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%2Fioj519qgashdlry1ktc7.png" alt="An example of a hashing function to convert a string to an integer, written in JavaScript" width="800" height="328"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;An example of a hashing function to convert a string to an integer, written in JavaScript&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It’s not critical to understand how the “left shift” or “bitwise and” operators work and why they’re used here, but it is useful to know what is going on at a high level.&lt;/p&gt;

&lt;p&gt;There are two main things that I’d like you to take away from this function. First, you can see on lines &lt;code&gt;4&lt;/code&gt; and &lt;code&gt;5&lt;/code&gt; that we’re incorporating every character from the input string into our final hash index. Because every character is used in the calculation of the hash index, the likelihood of hashing collisions is reduced. Second, you’ll notice on line &lt;code&gt;10&lt;/code&gt; that we’re using the “remainder” operator on the final hash value. This ensures that the resultant hash index is always less than the &lt;code&gt;maximumInteger&lt;/code&gt; value provided to the function invocation.&lt;/p&gt;

&lt;h3&gt;
  
  
  General Structure
&lt;/h3&gt;

&lt;p&gt;We could use a &lt;code&gt;class&lt;/code&gt; type here but there is not much to be gained from doing that. Instead, we’ll use a function and add three properties to its &lt;code&gt;this&lt;/code&gt; binding. Take a look:&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%2Fyw4un3sqhcrezp10eljb.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%2Fyw4un3sqhcrezp10eljb.png" alt="The general structure of a function to construct a hash table in JavaScript" width="800" height="196"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The general structure of a function to construct a hash table in JavaScript&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We initialize a &lt;code&gt;_storage&lt;/code&gt; property as an empty array literal, and that’s where we’ll store our hash table properties. For dynamic resizing purposes, we’ll need to track the total number of properties we currently have and the size limit of our hash table. We’ll track the property count using the &lt;code&gt;_count&lt;/code&gt; property and update it each time something is added or removed from the hash table. Similarly, we’ll track the size limit with the &lt;code&gt;_limit&lt;/code&gt;property and update it every time we need to expand or reduce the hash table’s capacity.&lt;/p&gt;

&lt;p&gt;In case you were wondering, we can’t simply use the &lt;code&gt;length&lt;/code&gt; property on the &lt;code&gt;_storage&lt;/code&gt; array to gauge our property count because we’ll be inserting items at indices generated by the hashing function. These indices are unlikely to be sequential, and therefore, we’ll have gaps in the array which won’t be reflected in the &lt;code&gt;length&lt;/code&gt; property. Try it out in your browser’s console. Assign an empty array to a variable, insert a value at index 5 or any other non-zero index, and then read the &lt;code&gt;length&lt;/code&gt; property on the array. You’ll see that the length property is &lt;code&gt;6&lt;/code&gt;, even though we’ve only inserted one item.&lt;/p&gt;

&lt;h3&gt;
  
  
  Insert Method
&lt;/h3&gt;

&lt;p&gt;Next, we’ll define the insert method and we’ll attach it to the &lt;code&gt;HashTable&lt;/code&gt; prototype so we can consume it.&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%2Fm15kzubl85trowv5tir9.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%2Fm15kzubl85trowv5tir9.png" alt="A JavaScript implementation of an insert function for a hash table" width="706" height="1024"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A JavaScript implementation of an insert function for a hash table&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let’s analyze the code to better understand what’s going on. The function can be broken down into two main parts: adding the property and conditionally resizing the data structure.&lt;/p&gt;

&lt;p&gt;To add the property to our data structure, we first compute the &lt;code&gt;index&lt;/code&gt; using our hashing function described earlier. This will provide us a value between 0 and the storage limit we defined earlier, &lt;code&gt;_limit&lt;/code&gt;. From there, we check our &lt;code&gt;_storage&lt;/code&gt; array to see if something already exists at that index. If nothing exists there, we’ll create a &lt;a href="https://en.wikipedia.org/wiki/Tuple" rel="noopener noreferrer"&gt;tuple&lt;/a&gt; from our &lt;code&gt;key&lt;/code&gt; and &lt;code&gt;value&lt;/code&gt; pair and place that into an array. Otherwise, if something already exists at that index, we’ll traverse the existing array and compare keys. If that key already exists, update the value associated with that key. If not, we’ll add it to the end of the array. Finally, we’ll update that property on the &lt;code&gt;_storage&lt;/code&gt;array and increment our &lt;code&gt;_count&lt;/code&gt; value to properly track our current property count.&lt;/p&gt;

&lt;p&gt;Now that our &lt;code&gt;_count&lt;/code&gt; value is up to date, we need to check if our hash table is properly sized. Deciding when to resize your hash table depends mostly on space versus time considerations, but for the sake of demonstration, we’ve chosen to double in size when the &lt;a href="https://en.wikipedia.org/wiki/Hash_table#Load_factor" rel="noopener noreferrer"&gt;load factor&lt;/a&gt;, or the percentage of capacity currently being used, crosses above the 75% threshold. To do this we’ll reset our &lt;code&gt;_storage&lt;/code&gt; and &lt;code&gt;_count&lt;/code&gt; variables, double our &lt;code&gt;_limit&lt;/code&gt;, and most importantly, we’ll rehash our entire inventory of properties. To do the rehashing, we’ll iterate through our nested storage structure, collect all of the pairs into a flat array, and then recursively call our &lt;code&gt;insert&lt;/code&gt; method on each pairing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Retrieve Method
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;retrieve&lt;/code&gt; method is considerably simpler than our &lt;code&gt;insert&lt;/code&gt; method but just as important. To get the value associated with a particular &lt;code&gt;key&lt;/code&gt; we need to compute the &lt;code&gt;index&lt;/code&gt; using the exact same hashing function (remember, our hashing function is repeatable). We then do a lookup on our &lt;code&gt;_storage&lt;/code&gt; array at that &lt;code&gt;index&lt;/code&gt; and iterate through the resultant array there to find a matching &lt;code&gt;key&lt;/code&gt;. Take a look below to see this implemented in JavaScript.&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%2Fb7qx4x3udkecldhnrpki.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%2Fb7qx4x3udkecldhnrpki.png" alt="A JavaScript implementation of a retrieve function for a hash table" width="800" height="371"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A JavaScript implementation of a retrieve function for a hash table&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Remove Method
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;remove&lt;/code&gt; method is completely analogous to our &lt;code&gt;insert&lt;/code&gt; method described previously. We compute the &lt;code&gt;index&lt;/code&gt;, find a matching &lt;code&gt;key&lt;/code&gt; if it exists, remove that value from the nested array, and decrement our &lt;code&gt;_count&lt;/code&gt;. Then, if the result of a lower property count brings us below our lower bound load factor (in this case 25%), we reduce our storage size in half using a similar recursive algorithm from our &lt;code&gt;insert&lt;/code&gt; method. You can see a JavaScript implementation of this below.&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%2Fzi4x3v7z2xp3sr697ikm.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%2Fzi4x3v7z2xp3sr697ikm.png" alt="A JavaScript implementation of a remove function for a hash table" width="800" height="788"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A JavaScript implementation of a remove function for a hash table&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;The hash table is one of the most efficient data structures available to us as developers, and it is used as the foundation of a lot of fundamental technology we use today. Understanding how to build one yourself will give you better insight into how and when to use them in your own code.&lt;/p&gt;

&lt;p&gt;If you’re curious about how to build other fundamental data structures in JavaScript, check out this article &lt;a href="https://codingbootcampguides.com/how-to-build-a-linked-list-in-javascript/" rel="noopener noreferrer"&gt;How to Build a Linked List in JavaScript&lt;/a&gt;. Or if you’re thinking about joining a coding bootcamp, &lt;a href="https://codingbootcampguides.com/10-things-i-learned-as-a-coding-bootcamp-grad/" rel="noopener noreferrer"&gt;10 Things I Learned as a Coding Bootcamp Grad&lt;/a&gt; is a great place to learn a little bit more.&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://codingbootcampguides.com/how-to-build-a-hash-table-in-javascript/" rel="noopener noreferrer"&gt;How to Build a Hash Table in JavaScript&lt;/a&gt; first appeared on &lt;a href="https://codingbootcampguides.com" rel="noopener noreferrer"&gt;Coding Bootcamp Guides&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>datastructures</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to Build a Stack in JavaScript</title>
      <dc:creator>Michael Stromberg</dc:creator>
      <pubDate>Sun, 18 Jul 2021 23:15:53 +0000</pubDate>
      <link>https://dev.to/mjstromberg/how-to-build-a-stack-in-javascript-f9i</link>
      <guid>https://dev.to/mjstromberg/how-to-build-a-stack-in-javascript-f9i</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2Aws-t4q16G_4_cppF" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2Aws-t4q16G_4_cppF" alt="A stack of pancakes." width="800" height="1200"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Photo by Tatiana Rodriguez on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Data structures are an integral part of your life, whether you notice them or not. From waiting in line at the grocery store to something more obvious like the glossary in a textbook, they’re everywhere. However, they are especially important in software engineering and the algorithm interview questions that are asked during technical interviews.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stacks
&lt;/h3&gt;

&lt;p&gt;A stack is an important type of data structure used in engineering and computer science, and it has certain properties that make it especially useful. Stacks can be described as a Last In First Out (LIFO) data structure. This means that each time you want to remove an item, the stack will provide you with the most recently added item. Imagine you work at a restaurant in the kitchen and you need to plate an order. You have a tall stockpile of dinner plates in front of you. Now imagine you grab a plate from the plate pile. What part of the pile did you reach for? Logically you would reach for one from the top and begin arranging the meal on it. While you could have lifted half of the plates, took a plate from the middle, and set the remaining plates back on top of the pile, this would have been a lot more work.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AAwitrdFFJ4gKVM6f" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AAwitrdFFJ4gKVM6f" alt="A stack of dishes." width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Photo by Mick Haupt on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Other good examples of stacks in real life are browser histories, clothing (it would be rather difficult to remove your shirt before you take off your jacket), or anything that is stored vertically like maybe some dining chairs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Efficiency
&lt;/h3&gt;

&lt;p&gt;Now that we generally understand how stacks work and where they’re used in real life, let’s talk about their efficiency. Data structure efficiency is often measured using &lt;a href="https://en.wikipedia.org/wiki/Big_O_notation" rel="noopener noreferrer"&gt;Big O notation&lt;/a&gt; for both time complexity and space complexity, but we’re generally only concerned with time complexity when simply evaluating data structures. We’re also often only interested in the worst-case scenarios (i.e. when there is a lot of data) because differences in time complexity efficiency for small amounts of data are often trivial or unreliable.&lt;/p&gt;

&lt;p&gt;Stacks are well-suited for insertion and deletion because they keep an active reference pointing at the most recent item added. Because of this, their time complexity for insertion and deletion are considered constant time (i.e. &lt;code&gt;O(1)&lt;/code&gt;). However, if you need to be able to look up any other item other than the latest item added to the stack, you may want to use a different data structure that is better optimized for that scenario. While you might consider stacks to have linear lookup time complexity (i.e. &lt;code&gt;O(n)&lt;/code&gt;), you would need to remove all of the items that were added after your target item in order to read it.&lt;/p&gt;

&lt;p&gt;With all of that said, stacks are very efficient when used properly. If you want to see a comparison of common data structures and their efficiencies, you can take a look at this popular &lt;a href="https://www.bigocheatsheet.com/" rel="noopener noreferrer"&gt;cheatsheet&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementation in JavaScript
&lt;/h3&gt;

&lt;p&gt;Generally speaking, a stack needs to be able to push and pop the latest item, as well as allow users to read its length. Below is a &lt;code&gt;class&lt;/code&gt; implementation of a basic stack in JavaScript.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F81o2mrlsvy29g3jaz71m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F81o2mrlsvy29g3jaz71m.png" alt="A class implementation of a stack data structure in JavaScript" width="800" height="525"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A class implementation of a stack data structure in JavaScript.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let’s talk about how this works. Here on lines 2 through 5, we initialize our stack &lt;code&gt;class&lt;/code&gt; with &lt;code&gt;data&lt;/code&gt; and &lt;code&gt;size&lt;/code&gt; properties attached to the instance. If the stack is instantiated without any initial data, the &lt;code&gt;data&lt;/code&gt; property will be assigned an empty array and the &lt;code&gt;size&lt;/code&gt; property will be 0.&lt;/p&gt;

&lt;p&gt;You may have noticed that I used &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions" rel="noopener noreferrer"&gt;arrow function expressions&lt;/a&gt; for the instance methods defined on lines 7 and 12. Because arrow function expressions don’t have their own &lt;code&gt;this&lt;/code&gt; bindings, the references to &lt;code&gt;this&lt;/code&gt; in the function definitions will evaluate to the &lt;code&gt;this&lt;/code&gt; found in the scope where the functions were defined. This is a minor convenience here, but I thought it would be worth explaining.&lt;/p&gt;

&lt;p&gt;I also want to draw your attention statement on line 15. This shortens the length of the &lt;code&gt;data&lt;/code&gt; array and effectively deletes any items that reside at indices beyond that length. Theoretically, this implementation can vary depending on the JavaScript engine being used, and for the sake of this post, I’ve assumed this is a constant time operation. However, since we’re tracking our own &lt;code&gt;size&lt;/code&gt; property, we don’t even need to shrink the array when we &lt;code&gt;pop&lt;/code&gt; an item off. We could just delete the item in the array and decrement our &lt;code&gt;size&lt;/code&gt; variable.&lt;/p&gt;

&lt;p&gt;One thing you might also have noticed is that our &lt;code&gt;data&lt;/code&gt; and &lt;code&gt;size&lt;/code&gt; properties are assigned onto the instance, and this could be considered “leaky.” Some developer could directly mutate the &lt;code&gt;data&lt;/code&gt; or &lt;code&gt;size&lt;/code&gt; properties and potentially break the stack functionality. Let’s see how we might get around this with a functional implementation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F7fz1ijfgl84atvdgchmy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F7fz1ijfgl84atvdgchmy.png" alt="A function implementation of a stack data structure in JavaScript" width="800" height="569"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A function implementation of a stack data structure in JavaScript.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In this implementation, I make use of a JavaScript closure to encapsulate our &lt;code&gt;data&lt;/code&gt; and &lt;code&gt;size&lt;/code&gt; values. In JavaScript, when a function is declared, it is given access to the lexical environment in which it was created. So by creating local variables within our &lt;code&gt;Stack&lt;/code&gt; function and returning an object with methods that reference those variables, we’re in full control of how we allow access and manipulation of those variables. This will help reduce bugs associated with leaky variables, and it’s just as readable and scannable as our class-based solution.&lt;/p&gt;

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

&lt;p&gt;Stacks are very useful data structures in software engineering and in the everyday world. They are particularly efficient for data insertion and deletion when used correctly. Hopefully, you’ve learned a thing or two about how to implement them in JavaScript, but let me know in the comments if you have any questions!&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://codingbootcampguides.com/how-to-build-a-stack-in-javascript/" rel="noopener noreferrer"&gt;How to Build a Stack in JavaScript&lt;/a&gt; first appeared on &lt;a href="https://codingbootcampguides.com" rel="noopener noreferrer"&gt;Coding Bootcamp Guides&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>datastructures</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Solving the “Merge Sorted Arrays in Place” Problem in JavaScript</title>
      <dc:creator>Michael Stromberg</dc:creator>
      <pubDate>Thu, 08 Jul 2021 22:50:12 +0000</pubDate>
      <link>https://dev.to/mjstromberg/solving-the-merge-sorted-arrays-in-place-problem-in-javascript-38mn</link>
      <guid>https://dev.to/mjstromberg/solving-the-merge-sorted-arrays-in-place-problem-in-javascript-38mn</guid>
      <description>&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%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AzHX2zFjz7PQNb2Zi" 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%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AzHX2zFjz7PQNb2Zi" alt="An image of railroad tracks crossing" width="800" height="629"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Photo by Lance Grandahl on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  A General Note about Coding Interviews
&lt;/h3&gt;

&lt;p&gt;As usual, I’d like to talk about the nature of coding interviews. They are very analogous to taking the SAT or GRE; sometimes they aren’t necessarily the best reflection of how you’ll perform at your job or in college, but more of a reflection of your preparation and resources.&lt;/p&gt;

&lt;p&gt;As long as companies still use these types of problems, you’ll need to prepare for them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem Source / Inspiration
&lt;/h3&gt;

&lt;p&gt;This is a common interview problem.&lt;br&gt;&lt;br&gt;
&lt;em&gt;Asked by: Amazon, Google, Apple, Facebook, Netflix, Microsoft, and many more.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem Description
&lt;/h3&gt;

&lt;p&gt;Given two sorted integer arrays A and B, merge B into A as one sorted array. Note, you may assume that A has enough space to hold additional elements from B, and the number of elements initialized in A and B are m and n, respectively.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem Solution
&lt;/h3&gt;

&lt;p&gt;Let’s visualize our algorithm, below. By first moving items to the end of the first array, we can minimize the number of cells we need to move (i.e. time complexity) because the extra space is located at the end of the array. If we had started by moving items at the beginning of the first array, we would potentially have to move all of the items in the first array that came after that cell over by one.&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%2Fk3yauowjldqcft9s1g8h.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%2Fk3yauowjldqcft9s1g8h.png" alt="A visual representation of merging to sorted arrays in place" width="800" height="378"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A visual representation of merging to sorted arrays in place&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now let’s take a look at the solution to the problem and break down the key aspects.&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%2Fecqvsy27eewvu6iav0w3.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%2Fecqvsy27eewvu6iav0w3.png" alt="An implementation of a function to merge sorted arrays in place, in JavaScript." width="800" height="503"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;An implementation of a function to merge sorted arrays in place, in JavaScript.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I chose to create three index variables &lt;code&gt;i&lt;/code&gt;, &lt;code&gt;j&lt;/code&gt;, and &lt;code&gt;k&lt;/code&gt; to point to specific indices of interest. &lt;code&gt;i&lt;/code&gt; corresponds to the current item index of the first array, starting with the last item. &lt;code&gt;j&lt;/code&gt; corresponds to the current item index of the second array, also starting with the last item. Finally, &lt;code&gt;k&lt;/code&gt; corresponds to the index of the cell that needs to be filled, starting with the last index of the first array.&lt;/p&gt;

&lt;p&gt;After identifying our pointers, we can begin to iterate. We begin by traversing backwards through the first array. For each iteration, we compare the values at &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;j&lt;/code&gt; from their respective arrays, and the larger item gets assigned to the cell at &lt;code&gt;k&lt;/code&gt;. Each iteration we need to update the appropriate pointers. We decrement &lt;code&gt;k&lt;/code&gt; on each loop and also decrement either &lt;code&gt;i&lt;/code&gt; or &lt;code&gt;j&lt;/code&gt;, depending on which array we took an item from. We also handle edge cases on line 7. If &lt;code&gt;j&lt;/code&gt; is less than 0, that means the second array is empty and we only need to draw from the first array. Similarly, if &lt;code&gt;i&lt;/code&gt; is less than 0, we only need to draw from the second array.&lt;/p&gt;

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

&lt;p&gt;The main challenge of this problem is to identify the usefulness of moving items to the back of the array where the available space is. You can do it starting from the front, but it makes the logic and code much more complicated. Spending some time to think about time complexity implications like this will save you even more time when it comes to coding it out.&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://codingbootcampguides.com/solving-the-merge-sorted-arrays-in-place-problem-in-javascript/" rel="noopener noreferrer"&gt;Solving the “Merge Sorted Arrays in Place” Problem in JavaScript&lt;/a&gt; first appeared on &lt;a href="https://codingbootcampguides.com" rel="noopener noreferrer"&gt;Coding Bootcamp Guides&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>algorithmdesignbreak</category>
      <category>algorithmdesign</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Solving the “Staircase with N Steps” Problem in JavaScript</title>
      <dc:creator>Michael Stromberg</dc:creator>
      <pubDate>Sun, 13 Oct 2019 18:06:50 +0000</pubDate>
      <link>https://dev.to/mjstromberg/solving-the-staircase-with-n-steps-problem-in-javascript-2mbj</link>
      <guid>https://dev.to/mjstromberg/solving-the-staircase-with-n-steps-problem-in-javascript-2mbj</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AGdq6e87ek44YXRqg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AGdq6e87ek44YXRqg" alt="A person walking up stairs" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Photo by Jake Hills on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;A General Note about Coding Interviews&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Coding interviews are very analogous to taking the SAT or GRE; sometimes they aren’t necessarily the best reflection of how you’ll perform at your job or in college, but more of a reflection of your preparation and resources.&lt;/p&gt;

&lt;p&gt;As long as companies still use these types of problems, you’ll need to prepare for them.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Problem Source / Inspiration&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.dailycodingproblem.com/levels" rel="noopener noreferrer"&gt;https://www.dailycodingproblem.com&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Asked by: Amazon&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Problem Description&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;There’s a staircase with N steps, and you can climb 1 or 2 steps at a time. Given N, write a function that returns the number of unique ways you can climb the staircase. The order of the steps matters.&lt;/p&gt;

&lt;p&gt;For example, if N is 4, then there are 5 unique ways:&lt;br&gt;
  &lt;/p&gt;
&lt;ul&gt;

    &lt;li&gt;1, 1, 1, 1&lt;/li&gt;

    &lt;li&gt;2, 1, 1&lt;/li&gt;

    &lt;li&gt;1, 2, 1&lt;/li&gt;

    &lt;li&gt;1, 1, 2&lt;/li&gt;

    &lt;li&gt;2, 2&lt;/li&gt;

  &lt;/ul&gt;

&lt;p&gt;What if, instead of being able to climb 1 or 2 steps at a time, you could climb any number from a set of positive integers X? For example, if X = {1, 3, 5}, you could climb 1, 3, or 5 steps at a time. Generalize your function to take in X.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Problem Solution&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;These problems can sometimes be hard to conceptualize, especially when using &lt;a href="https://codingbootcampguides.com/recursion-explained-in-javascript/" rel="noopener noreferrer"&gt;recursion&lt;/a&gt;. So with that in mind, I decided to illustrate the initial part of the problem below for &lt;code&gt;n = 4&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fhxphnd1dnjhp4pwc6q94.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fhxphnd1dnjhp4pwc6q94.png" alt="A tree diagram of all possible step permutations for 4 total steps and a maximum step size of 2" width="800" height="500"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A tree diagram of all possible step permutations for 4 total steps and a maximum step size of 2&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As you can see from above, in order to solve this problem (without being a mathematician) we can visualize it as a tree-like structure and traverse it to find the branches that satisfy our criteria. I didn’t show all of the failed branches, but you could imagine a branch like 1–2–2 that would fail our criteria of taking exactly 4 steps.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Solution Part #1&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Let’s break down the solution to the first part of the problem.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F4cpjj7f5zvqktj9brcrr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F4cpjj7f5zvqktj9brcrr.png" alt="An implementation of a function to count the unique steps by one or two in JavaScript" width="800" height="350"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;An implementation of a function to count the unique steps by one or two in JavaScript.&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When we recurse, we are homing in on a criteria with each successive call of our function. In our problem, we are decrementing the number of total steps left by the step size that we took until there are no steps left.&lt;/li&gt;
&lt;li&gt;Our recursive case can be seen on line 7. Here we’re invoking our function with &lt;code&gt;n — 1&lt;/code&gt; and &lt;code&gt;n — 2&lt;/code&gt;, respectively. Then we sum the returned values of those subsequent calls.&lt;/li&gt;
&lt;li&gt;We still have to handle the cases where we take too many steps. We handle this on lines 2 and 3 by returning 0 if &lt;code&gt;n&lt;/code&gt; is negative (i.e. if we’ve taken too many steps).&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Solution Part #2&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Now let’s take a look at the more complicated scenario.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fig9muhd58frimanu8cz4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fig9muhd58frimanu8cz4.png" alt="An implementation of a function to count unique steps by a given step size in JavaScript." width="800" height="328"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;An implementation of a function to count unique steps by a given step size in JavaScript.&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In this case, we’re now expecting an array of valid step sizes. Since, we don’t know the step sizes ahead of time, we can’t hardcode our step size reduction like before.&lt;/li&gt;
&lt;li&gt;Instead, we’ll iterate through the &lt;code&gt;stepSizes&lt;/code&gt; array, apply our recursion criteria, and then return the sum of the values we produce. To do this, we’ll use &lt;code&gt;Array.prototype.reduce&lt;/code&gt; because it allows us to declaratively iterate over an array and accumulate a value.&lt;/li&gt;
&lt;li&gt;Our cases are similar to that in Part #1. We handle the cases where we take too many steps on lines 3 and 4, we have our base case on lines 5 and 6, and we handle our recursive case on lines 7 and 8.&lt;/li&gt;
&lt;li&gt;In the recursive case, we invoke our function again with a remaining number of steps equal to &lt;code&gt;n — stepSize&lt;/code&gt;. We then add the returned value of the function call to our &lt;code&gt;sum&lt;/code&gt; variable.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;These problem solutions aren’t very verbose; we were able to solve the more complicated part of this problem in 11 easy-to-read lines. The main challenge is to identify the problem as one where you could traverse all possible paths and determine whether each one satisfies the criteria.&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://codingbootcampguides.com/solving-the-staircase-with-n-steps-problem-in-javascript/" rel="noopener noreferrer"&gt;Solving the “Staircase with N Steps” Problem in JavaScript&lt;/a&gt; first appeared on &lt;a href="https://codingbootcampguides.com" rel="noopener noreferrer"&gt;Coding Bootcamp Guides&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>algorithmdesignbreak</category>
      <category>algorithmdesign</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
