avatarJoan Indiana Lyness

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

4390

Abstract

for example, and our loop continues until we start our slice at the last element, we are not going to get 5 integers; we’re going to get just the last element.</p><p id="a087">We can account for this by setting the maximum value for i at: <code>i < s.length — 1 — m.</code> BUT for reasons this Noob can’t figure out, doing that makes the algorithm fails some of HackerRank’s tests. <i>Please comment if you know why!!</i></p><p id="d6a2">As a workaround, I added an extra if statement to check that my subArray’s length is in fact equal to m.</p><div id="6902"><pre><span class="hljs-variable">function</span> <span class="hljs-title function_">birthday</span>(<span class="hljs-params">s</span>, <span class="hljs-params">d</span>, <span class="hljs-params">m</span>) {</pre></div><div id="63fc"><pre> <span class="hljs-keyword">for</span>(let i = <span class="hljs-number">0</span>; i < s.<span class="hljs-built_in">length</span> - <span class="hljs-number">1</span>; i++){ let subArray = s.<span class="hljs-built_in">slice</span>(i, i+m) <span class="hljs-keyword">if</span> subArray.<span class="hljs-built_in">length</span> === m { <span class="hljs-comment">// more code here</span></pre></div><div id="fbdf"><pre> }</pre></div><div id="2c5f"><pre> }</pre></div><div id="bbe8"><pre>}</pre></div><h1 id="e952">Step 2. Get the sum of the slice</h1><p id="fb4b">This is a perfect place to use <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce">JavaScript’s reduce() method.</a></p><p id="562d"><code>let sum = subArray.reduce((a,b) => a + b, 0)</code></p><h1 id="1c7a">Step 3. if the sum equals date, increment a counter</h1><p id="0c7c">To increment a counter, we have to set one up. We’ll set ours up before the loop, operate on the counter during the loop, and then return the counter after the loop.</p><p id="326d">Inside the loop, we’ll increment like so:</p><div id="3574"><pre><span class="hljs-function"><span class="hljs-title">if</span><span class="hljs-params">(sum === d)</span></span>{ counter += <span class="hljs-number">1</span> }</pre></div><p id="c995">So far, our code looks like this:</p><div id="b40f"><pre><span class="hljs-keyword">function</span> <span class="hljs-title function_">birthday</span>(<span class="hljs-params">s, d, m</span>) { <span class="hljs-keyword">let</span> counter = <span class="hljs-number">0</span></pre></div><div id="c8db"><pre> <span class="hljs-keyword">for</span>(let i = <span class="hljs-number">0</span>; i < s.<span class="hljs-built_in">length</span> - <span class="hljs-number">1</span>; i++){ let subArray = s.<span class="hljs-built_in">slice</span>(i, i+m) <span class="hljs-keyword">if</span> subArray.<span class="hljs-built_in">length</span> === m { let <span class="hljs-built_in">sum</span> = subArray.<span class="hljs-built_in">reduce</span>(<span class="hljs-function">(<span class="hljs-params">a,b</span>) =></span> a + b, <span class="hljs-number">0</span>) <span class="hljs-keyword">if</span>(<span class="hljs-built_in">sum</span> === d){ counter += <span class="hljs-number">1</span>
} } }</pre></div><div id="c974"><pre> <span class="hljs-keyword">return</span> counter }</pre></div><h1 id="4c23">and now, for the edge cases ….</h1><p id="a134">Edge cases are the odd ones — for instance, what if your array, <i>s</i>, included some letters, not just digits? or what if <i>s</i> weren’t always an array etc? It’s easy to go overboard imagining what could possibly be wrong with the inputs.</p><p id="81f6">After a few weeks of solving algorithms for several hours a day, 5 days a week, I began to notice that you can save a lot of time by reading directions carefully. The directions often rule out possible edge cases.</p><p id="673b">For this problem, here are HackerRank’s notes about the inputs and their constraints:</p><figure id="09fa"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*fz--hvsnwVYIa_5o5rPHLQ.png"><figcaption></figcaption></figure><p id="0e9a">In other words, we can always expect integers, in certain ranges.</p><p id="5ea2">Within these parameters, however, there are still special cases. What if the birth month is Novembe

Options

