avatarJoan Indiana Lyness

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

4138

Abstract

prices.<span class="hljs-title function_">forEach</span>(<span class="hljs-keyword">function</span>(<span class="hljs-params">buy, index</span>) { <span class="hljs-keyword">let</span> rest = prices.<span class="hljs-title function_">slice</span>(index + <span class="hljs-number">1</span>)
<span class="hljs-keyword">if</span> (rest){ <span class="hljs-keyword">let</span> sell = <span class="hljs-title class_">Math</span>.<span class="hljs-title function_">max</span>(...rest)
sell > buy ? profit = sell - buy : <span class="hljs-literal">null</span> profit > maxProfit ? maxProfit = profit : <span class="hljs-literal">null</span>
}
})
<span class="hljs-keyword">return</span> maxProfit
};</pre></div><p id="3468">It works! BUT how does it perform?</p> <figure id="1877"> <div> <div> <img class="ratio" src="http://placehold.it/16x9"> <iframe class="" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fgiphy.com%2Fembed%2F3NtY188QaxDdC%2Ftwitter%2Fiframe&amp;display_name=Giphy&amp;url=https%3A%2F%2Fgiphy.com%2Fgifs%2F3NtY188QaxDdC&amp;image=https%3A%2F%2Fmedia.giphy.com%2Fmedia%2F3NtY188QaxDdC%2Fgiphy.gif&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=giphy" allowfullscreen="" frameborder="0" height="435" width="435"> </div> </div> </figure></iframe></div></div></figure><p id="6e3f">We are in the bottom 5 percent!</p><figure id="4ca1"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*JL6dS7brRs0JAw6IFoU4hw.png"><figcaption></figcaption></figure><p id="3f0b">Why? Because we have nested loops — an if loop inside a for loop, not to mention two ternary operations for each nested loop.</p><h1 id="893a">We need a different approach!</h1><p id="6216">Our first approach was to break our array into two arrays, nesting one inside the other. This time, let’s iterate only once. We’ll still set an initial value for maxProfit. We’ll also set an initial value for <i>min </i>(minimum value, ie lowest price).</p><div id="a258"><pre>var maxProfit <span class="hljs-operator">=</span> function(prices) { let maxProfit <span class="hljs-operator">=</span> <span class="hljs-number">0</span><span class="hljs-comment">;</span> let min <span class="hljs-operator">=</span> prices[<span class="hljs-number">0</span>]<span class="hljs-comment">;</span> for(let i <span class="hljs-operator">=</span> <span class="hljs-number">1</span><span class="hljs-comment">; i < prices.length; i++) {</span> // more code here } }</pre></div><p id="08e7">As we iterate we’ll compare our most recent value for <i>min</i> with the next element, and set the lesser of those two values as the new value for <i>min</i>. We’re using javaScript’s <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/min">Math.min()</a>.</p><div id="742c"><pre><span class="hljs-keyword">const</span> prices = [<span class="hljs-number">7</span>,<span class="hljs-number">1</span>,<span class="hljs-number">5</span>,<span class="hljs-number">3</span>,<span class="hljs-number">6</span>,<span class="hljs-number">4</span>] <span class="hljs-built_in">min</span> = Math.<span class="hljs-built_in">min</span>(prices[i], <span class="hljs-built_in">min</span>); //i = <span class="hljs-number">1</span>, <span class="hljs-built_in">min</span> = Math.<span class="hljs-built_in">min</span>(<span class="hljs-number">1</span>,<span class="hljs-number">7</span>) => <span class="hljs-number">1</span></pre></div><h1 id="5c70">Tracking Profits</h1><p id="a5a0">In the same loop, we also update maximum profit, which we define as either the previous value for <i>maxProfit</i>, or the current price minus <i>min</i>.</p><div id="5ee4"><pre><span class="hljs-keyword">max</span>Profit = Math.<span class="hljs-keyword">max</span>(<span class="hljs-keyword">max</span>Profit, prices[i] - <span class="hljs-keyword">min</span>);</pre></div><p id="57c2">Here’

Options

s a look at how those values update after each loop:</p><div id="4fff"><pre>const prices = <span class="hljs-string">[7,1,5,3,6,4]</span></pre></div><div id="edc1"><pre><span class="hljs-function"><span class="hljs-title">for</span><span class="hljs-params">(let i = <span class="hljs-number">1</span>; i < prices.length; i++)</span></span> {</pre></div><div id="0bc8"><pre> min = <span class="hljs-built_in">Math</span>.min(prices[i], min); <span class="hljs-regexp">//i = 1, lowestPrice = Math.min(1,7) => 1 //i</span> = <span class="hljs-number">2</span>, lowestPrice = <span class="hljs-built_in">Math</span>.min(<span class="hljs-number">5</span>,<span class="hljs-number">1</span>) => <span class="hljs-number">1</span> //i = <span class="hljs-number">3</span>, lowestPrice = <span class="hljs-built_in">Math</span>.min(<span class="hljs-number">3</span>,<span class="hljs-number">1</span>) => <span class="hljs-number">1</span> //i = <span class="hljs-number">4</span>, lowestPrice = <span class="hljs-built_in">Math</span>.min(<span class="hljs-number">6</span>,<span class="hljs-number">1</span>) => <span class="hljs-number">1</span> //i = <span class="hljs-number">5</span>, lowestPrice = <span class="hljs-built_in">Math</span>.min(<span class="hljs-number">4</span>,<span class="hljs-number">1</span>) => <span class="hljs-number">1</span></pre></div><div id="b175"><pre> maxProfit = <span class="hljs-built_in">Math</span>.max(maxProfit, prices[i] - min); <span class="hljs-regexp">//i = 1, Math.max(0, 1 - 1) => 0 //i</span> = <span class="hljs-number">2</span>, <span class="hljs-built_in">Math</span>.max(<span class="hljs-number">0</span>, <span class="hljs-number">5</span> - <span class="hljs-number">1</span>) => <span class="hljs-number">4</span> //i = <span class="hljs-number">3</span>, <span class="hljs-built_in">Math</span>.max(<span class="hljs-number">4</span>, <span class="hljs-number">3</span> - <span class="hljs-number">1</span>) => <span class="hljs-number">4</span> //i = <span class="hljs-number">4</span>, <span class="hljs-built_in">Math</span>.max(<span class="hljs-number">4</span>, <span class="hljs-number">6</span> - <span class="hljs-number">1</span>) => <span class="hljs-number">5</span> //i = <span class="hljs-number">5</span>, <span class="hljs-built_in">Math</span>.max(<span class="hljs-number">5</span>, <span class="hljs-number">4</span> - <span class="hljs-number">1</span>) => <span class="hljs-number">5</span> }</pre></div><p id="435b">All together now:</p><div id="8747"><pre>const maxProfit = function(prices) { <span class="hljs-built_in">let</span> maxProfit = <span class="hljs-number">0</span>; <span class="hljs-built_in">let</span> lowestPrice = prices[<span class="hljs-number">0</span>]; <span class="hljs-keyword">for</span>(<span class="hljs-built_in">let</span> i = <span class="hljs-number">1</span>; i < prices.<span class="hljs-built_in">length</span>; i++) { <span class="hljs-built_in">min</span> = Math.<span class="hljs-built_in">min</span>(prices[i], <span class="hljs-built_in">min</span>); maxProfit = Math.<span class="hljs-built_in">max</span>(maxProfit, prices[i] - <span class="hljs-built_in">min</span>); } <span class="hljs-built_in">return</span> maxProfit; };</pre></div><p id="6ab3">It works! And this time we are only using one loop, plus Math.max() and Math.min():</p><figure id="4fb2"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*jofGRsLrFVN7ZPaxgZfyTw.png"><figcaption></figcaption></figure><p id="7e02"><a href="https://readmedium.com/algorithms-101-jewels-and-stones-in-ruby-and-javascript-c22fce37ad2b"><i>next: Algorithms 101, #9: Jewels and Stones in Ruby and JS</i></a></p><p id="b31b"><a href="https://readmedium.com/algorithms-101-best-time-to-buy-and-sell-stock-in-javascript-7a2249b29495"><i>in case you missed it: Algorithms 101, #7: House Robber in JavaScript</i></a></p><p id="2171">Copyright © Joan Indiana Lyness 2019</p></article></body>

Algorithms 101: best time to buy and sell stock in JavaScript

Noob v. LeetCode, Episode 8, array manipulation

Photo by Chris Liverani on Unsplash

Looking through LeetCode’s top interview questions in the ‘easy’ category, I found this one:

My first approach went like this. For each number in the array- let’s call it buy — find the greatest element to the right — let’s call that one sell. If sell is lower than buy, let’s subtract sell from buy and call the result profit.

Meanwhile, we’ll have another variable called maxProfit that starts at zero. At the end of each loop, if profit is greater than maxProfit, then we’ll set maxProfit equal to profit. If that confuses you, I’ll break it down into steps below.

Step 1. Iterate, while keeping track of index

var maxProfit = function(prices) {
   let profit
   let maxProfit = 0
   
   prices.forEach(function(buy, index) {
       // more code here
   })  
    return maxProfit    
};

Step 2. Make a new sub-array of elements to the right

let rest = prices.slice(index + 1)
//it's index + 1 because we want all elements to the right ...

Step 3. Find the biggest number in that sub-array

But … if we’re looking at the last element of the array, then rest = []. To account for this edge case, let’s first check to see that rest is not null. We’ll use javaScript’s Math.max() to find the largest values. We’ll save that value as sell.

if(rest){
    let sell = Math.max(...rest)
}

Step 4. Calculate profit

If sell is greater than buy (as required by rules of this challenge), we can calculate profit like so:

if (sell > buy){
 profit = sell — buy
 }

Step 5. Check to see if profit is greater than maxProfit

For each buy, we are calculating profit. We started maxProfit at zero. Now, inside our loop, we need to compare the two, and always assign the greater value to maxProfit:

profit > maxProfit ? maxProfit = profit : null

Finally, at the end of our loop, we return maxProfit:

var maxProfit = function(prices) {
   let profit
   let maxProfit = 0
   
   prices.forEach(function(buy, index) {
       let rest = prices.slice(index + 1)       
       if (rest){
         let sell = Math.max(...rest)      
           sell > buy ? profit = sell - buy : null
            profit > maxProfit ? maxProfit = profit : null    
     }     
   })  
    return maxProfit    
};

It works! BUT how does it perform?

We are in the bottom 5 percent!

Why? Because we have nested loops — an if loop inside a for loop, not to mention two ternary operations for each nested loop.

We need a different approach!

Our first approach was to break our array into two arrays, nesting one inside the other. This time, let’s iterate only once. We’ll still set an initial value for maxProfit. We’ll also set an initial value for min (minimum value, ie lowest price).

var maxProfit = function(prices) {
    let maxProfit = 0;
    let min = prices[0];
    for(let i = 1; i < prices.length; i++) {
    // more code here
    }
}

As we iterate we’ll compare our most recent value for min with the next element, and set the lesser of those two values as the new value for min. We’re using javaScript’s Math.min().

const prices = [7,1,5,3,6,4]
min = Math.min(prices[i], min);
        //i = 1, min = Math.min(1,7) => 1

Tracking Profits

In the same loop, we also update maximum profit, which we define as either the previous value for maxProfit, or the current price minus min.

maxProfit = Math.max(maxProfit, prices[i] - min);

Here’s a look at how those values update after each loop:

const prices = [7,1,5,3,6,4]
for(let i = 1; i < prices.length; i++) {
        min = Math.min(prices[i], min);
        //i = 1, lowestPrice = Math.min(1,7) => 1
        //i = 2, lowestPrice = Math.min(5,1) => 1
        //i = 3, lowestPrice = Math.min(3,1) => 1
        //i = 4, lowestPrice = Math.min(6,1) => 1
        //i = 5, lowestPrice = Math.min(4,1) => 1
        maxProfit = Math.max(maxProfit, prices[i] - min);
        //i = 1, Math.max(0, 1 - 1) => 0
        //i = 2, Math.max(0, 5 - 1) => 4
        //i = 3, Math.max(4, 3 - 1) => 4
        //i = 4, Math.max(4, 6 - 1) => 5
        //i = 5, Math.max(5, 4 - 1) => 5
    }

All together now:

const maxProfit = function(prices) {
    let maxProfit = 0;
    let lowestPrice  = prices[0];
    for(let i = 1; i < prices.length; i++) {
        min = Math.min(prices[i], min);
        maxProfit = Math.max(maxProfit, prices[i] - min);
    }
    return maxProfit;
};

It works! And this time we are only using one loop, plus Math.max() and Math.min():

next: Algorithms 101, #9: Jewels and Stones in Ruby and JS

in case you missed it: Algorithms 101, #7: House Robber in JavaScript

Copyright © Joan Indiana Lyness 2019

JavaScript
Programming
Web Development
Coding
Algorithms
Recommended from ReadMedium