{"id":672,"date":"2017-01-18T14:15:01","date_gmt":"2017-01-18T14:15:01","guid":{"rendered":"https:\/\/www.audero.it\/blog\/?p=672"},"modified":"2017-01-18T14:39:42","modified_gmt":"2017-01-18T14:39:42","slug":"from-javascript-developer-to-javascript-engineer-find-all-celebrities-in-a-set-of-people","status":"publish","type":"post","link":"https:\/\/www.audero.it\/blog\/2017\/01\/18\/from-javascript-developer-to-javascript-engineer-find-all-celebrities-in-a-set-of-people\/","title":{"rendered":"From JavaScript developer to JavaScript engineer: find all celebrities in a set of people"},"content":{"rendered":"<p>In the first article of my series <cite><a href=\"https:\/\/www.audero.it\/blog\/category\/javascript\/from-javascript-developer-to-javascript-engineer\/\">From JavaScript developer to JavaScript engineer<\/a><\/cite> titled <cite><a href=\"https:\/\/www.audero.it\/blog\/2016\/12\/16\/from-javascript-developer-to-javascript-engineer-re-implementing-ecmascript-2015s-string-prototype-repeat-method\/\">From JavaScript developer to JavaScript engineer: Re-implementing ECMAScript 2015&#8217;s String.prototype.repeat() method<\/a><\/cite> I&#8217;ve discussed how <strong>computer science concepts can help in writing better and more elegant software<\/strong>. Specifically, I&#8217;ve demonstrated how to use appropriate <strong>algorithms and data structures<\/strong>, together with techniques like memoization, to re-implement the <code>String.prototype.repeat()<\/code> method so that it&#8217;s blazing fast.<\/p>\n<p>In this second article of the series, I&#8217;ll discuss how important is reasoning about the problem we&#8217;re facing. To do that, I&#8217;ll analyze the problem of finding all celebrities in a set of people.<\/p>\n<p>If you want to take a look at the final solution, you can either go to the section <cite>An efficient solution<\/cite> or browse my <a href=\"https:\/\/github.com\/AurelioDeRosa\/interview-questions\" target=\"_blank\"><cite>Interview questions<\/cite> repository on GitHub<\/a>.<br \/>\n<!--more--><\/p>\n<h2>Introducing the problem<\/h2>\n<p><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"705\" data-permalink=\"https:\/\/www.audero.it\/blog\/2017\/01\/18\/from-javascript-developer-to-javascript-engineer-find-all-celebrities-in-a-set-of-people\/oscars-2014-selfie\/\" data-orig-file=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2016\/12\/oscars-2014-selfie.jpg\" data-orig-size=\"620,387\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"oscars 2014 selfie\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2016\/12\/oscars-2014-selfie.jpg\" src=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2016\/12\/oscars-2014-selfie.jpg\" alt=\"\" width=\"620\" height=\"387\" class=\"aligncenter size-full wp-image-705\" srcset=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2016\/12\/oscars-2014-selfie.jpg 620w, https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2016\/12\/oscars-2014-selfie-300x187.jpg 300w\" sizes=\"auto, (max-width: 620px) 100vw, 620px\" \/><\/p>\n<p>The problem I&#8217;ll analyze in this article is about finding all the celebrities in a set of people. On its own, this isn&#8217;t very informative, so here it is the text of the problem:<\/p>\n<blockquote><p>A person is considered a celebrity if he\/she likes nobody and everybody likes him\/her. Given a set of people and a function <code>likes(i, j)<\/code>, which takes the names of two people as parameters and returns <code>true<\/code> if <var>i<\/var> likes <var>j<\/var> and <code>false<\/code> otherwise, write a <code>findCelebrities()<\/code> function to return all the celebrities in the given set.<\/p><\/blockquote>\n<p>The description of the problem might have still left you a bit confused, so let&#8217;s consider a couple of examples.<\/p>\n<p>Given an empty set of people (for example, <code>const people = [];<\/code>), regardless of the values returned by the <code>likes()<\/code> function, <code>findCelebrities()<\/code> should return an empty set (that is <code>[]<\/code>).<\/p>\n<p>Let&#8217;s now consider a more complex example. Given a set of many people:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nconst people = &#x5B;\r\n   'Mark',\r\n   'David',\r\n   'John',\r\n   'Aurelio',\r\n   'Anna',\r\n   'Peter'\r\n];\r\n<\/pre>\n<p>and the following <code>likes()<\/code> function:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nfunction likes(i, j) {\r\n   return i !== 'Peter';\r\n}\r\n<\/pre>\n<p><code>findCelebrities()<\/code> should return:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nfindCelebrities(people, likes); \/\/ &#x5B;'Peter']\r\n<\/pre>\n<p>These two examples have hopefully clarified the behavior of the <code>findCelebrities()<\/code> function. So, it&#8217;s now time to implement it.<\/p>\n<h2>A simple solution<\/h2>\n<p>The text of the problem asks to find all celebrities in a set of people. A celebrity is defined as someone that likes nobody and is liked by everyone. This condition can be expressed with the following set-builder notation:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"677\" data-permalink=\"https:\/\/www.audero.it\/blog\/2017\/01\/18\/from-javascript-developer-to-javascript-engineer-find-all-celebrities-in-a-set-of-people\/celebrities-set-builder-formula\/\" data-orig-file=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2016\/12\/celebrities-set-builder-formula.png\" data-orig-size=\"506,23\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"celebrities set builder formula\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2016\/12\/celebrities-set-builder-formula.png\" src=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2016\/12\/celebrities-set-builder-formula.png\" alt=\"The set C is made of all the i such that i belongs to P and for all the j belonging to P, with i not equal to j, it occurs that likes(j, i) and not likes(i, j)\" width=\"506\" height=\"23\" class=\"aligncenter size-full wp-image-677\" srcset=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2016\/12\/celebrities-set-builder-formula.png 506w, https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2016\/12\/celebrities-set-builder-formula-300x14.png 300w\" sizes=\"auto, (max-width: 506px) 100vw, 506px\" \/><\/p>\n<p>This notation gives us the simplest solution to the problem. We start with a fixed person, let&#8217;s call this person <var>candidate<\/var>, and loop through the whole set <var>P<\/var> (where <var>P<\/var> stands for people) to verify the condition that everyone else likes <var>candidate<\/var> and <var>candidate<\/var> dislikes everyone else. We can stop the loop as soon as one of these two conditions is not verified. In such case, we know that <var>candidate<\/var> is not a celebrity. We then repeat this process for every person in the set <var>P<\/var>. Once done, we&#8217;ll obtain the set <var>C<\/var> of all the celebrities.<\/p>\n<p>Turning this description into code, results in the following code:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nfunction findCelebrities(people, likes) {\r\n   return people.filter(function(candidate) {\r\n      return !people.find(function(person) {\r\n         return person !== candidate &amp;&amp;\r\n            (likes(candidate, person) || !likes(person, candidate));\r\n      });\r\n   });\r\n}\r\n<\/pre>\n<p>The code above is concise but not very efficient. If we analyze its time complexity, we can demonstrate that it&#8217;s an <em>O(<var>n<\/var><sup>2<\/sup>)<\/em> where <var>n<\/var> is the number of the people in the set. The reason is that we loop over every person in the set and for each of them we scan again the whole set to verify that the conditions to be a celebrity are met.<\/p>\n<p><small>If you have never heard of <a href=\"https:\/\/en.wikipedia.org\/wiki\/Big_O_notation\">the Big O notation<\/a>, I suggest you to learn more about it. It\u2019s a fundamental concept to analyze the performance of your algorithms.<\/small><\/p>\n<p>The time complexity of this function can be heavily improved. In the next section I&#8217;ll show you how.<\/p>\n<h2>Analysis of the problem<\/h2>\n<p>To understand how we can optimize <code>findCelebrities()<\/code>, we have to think what its weak points are.<\/p>\n<h3>Every set has at most one celebrity<\/h3>\n<p>The most important point to understand is the amount of celebrities that may be present in the given set. The text asks to find all of them, but in a given set there may be at most one. The demonstration can be made by using <a href=\"https:\/\/en.wikipedia.org\/wiki\/Reductio_ad_absurdum\" target=\"_blank\"><em lang=\"la\">reductio ad absurdum<\/em><\/a>.<\/p>\n<p>Let&#8217;s say that more than one celebrity can be present in the set, for example two. We may assume, without loss of generality, that they are the first and the second person that we&#8217;ll process. Because the first person is a celebrity, it occurs that everyone else likes the person and the latter doesn&#8217;t like everyone else. But if this is true, then it means that the second celebrity is at least not liked by the first celebrity (it&#8217;s also true that the second celebrity likes someone, the first celebrity). Therefore, the second celebrity can&#8217;t be a celebrity at all, which confirms the previous statement.<\/p>\n<h3>Choosing the best candidate to be a celebrity<\/h3>\n<p>Thanks to the consideration of the previous section, we can optimize the algorithm to search for the best candidate to be a celebrity. Once we find it, we test that this person meets the two conditions required. If the conditions are met, we have a celebrity; otherwise the set doesn&#8217;t include any celebrity.<\/p>\n<p>We can start with the assumption that the first person in the set is the best candidate and test the relation against the other people in the set, one at a time. If one of the two conditions is not met, that is if the candidate likes the person currently under analysis or the candidate isn&#8217;t liked by the person, we know that the current best candidate isn&#8217;t a celebrity. In particular, we deal with two possible scenarios:<\/p>\n<ul>\n<li>The current best candidate likes the person: without further processing, we assume the current person under analysis (the one the candidate was tested against) to be the best candidate and we continue the process<\/li>\n<li>The current best candidate doesn&#8217;t like the person but the latter doesn&#8217;t like the current best candidate: both of them are not celebrities. Therefore, we can continue the process starting from the person following the one we tested against<\/li>\n<\/ul>\n<p>On the other hand, if both the conditions are met while analyzing a candidate and a person, we can exclude the latter as a celebrity. In fact, because both the conditions are met, it means that the person likes the candidate and the person isn&#8217;t liked by the candidate.<\/p>\n<p>Once we complete this process, we test that our best candidate meets the two conditions against all the other people in the set (those that haven&#8217;t been tested yet with this candidate).<\/p>\n<p>This new approach changes the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Time_complexity\" target=\"_blank\">time complexity<\/a> of the function. We have passed from an execution time that can be expressed by a squared function to an execution time that can be expressed by a linear function. So, if our set was made of 1000 people, we have moved from 1000000 operations to just 1000 operations. The image below should also help in visualizing the difference in the operations executed by the two versions discussed in this post.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"691\" data-permalink=\"https:\/\/www.audero.it\/blog\/2017\/01\/18\/from-javascript-developer-to-javascript-engineer-find-all-celebrities-in-a-set-of-people\/time-complexity-comparison-findcelebrities\/\" data-orig-file=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2016\/12\/time-complexity-comparison-findcelebrities.png\" data-orig-size=\"600,371\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"time complexity comparison findcelebrities\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2016\/12\/time-complexity-comparison-findcelebrities.png\" src=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2016\/12\/time-complexity-comparison-findcelebrities.png\" alt=\"\" width=\"600\" height=\"371\" class=\"aligncenter size-full wp-image-691\" srcset=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2016\/12\/time-complexity-comparison-findcelebrities.png 600w, https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2016\/12\/time-complexity-comparison-findcelebrities-300x186.png 300w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<h4>New approach in action<\/h4>\n<p>To further clarify the strategy described, let&#8217;s discuss an example with the support of some images. Let&#8217;s say that we have a set of people defined as follows:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nconst people = &#x5B;\r\n   'Mark',\r\n   'David',\r\n   'John',\r\n   'Aurelio',\r\n   'Anna',\r\n   'Peter'\r\n];\r\n<\/pre>\n<p>The <code>likes()<\/code> function for this example is reported below:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nfunction likes(i, j) {\r\n   const likesMap = new Map(&#x5B;\r\n      &#x5B;'Mark', &#x5B;'David', 'John', 'Aurelio', 'Anna', 'Peter']],\r\n      &#x5B;'David', &#x5B;'Mark', 'Anna', 'Peter']],\r\n      &#x5B;'John', &#x5B;'Mark', 'David', 'Aurelio', 'Anna']],\r\n      &#x5B;'Aurelio', &#x5B;'Peter', 'Anna']],\r\n      &#x5B;'Anna', &#x5B;]],\r\n      &#x5B;'Peter', &#x5B;'Anna']]\r\n   ]);\r\n\r\n   return likesMap.get(i).includes(j);\r\n}\r\n<\/pre>\n<p>Let&#8217;s now see what happens by applying the approach discussed in this section.<\/p>\n<h5>Step 1<\/h5>\n<p>We assume the best candidate to be the first element in the set, Mark. We start to scan the set from the person at the second position (having index of 1), David.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"722\" data-permalink=\"https:\/\/www.audero.it\/blog\/2017\/01\/18\/from-javascript-developer-to-javascript-engineer-find-all-celebrities-in-a-set-of-people\/findcelebrities-step-1\/\" data-orig-file=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2017\/01\/findcelebrities-step-1.png\" data-orig-size=\"355,101\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"findcelebrities step 1\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2017\/01\/findcelebrities-step-1.png\" src=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2017\/01\/findcelebrities-step-1.png\" alt=\"\" width=\"355\" height=\"101\" class=\"aligncenter size-full wp-image-722\" srcset=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2017\/01\/findcelebrities-step-1.png 355w, https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2017\/01\/findcelebrities-step-1-300x85.png 300w\" sizes=\"auto, (max-width: 355px) 100vw, 355px\" \/><\/p>\n<p>The call to <code>likes('Mark', 'David')<\/code> returns <code>true<\/code>, so Mark can&#8217;t be a celebrity. We update our <var>candidate<\/var> variable, and we set it so that the new potential celebrity is David. We continue to loop over the set.<\/p>\n<h5>Step 2<\/h5>\n<p>Our candidate is David and we test him against John.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"723\" data-permalink=\"https:\/\/www.audero.it\/blog\/2017\/01\/18\/from-javascript-developer-to-javascript-engineer-find-all-celebrities-in-a-set-of-people\/findcelebrities-step-2\/\" data-orig-file=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2017\/01\/findcelebrities-step-2.png\" data-orig-size=\"342,101\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"findcelebrities step 2\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2017\/01\/findcelebrities-step-2.png\" src=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2017\/01\/findcelebrities-step-2.png\" alt=\"\" width=\"342\" height=\"101\" class=\"aligncenter size-full wp-image-723\" srcset=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2017\/01\/findcelebrities-step-2.png 342w, https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2017\/01\/findcelebrities-step-2-300x89.png 300w\" sizes=\"auto, (max-width: 342px) 100vw, 342px\" \/><\/p>\n<p>The call to <code>likes('David', 'John')<\/code> returns <code>false<\/code>. To know if we have to keep David as the best candidate, we need to test if John likes David. The call to <code>likes('John', 'David')<\/code> returns <code>true<\/code>. So, at least for now, David is a good candidate to be a celebrity. But we have many other people to test against, so we continue to loop over the set.<\/p>\n<h5>Step 3<\/h5>\n<p>We test David against Aurelio.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"724\" data-permalink=\"https:\/\/www.audero.it\/blog\/2017\/01\/18\/from-javascript-developer-to-javascript-engineer-find-all-celebrities-in-a-set-of-people\/findcelebrities-step-3\/\" data-orig-file=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2017\/01\/findcelebrities-step-3.png\" data-orig-size=\"342,101\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"findcelebrities step 3\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2017\/01\/findcelebrities-step-3.png\" src=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2017\/01\/findcelebrities-step-3.png\" alt=\"\" width=\"342\" height=\"101\" class=\"aligncenter size-full wp-image-724\" srcset=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2017\/01\/findcelebrities-step-3.png 342w, https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2017\/01\/findcelebrities-step-3-300x89.png 300w\" sizes=\"auto, (max-width: 342px) 100vw, 342px\" \/><\/p>\n<p>The call to <code>likes('David', 'Aurelio')<\/code> returns <code>false<\/code>. Unfortunately, the call to <code>likes('Aurelio', 'David')<\/code> returns <code>false<\/code> as well, hence David can&#8217;t be a celebrity. Moreover, because Aurelio is not liked by at least one person (David), we can exclude Aurelio too.<\/p>\n<p>We update the <var>candidate<\/var> variable so that the new potential celebrity is Anna. This time we also update <var>i<\/var> to have as a value the index of the person following Anna in the set (Peter).<\/p>\n<h5>Step 4<\/h5>\n<p>The new candidate is Anna and we test her against Peter.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"725\" data-permalink=\"https:\/\/www.audero.it\/blog\/2017\/01\/18\/from-javascript-developer-to-javascript-engineer-find-all-celebrities-in-a-set-of-people\/findcelebrities-step-4\/\" data-orig-file=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2017\/01\/findcelebrities-step-4.png\" data-orig-size=\"342,101\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"findcelebrities step 4\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2017\/01\/findcelebrities-step-4.png\" src=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2017\/01\/findcelebrities-step-4.png\" alt=\"\" width=\"342\" height=\"101\" class=\"aligncenter size-full wp-image-725\" srcset=\"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2017\/01\/findcelebrities-step-4.png 342w, https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2017\/01\/findcelebrities-step-4-300x89.png 300w\" sizes=\"auto, (max-width: 342px) 100vw, 342px\" \/><\/p>\n<p>The call to <code>likes('Anna', 'Peter')<\/code> returns <code>false<\/code> and the call <code>likes('Peter', 'Anna')<\/code> returns <code>true<\/code>. This means that Anna is still a good candidate to be a celebrity.<\/p>\n<p>Peter is the last person in the set, so we keep Anna as the best candidate and we move onto the next part of the process.<\/p>\n<h5>Step 5<\/h5>\n<p>We have verified that both the conditions to be a celebrity are met for all the people that come <em>after<\/em> Anna in the set. So, now we need to test that the conditions are verified for all the people that come <em>before<\/em> Anna. If all the tests are passed, Anna is a celebrity; if even one condition is not met, there are no celebrities in the set and we can stop searching for one.<\/p>\n<p>Without showing the steps left, I can assure you that Anna will be successfully verified as a celebrity.<\/p>\n<p>With this last consideration, we are ready to implement the final solution. If you want to see some metrics about how the first solution and the efficient solution compares, have a look at the section titled <cite>Performance comparison<\/cite>.<\/p>\n<h2>An efficient solution<\/h2>\n<p>Thanks to our analysis of the problem, we&#8217;re now ready to implement an efficient version of the <code>findCelebrities()<\/code> function.<\/p>\n<p>We can start by managing the cases where the set of people is either empty or contains only one person. In these cases, the celebrities are zero and one respectively.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nif (people.length &lt; 2) {\r\n   return people.slice();\r\n}\r\n<\/pre>\n<p>If the set of people contains more than one person, we can start the process outlined in the section <cite>Choosing the best candidate to be a celebrity<\/cite>. So, we start assuming our best candidate to be a celebrity is the first person in the set. Then, we test the candidate against all of the other people. Along the way, we might need to update the best candidate because we find that the current one likes someone or the candidate isn&#8217;t liked by someone.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nlet candidate = 0;\r\n\r\nfor (let i = 1; i &lt; people.length; i++) {\r\n   if (likes(people&#x5B;candidate], people&#x5B;i])) {\r\n      candidate = i;\r\n   } else if (!likes(people&#x5B;i], people&#x5B;candidate])) {\r\n      candidate = ++i;\r\n   }\r\n}\r\n<\/pre>\n<p>When testing the best candidate against the last person in the set, we might find out that both of them aren&#8217;t celebrities. In this case, <var>candidate<\/var> will be updated to an index outside of the range of the set. If this happens, we know that the set doesn&#8217;t include any celebrity.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nif (candidate === people.length) {\r\n   return &#x5B;];\r\n}\r\n<\/pre>\n<p>Finally, we verify that the conditions to be a celebrity are met against all the people that haven&#8217;t been tested in the previous scan. If any of the conditions is not met, we return an empty set; otherwise we return a set that contains as its only element the best candidate.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nfor (let i = 0; i &lt; candidate; i++) {\r\n   if (likes(people&#x5B;candidate], people&#x5B;i]) ||\r\n       !likes(people&#x5B;i], people&#x5B;candidate])\r\n   ) {\r\n      return &#x5B;];\r\n   }\r\n}\r\n\r\nreturn people.slice(candidate, candidate + 1);\r\n<\/pre>\n<p>The final version of the <code>findCelebrities()<\/code> function can be found in my <a href=\"https:\/\/github.com\/AurelioDeRosa\/interview-questions\" target=\"_blank\"><cite>Interview questions<\/cite> repository on GitHub<\/a> and it&#8217;s also listed below:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nfunction findCelebrities(people, likes) {\r\n   if (people.length &lt; 2) {\r\n      return people.slice();\r\n   }\r\n\r\n   let candidate = 0;\r\n\r\n   for (let i = 1; i &lt; people.length; i++) {\r\n      if (likes(people&#x5B;candidate], people&#x5B;i])) {\r\n         candidate = i;\r\n      } else if (!likes(people&#x5B;i], people&#x5B;candidate])) {\r\n         candidate = ++i;\r\n      }\r\n   }\r\n\r\n   if (candidate === people.length) {\r\n      return &#x5B;];\r\n   }\r\n\r\n   for (let i = 0; i &lt; candidate; i++) {\r\n      if (likes(people&#x5B;candidate], people&#x5B;i]) ||\r\n          !likes(people&#x5B;i], people&#x5B;candidate])\r\n      ) {\r\n         return &#x5B;];\r\n      }\r\n   }\r\n\r\n   return people.slice(candidate, candidate + 1);\r\n}\r\n<\/pre>\n<h2>Performance comparison<\/h2>\n<p>Now that we&#8217;ve discussed the simple and the final version, it&#8217;s worth discussing how faster the latter improves the performance compared to the former. In this section, I want to show you some data so that you can visualize the improvement.<\/p>\n<p>The table below shows the number of operations of the two versions for different sizes of the set of people.<\/p>\n<table>\n<tbody>\n<tr>\n<th>Size<\/th>\n<th>Simple<\/th>\n<th>Final<\/th>\n<\/tr>\n<tr>\n<td>1<\/td>\n<td>1<\/td>\n<td>1<\/td>\n<\/tr>\n<tr>\n<td>10<\/td>\n<td>100<\/td>\n<td>10<\/td>\n<\/tr>\n<tr>\n<td>100<\/td>\n<td>10000<\/td>\n<td>100<\/td>\n<\/tr>\n<tr>\n<td>1000<\/td>\n<td>1000000<\/td>\n<td>1000<\/td>\n<\/tr>\n<tr>\n<td>10000<\/td>\n<td>100000000<\/td>\n<td>10000<\/td>\n<\/tr>\n<tr>\n<td>100000<\/td>\n<td>10000000000<\/td>\n<td>100000<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The second table reports the execution times of both the solutions. To calculate them, I used the <a href=\"https:\/\/www.sitepoint.com\/discovering-the-high-resolution-time-api\/\" target=\"_blank\">High Resolution Time API<\/a> to retrieve the current time in milliseconds, with the microseconds in the fractional part. Moreover, in order to have a more accurate estimation, I&#8217;ve executed both the functions for 10000 times and calculated the average execution time for each value of <var>size<\/var>. It&#8217;s also important to mention the conditions in which the functions were executed. The set of people was always created to include a celebrity and to have it in the middle. So, if the size of the set was 1000, the celebrity was at position 500.<\/p>\n<table>\n<tbody>\n<tr>\n<th>Size<\/th>\n<th>Simple<\/th>\n<th>Final<\/th>\n<\/tr>\n<tr>\n<td>1<\/td>\n<td>0.0013237499999999482<\/td>\n<td>0.002664349999999955<\/td>\n<\/tr>\n<tr>\n<td>10<\/td>\n<td>0.004032200000000131<\/td>\n<td>0.0013155000000000467<\/td>\n<\/tr>\n<tr>\n<td>100<\/td>\n<td>0.10371665000000113<\/td>\n<td>0.0016612499999999995<\/td>\n<\/tr>\n<tr>\n<td>1000<\/td>\n<td>9.445168000000002<\/td>\n<td>0.008824599999999932<\/td>\n<\/tr>\n<tr>\n<td>10000<\/td>\n<td>888.4801000000001<\/td>\n<td>0.10347660000000054<\/td>\n<\/tr>\n<tr>\n<td>100000<\/td>\n<td>94304.16500000001<\/td>\n<td>1.0804022500000032<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>As you can see, the difference in performance of the two functions is astonishing. For a set of people of size 100000, <strong>the final version is ~87200 times faster than the simple version<\/strong>.<\/p>\n<h2>Conclusions<\/h2>\n<p>In this second article of my series <cite><a href=\"https:\/\/www.audero.it\/blog\/category\/javascript\/from-javascript-developer-to-javascript-engineer\/\">From JavaScript developer to JavaScript engineer<\/a><\/cite>, I&#8217;ve discussed the problem of finding all the celebrities in a set. The main take-away lesson of this article is that reasoning about the problem we&#8217;re facing is very important because it allows us to avoid sub-optimal solutions and it might lead us to conclusions we didn&#8217;t foresee at the beginning. The findings of our analysis can help us in writing better and faster software.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the first article of my series <cite><a href=\"https:\/\/www.audero.it\/blog\/category\/javascript\/from-javascript-developer-to-javascript-engineer\/\">From JavaScript developer to JavaScript engineer<\/a><\/cite> titled <cite><a href=\"https:\/\/www.audero.it\/blog\/2016\/12\/16\/from-javascript-developer-to-javascript-engineer-re-implementing-ecmascript-2015s-string-prototype-repeat-method\/\">From JavaScript developer to JavaScript engineer: Re-implementing ECMAScript 2015&#8217;s String.prototype.repeat() method<\/a><\/cite> I&#8217;ve discussed how <strong>computer science concepts can help in writing better and more elegant software<\/strong>. Specifically, I&#8217;ve demonstrated how to use appropriate <strong>algorithms and data structures<\/strong>, together with techniques like memoization, to re-implement the <code>String.prototype.repeat()<\/code> method so that it&#8217;s blazing fast.<\/p>\n<p>In this second article of the series, I&#8217;ll discuss how important is reasoning about the problem we&#8217;re facing. To do that, I&#8217;ll analyze the problem of finding all celebrities in a set of people.<\/p>\n<p>If you want to take a look at the final solution, you can either go to the section <cite>An efficient solution<\/cite> or browse my <a href=\"https:\/\/github.com\/AurelioDeRosa\/interview-questions\" target=\"_blank\"><cite>Interview questions<\/cite> repository on GitHub<\/a>.<\/p>\n","protected":false},"author":1,"featured_media":728,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[76,3],"tags":[73,75,74,72,70,46,23],"class_list":["post-672","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-from-javascript-developer-to-javascript-engineer","category-javascript","tag-algorithm","tag-computer-science","tag-data-structure","tag-ecmascript","tag-ecmascript-2015","tag-javascript","tag-performance"],"jetpack_featured_media_url":"https:\/\/www.audero.it\/blog\/wp-content\/uploads\/2017\/01\/vip.png","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p9Or4e-aQ","jetpack-related-posts":[{"id":637,"url":"https:\/\/www.audero.it\/blog\/2016\/12\/16\/from-javascript-developer-to-javascript-engineer-re-implementing-ecmascript-2015s-string-prototype-repeat-method\/","url_meta":{"origin":672,"position":0},"title":"From JavaScript developer to JavaScript engineer: re-implementing ECMAScript 2015&#8217;s String.prototype.repeat() method","author":"Aurelio De Rosa","date":"December 16, 2016","format":false,"excerpt":"As developers, our work is to solve problems which often implies writing code. Some of the problems we face look really simple in nature, but their simplicity leads us to write sub-optimal solutions without even realizing it. JavaScript developers come from very different backgrounds, and assuming that everyone has the\u2026","rel":"","context":"In &quot;From JavaScript developer to JavaScript engineer&quot;","block_context":{"text":"From JavaScript developer to JavaScript engineer","link":"https:\/\/www.audero.it\/blog\/category\/javascript\/from-javascript-developer-to-javascript-engineer\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2016\/12\/time-complexity-comparison.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2016\/12\/time-complexity-comparison.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2016\/12\/time-complexity-comparison.png?resize=525%2C300&ssl=1 1.5x"},"classes":[]},{"id":626,"url":"https:\/\/www.audero.it\/blog\/2016\/12\/05\/monkey-patching-javascript\/","url_meta":{"origin":672,"position":1},"title":"Monkey patching in JavaScript","author":"Aurelio De Rosa","date":"December 5, 2016","format":false,"excerpt":"When working on a project, we often use libraries that implement methods that aren't built-in in the programming language in use but we need. These libraries don't cover all the possible methods, so they might lack one or more crucial features we need. When this happens, we have two choices:\u2026","rel":"","context":"In &quot;JavaScript&quot;","block_context":{"text":"JavaScript","link":"https:\/\/www.audero.it\/blog\/category\/javascript\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2016\/12\/monkey-patching.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":832,"url":"https:\/\/www.audero.it\/blog\/2018\/07\/20\/5-javascript-interview-questions-a-mid-level-developer-should-be-able-to-answer\/","url_meta":{"origin":672,"position":2},"title":"5 JavaScript interview questions a mid-level developer should be able to answer","author":"Aurelio De Rosa","date":"July 20, 2018","format":false,"excerpt":"According to the results of the 2018's StackOverflow survey, JavaScript is the most popular technology. The amount of job offers for JavaScript developers is constantly increasing and with more companies adopting JavaScript as their main language, it's easy to find good ones. But before you are hired by a company,\u2026","rel":"","context":"In &quot;JavaScript&quot;","block_context":{"text":"JavaScript","link":"https:\/\/www.audero.it\/blog\/category\/javascript\/"},"img":{"alt_text":"job interview panel","src":"https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2016\/06\/job-interview-panel.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2016\/06\/job-interview-panel.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2016\/06\/job-interview-panel.jpg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2016\/06\/job-interview-panel.jpg?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2016\/06\/job-interview-panel.jpg?resize=1050%2C600&ssl=1 3x"},"classes":[]},{"id":387,"url":"https:\/\/www.audero.it\/blog\/2015\/05\/29\/trick-of-the-day-immutability-in-javascript\/","url_meta":{"origin":672,"position":3},"title":"Trick of the day: Immutability in JavaScript","author":"Aurelio De Rosa","date":"May 29, 2015","format":false,"excerpt":"In computer science there is a concept called Immutability. If you create an immutable object, once it's created you aren't allowed to change it anymore. This includes adding, modifying, or deleting a properties. For very simple situations, this concept isn't used a lot. However, if you start writing complex applications\u2026","rel":"","context":"In &quot;Trick of the day&quot;","block_context":{"text":"Trick of the day","link":"https:\/\/www.audero.it\/blog\/category\/trick-of-the-day\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":612,"url":"https:\/\/www.audero.it\/blog\/2016\/11\/29\/most-used-npm-commands\/","url_meta":{"origin":672,"position":4},"title":"My most used npm commands","author":"Aurelio De Rosa","date":"November 29, 2016","format":false,"excerpt":"If you're a front-end or a JavaScript developer, you're surely using npm. npm is a registry where people publish their software. At the beginning, it was used to share JavaScript libraries and frameworks, but today you can also find CSS frameworks, font icons, and much more. In addition to being\u2026","rel":"","context":"In &quot;JavaScript&quot;","block_context":{"text":"JavaScript","link":"https:\/\/www.audero.it\/blog\/category\/javascript\/"},"img":{"alt_text":"npm","src":"https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2016\/11\/npm.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2016\/11\/npm.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2016\/11\/npm.jpg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2016\/11\/npm.jpg?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":329,"url":"https:\/\/www.audero.it\/blog\/2014\/09\/19\/resources-beginner-front-end-developers\/","url_meta":{"origin":672,"position":5},"title":"Resources for Beginner Front-end Developers","author":"Aurelio De Rosa","date":"September 19, 2014","format":false,"excerpt":"Few weeks ago I received an email from a developer asking me for suggestions on how to delve into the front-end world. After having replied to this email, I thought that it'd have been nice to share the same suggestions on my blog. That's exactly what you'll find in this\u2026","rel":"","context":"In &quot;Discussions &amp; Opinions&quot;","block_context":{"text":"Discussions &amp; Opinions","link":"https:\/\/www.audero.it\/blog\/category\/discussions-opinions\/"},"img":{"alt_text":"html5 css3 javascript logos","src":"https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2014\/09\/front-end-stack.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2014\/09\/front-end-stack.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2014\/09\/front-end-stack.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2014\/09\/front-end-stack.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/www.audero.it\/blog\/wp-content\/uploads\/2014\/09\/front-end-stack.png?resize=1050%2C600&ssl=1 3x"},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.audero.it\/blog\/wp-json\/wp\/v2\/posts\/672","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.audero.it\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.audero.it\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.audero.it\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.audero.it\/blog\/wp-json\/wp\/v2\/comments?post=672"}],"version-history":[{"count":22,"href":"https:\/\/www.audero.it\/blog\/wp-json\/wp\/v2\/posts\/672\/revisions"}],"predecessor-version":[{"id":727,"href":"https:\/\/www.audero.it\/blog\/wp-json\/wp\/v2\/posts\/672\/revisions\/727"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.audero.it\/blog\/wp-json\/wp\/v2\/media\/728"}],"wp:attachment":[{"href":"https:\/\/www.audero.it\/blog\/wp-json\/wp\/v2\/media?parent=672"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.audero.it\/blog\/wp-json\/wp\/v2\/categories?post=672"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.audero.it\/blog\/wp-json\/wp\/v2\/tags?post=672"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}