r? In that case, <i>m</i> equals 11, and we are looking for 11 contiguous squares of chocolate whose integers add up to <i>d</i>. But if we have fewer than 11 squares of chocolate, no matter what the integers are, we won’t succeed.</p><p id="92f2">We can deal with that edge case like so:</p><div id="707e"><pre>//edge <span class="hljs-keyword">case</span>, month greater than <span class="hljs-comment"># of squares in bar</span></pre></div><div id="e6e4"><pre>let counter <span class="hljs-operator">=</span> <span class="hljs-number">0</span><span class="hljs-comment">;</span></pre></div><div id="87c9"><pre><span class="hljs-function"><span class="hljs-title">if</span><span class="hljs-params">(m > s.length )</span></span>{ return counter }</pre></div><p id="ec7e">Another edge case:</p><p id="941b">What if the birth month is January, <i>and </i>there’s only one square of chocolate? Then the integer on that square must equal that date. We can handle this edge case like so:</p><div id="bb19"><pre><span class="hljs-operator">/</span><span class="hljs-operator">/</span>edge <span class="hljs-keyword">case</span> <span class="hljs-keyword">month</span> <span class="hljs-keyword">is</span> <span class="hljs-keyword">one</span>, <span class="hljs-keyword">only</span> <span class="hljs-keyword">one</span> square <span class="hljs-keyword">of</span> chocolate.</pre></div><div id="c81c"><pre><span class="hljs-function"><span class="hljs-title">if</span><span class="hljs-params">(s.length === <span class="hljs-number">1</span> && m === <span class="hljs-number">1</span>)</span></span>{</pre></div><div id="aa3c"><pre> if (s[<span class="hljs-number">0</span>] <span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span> d) {</pre></div><div id="0c36"><pre> <span class="hljs-keyword">return</span> <span class="hljs-number">1</span> } }</pre></div><p id="a0ad">All together now:</p><div id="b57a"><pre><span class="hljs-variable">function</span> <span class="hljs-title function_">birthday</span>(<span class="hljs-params">s</span>, <span class="hljs-params">d</span>, <span class="hljs-params">m</span>) {</pre></div><div id="7144"><pre> //edge <span class="hljs-keyword">case</span> <span class="hljs-comment">#1, m > squares of chocolate</span> <span class="hljs-built_in">let</span> counter = 0; <span class="hljs-keyword">if</span>(m > s.length ){ <span class="hljs-built_in">return</span> counter }</pre></div><div id="59ce"><pre> //edge <span class="hljs-keyword">case</span> <span class="hljs-comment">#2, month is jan, only one square of choc.</span> <span class="hljs-keyword">if</span>(s.length === 1 && m === 1){ <span class="hljs-keyword">if</span> (s[0] === d) { <span class="hljs-built_in">return</span> 1 } }</pre></div><div id="04f3"><pre> <span class="hljs-keyword">for</span>(let i = <span class="hljs-number">0</span>; i < s.<span class="hljs-built_in">length</span> - <span class="hljs-number">1</span>; i++){ let subArray = s.<span class="hljs-built_in">slice</span>(i, i+m) <span class="hljs-keyword">if</span> subArray.<span class="hljs-built_in">length</span> === m { let <span class="hljs-built_in">sum</span> = subArray.<span class="hljs-built_in">reduce</span>(<span class="hljs-function">(<span class="hljs-params">a,b</span>) =></span> a + b, <span class="hljs-number">0</span>) <span class="hljs-keyword">if</span>(<span class="hljs-built_in">sum</span> === d){ counter += <span class="hljs-number">1</span>
} } }</pre></div><div id="3a45"><pre> <span class="hljs-keyword">return</span> counter }</pre></div><p id="f8a9">It works! And now I’m thinking about chocolate ….</p><p id="348b">Copyright © Joan Indiana Lyness 2019</p><p id="dc96">Next: <a href="https://readmedium.com/algorithms-101-princesses-peas-and-recursion-in-ruby-dffb44799d6e"><i>Algorithms 101, #11, Princesses, Peas & Recursion in Ruby</i></a></p><p id="48f0"><i>in case you missed it: <a href="https://readmedium.com/algorithms-101-jewels-and-stones-in-ruby-and-javascript-c22fce37ad2b">Algorithms 101, #9, Jewels and Stones in Ruby and JavaScript</a></i></p></article></body>

Algorithms 101: Birthday Chocolate in JavaScript

Noob v. Algorithms #10, array manipulation

yes, i am more attracted to algorithms when they mention chocolate …

So there’s this girl, Lily. She wants to give her pal chocolate for her birthday, but there are conditions!

Here’s the problem in HackerRank:

For those of you who learn better with pictures, read on. In the sample input below, 5 is the number of squares in the chocolate bar; the second line is the integers in those squares; the third line is his birth date(3) followed by his birth month(2).

who knew gifting chocolate could be so complicated?

Here’s how we start:

function birthday(s, d, m) {
     // s = array of integers 
     // d = date  
     // m = month
}

Observations/ Choose your weapons …

Things to notice:

  1. The integers have to be contiguous — which means we need to preserve the order of the array. So we probably won’t be using .sort(); but we will be using a loop.
  2. We need m integers in a row to add up exactly to d, so as we loop, we are going to want to look at the sum of m contiguous integers at a time. If you want to look at just part of an array, in order, slice() is your tool!

Break the problem up into smaller problems

We will only give away chocolate if we have m contiguous squares adding up to d. Assuming we have at least m squares (that’s an edge case we can check for later), here’s what we have to do:

  1. loop through one slice of the array at a time; slice has a length of m
  2. get the sum of that slice
  3. if the sum equals date, increment a counter
  4. return the counter
loop!

Step 1. Let’s Loop and slice() …

Slice is slightly tricky! It takes two arguments, a starting index and an ending index. Your slice will end just before the ending index. Documentation here.

So array.slice(0,2) gives you a ‘slice’ of the array from the 0th index up to but not including index 2:

let array = [apple, bobcat, couch]
let slice = array.slice(0,2)
// slice = [apple, bobcat] 

In our code, we want to examine the sum of the current index plus the next two indexes, so our slice will look like this:

function birthday(s, d, m) {
     for(let i = 0; i < s.length - 1; i++){
          let subArray = s.slice(i, i+m)
          if subArray.length === m {
             // more code here
          }
     }
}

Note: if you are looping over an array one item at a time, starting at the first index (i = 0) and you stop at the end, where the index is array.length — 1.

In our case, we want to make sure we are always looking at m number of squares at a time. If m is 5, for example, and our loop continues until we start our slice at the last element, we are not going to get 5 integers; we’re going to get just the last element.

We can account for this by setting the maximum value for i at: i < s.length — 1 — m. BUT for reasons this Noob can’t figure out, doing that makes the algorithm fails some of HackerRank’s tests. Please comment if you know why!!

As a workaround, I added an extra if statement to check that my subArray’s length is in fact equal to m.

function birthday(s, d, m) {
     for(let i = 0; i < s.length - 1; i++){
          let subArray = s.slice(i, i+m)
          if subArray.length === m {
             // more code here
           }
     }
}

Step 2. Get the sum of the slice

This is a perfect place to use JavaScript’s reduce() method.

let sum = subArray.reduce((a,b) => a + b, 0)

Step 3. if the sum equals date, increment a counter

To increment a counter, we have to set one up. We’ll set ours up before the loop, operate on the counter during the loop, and then return the counter after the loop.

Inside the loop, we’ll increment like so:

if(sum === d){
     counter += 1
}

So far, our code looks like this:

function birthday(s, d, m) {
    let counter = 0
    for(let i = 0; i < s.length - 1; i++){
          let subArray = s.slice(i, i+m)
          if subArray.length === m {
             let sum = subArray.reduce((a,b) => a + b, 0)
             if(sum === d){
                  counter += 1          
              }
           }
     }
     return counter
}

and now, for the edge cases ….

Edge cases are the odd ones — for instance, what if your array, s, included some letters, not just digits? or what if s weren’t always an array etc? It’s easy to go overboard imagining what could possibly be wrong with the inputs.

After a few weeks of solving algorithms for several hours a day, 5 days a week, I began to notice that you can save a lot of time by reading directions carefully. The directions often rule out possible edge cases.

For this problem, here are HackerRank’s notes about the inputs and their constraints:

In other words, we can always expect integers, in certain ranges.

Within these parameters, however, there are still special cases. What if the birth month is November? In that case, m equals 11, and we are looking for 11 contiguous squares of chocolate whose integers add up to d. But if we have fewer than 11 squares of chocolate, no matter what the integers are, we won’t succeed.

We can deal with that edge case like so:

//edge case, month greater than # of squares in bar
let counter = 0;
if(m > s.length ){
     return counter
}

Another edge case:

What if the birth month is January, and there’s only one square of chocolate? Then the integer on that square must equal that date. We can handle this edge case like so:

//edge case month is one, only one square of chocolate.
if(s.length === 1 && m === 1){
     if (s[0] === d) {
          return 1
     }
}

All together now:

function birthday(s, d, m) {
     //edge case #1, m > squares of chocolate
     let counter = 0;
     if(m > s.length ){
           return counter
     }
     //edge case #2, month is jan, only one square of choc.
     if(s.length === 1 && m === 1){
          if (s[0] === d) {
               return 1
          }
      }
     for(let i = 0; i < s.length - 1; i++){
          let subArray = s.slice(i, i+m)
          if subArray.length === m {
             let sum = subArray.reduce((a,b) => a + b, 0)
             if(sum === d){
                  counter += 1          
              }
           }
     }
     return counter
}

It works! And now I’m thinking about chocolate ….

Copyright © Joan Indiana Lyness 2019

Next: Algorithms 101, #11, Princesses, Peas & Recursion in Ruby

in case you missed it: Algorithms 101, #9, Jewels and Stones in Ruby and JavaScript

JavaScript
Algorithms
Hackerrank
Programming
Web Development
Recommended from ReadMedium