freeCodeCamp/challenges/08-coding-interview-questio.../coding-interview-data-struc...

2830 lines
209 KiB
JSON
Raw Normal View History

2017-01-17 04:44:38 +00:00
{
2017-01-20 22:31:35 +00:00
"name": "Coding Interview Data Structure Questions",
"order": 2,
"time": "",
"helpRoom": "HelpJavaScript",
2017-01-17 04:44:38 +00:00
"challenges": [
{
"id": "587d8253367417b2b2512c6a",
"title": "Typed Arrays",
"description": [
"Arrays are JavaScript objects that can hold a lot of different elements.",
"<code>var complexArr = [1, 5, \"2\", \"Word\", {\"name\": \"James\"}];</code>",
"Basically what happens in the background is that your browser will automatically give the right amount of memory space for that array. It will also change as needed if you add or remove data.",
"However, in the world of high performance and different element types, sometimes you need to be more specific on how much memory is given to an array.",
"<dfn>Typed arrays</dfn> are the answer to this problem. You are now able to say how much memory you want to give an array. Below is a basic overview of the different types of arrays available and the size in bytes for each element in that array.",
"<table class='table table-striped'><tr><th>Type</th><th>Each element size in bytes</th></tr><tr><td><code>Int8Array</code></td><td>1</td></tr><tr><td><code>Uint8Array</code></td><td>1</td></tr><tr><td><code>Uint8ClampedArray</code></td><td>1</td></tr><tr><td><code>Int16Array</code></td><td>2</td></tr><tr><td><code>Uint16Array</code></td><td>2</td></tr><tr><td><code>Int32Array</code></td><td>4</td></tr><tr><td><code>Uint32Array</code></td><td>4</td></tr><tr><td><code>Float32Array</code></td><td>4</td></tr><tr><td><code>Float64Array</code></td><td>8</td></tr></table>",
"There are two ways in creating these kind of arrays. One way is to create it directly. Below is how to create a 3 length <code>Int16Array</code>.",
"<blockquote>var i8 = new Int16Array(3);<br>console.log(i8);<br>// Returns [0, 0, 0]</blockquote>",
"You can also create a <dfn>buffer</dfn> to assign how much data (in bytes) you want the array to take up.",
"<strong>Note</strong><br>To create typed arrays using buffers, you need to assign the number of bytes to be a multiple of the bytes listed above.",
"<blockquote>// Create same Int16Array array differently<br>var byteSize = 6; // Needs to be multiple of 2<br>var buffer = new ArrayBuffer(byteSize);<br>var i8View = new Int16Array(buffer);<br>buffer.byteLength; // Returns 6<br>i8View.byteLength; // Returns 6<br>console.log(i8View); // Returns [0, 0, 0]</blockquote>",
"<dfn>Buffers</dfn> are general purpose objects that just carry data. You cannot access them normally. To access them, you need to first create a <dfn>view</dfn>.",
"<blockquote>i8View[0] = 42;<br>console.log(i8View); // Returns [42, 0, 0]</blockquote>",
"<strong>Note</strong><br>Typed arrays do not have some of the methods traditional arrays have such as <code>.pop()</code> or <code>.push()</code>. Typed arrays also fail <code>Array.isArray()</code> that checks if something is an array. Although simpler, this can be an advantage for less-sophisticated JavaScript engines to implement them.",
"<hr>",
2017-04-14 23:30:38 +00:00
"First create a <code>buffer</code> that is 64-bytes. Then create a <code>Int32Array</code> typed array with a view of it called <code>i32View</code>."
],
"challengeSeed": [
"var buffer;",
"var i32View;"
],
"tests": [
"assert(buffer.byteLength === 64, 'message: Your <code>buffer</code> should be 64 bytes large.');",
"assert(i32View.byteLength === 64, 'message: Your <code>i32View</code> view of your buffer should be 64 bytes large.');",
"assert(i32View.length === 16, 'message: Your <code>i32View</code> view of your buffer should be 16 elements long.');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [
"var buffer = new ArrayBuffer(64);\nvar i32View = new Int32Array(buffer);"
],
"challengeType": 1,
"translations": {}
},
2017-01-17 04:44:38 +00:00
{
"id": "587d8250367417b2b2512c5e",
"title": "Learn how a Stack Works",
"description": [
"You are probably familiar with stack of books on your table. You have likely used the undo feature of a text editor. You are also probably used to hitting the back button on your phone to go back to the previous view in your app.",
2017-01-17 04:44:38 +00:00
"You know what they all have in common? They all store the data in a way so that you can traverse backwards.",
"The topmost book in the stack was the one that was put there last. If you remove that book from your stack's top, you would expose the book that was put there before the last book and so on.",
"If you think about it, in all the above examples, you are getting <dfn>Last-In-First-Out</dfn> type of service. We will try to mimic this with our code.",
"This data storage scheme is called a <dfn>Stack</dfn>. In particular, we would have to implement the <code>push()</code> method that pushes JavaScript objects at the top of the stack; and <code>pop()</code> method, that removes the JavaScript object that's at the top of the stack at the current moment.",
"<hr>",
"Here we have a stack of homework assignments represented as an array: <code>\"BIO12\"</code> is at the base, and <code>\"PSY44\"</code> is at the top of the stack.",
"Modify the given array and treat it like a <code>stack</code> using the JavaScript methods mentioned above. Remove the top element <code>\"PSY44\"</code> from the stack. Then add <code>\"CS50\"</code> to be the new top element of the stack."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"var homeworkStack = [\"BIO12\",\"HIS80\",\"MAT122\",\"PSY44\"];",
"// Only change code below this line",
""
2017-01-17 04:44:38 +00:00
],
"tests": [
"assert(homeworkStack.length === 4, 'message: <code>homeworkStack</code> should only contain 4 elements.');",
"assert(homeworkStack[3] === 'CS50', 'message: The last element in <code>homeworkStack</code> should be <code>\"CS50\"</code>.');",
"assert(homeworkStack.indexOf('PSY44') === -1, 'message: <code>homeworkStack</code> should not contain <code>\"PSY44\"</code>.');",
"assert(code.match(/=/g).length === 1 && /homeworkStack\\s*=\\s*\\[\"BIO12\"\\s*,\\s*\"HIS80\"\\s*,\\s*\"MAT122\"\\s*,\\s*\"PSY44\"\\]/.test(code), 'message: The initial declaration of the <code>homeworkStack</code> should not be changed.');"
2017-01-17 04:44:38 +00:00
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
2017-01-17 04:44:38 +00:00
"challengeType": 1,
"translations": {}
2017-01-17 04:44:38 +00:00
},
{
"id": "587d8250367417b2b2512c5f",
"title": "Create a Stack Class",
"description": [
"In the last section, we talked about what a stack is and how we can use an array to represent a stack. In this section, we will be creating our own stack class.",
"Although you can use arrays to create stacks, sometimes it is best to limit the amount of control we have with our stacks.",
"Apart from the <code>push</code> and <code>pop</code> method, stacks have other useful methods. Let's add a <code>peek</code>, <code>isEmpty</code>, and <code>clear</code> method to our stack class.",
2017-01-17 04:44:38 +00:00
"Instructions",
"Write a <code>push</code> method that pushes an element to the top of the stack, a <code>pop</code> method that removes the element on the top of the stack, a <code>peek</code> method that looks at the first element in the stack, an <code>isEmpty</code> method that checks if the stack is empty, and a <code>clear</code> method that removes all elements from the stack.",
"Normally stacks don't have this, but we've added a <code>print</code> helper method that console logs the collection."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"function Stack() { ",
" collection = [];",
" this.print = function() {",
" console.log(collection);",
" };",
2017-01-17 04:44:38 +00:00
" // Only change code below this line",
"",
" // Only change code above this line",
"}"
2017-01-17 04:44:38 +00:00
],
"tests": [
"assert((function(){var test = new Stack(); return (typeof test.push === 'function')}()), 'message: Your <code>Stack</code> class should have a <code>push</code> method.');",
"assert((function(){var test = new Stack(); return (typeof test.pop === 'function')}()), 'message: Your <code>Stack</code> class should have a <code>pop</code> method.');",
"assert((function(){var test = new Stack(); return (typeof test.peek === 'function')}()), 'message: Your <code>Stack</code> class should have a <code>peek</code> method.');",
"assert((function(){var test = new Stack(); return (typeof test.isEmpty === 'function')}()), 'message: Your <code>Stack</code> class should have a <code>isEmpty</code> method.');",
"assert((function(){var test = new Stack(); return (typeof test.clear === 'function')}()), 'message: Your <code>Stack</code> class should have a <code>clear</code> method.');",
"assert((function(){var test = new Stack(); test.push('CS50'); return (test.peek() === 'CS50')}()), 'message: The <code>peek</code> method should return the top element of the stack');",
"assert((function(){var test = new Stack(); test.push('CS50'); return (test.pop() === 'CS50');}()), 'message: The <code>pop</code> method should remove and return the top element of the stack');",
"assert((function(){var test = new Stack(); return test.isEmpty()}()), 'message: The <code>isEmpty</code> method should return true if a stack does not contain any elements');",
"assert((function(){var test = new Stack(); test.push('CS50'); test.clear(); return (test.isEmpty())}()), 'message: The <code>clear</code> method should remove all element from the stack');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
2017-01-17 04:44:38 +00:00
"challengeType": 1,
"translations": {}
2017-01-17 04:44:38 +00:00
},
{
"id": "587d8250367417b2b2512c60",
"title": "Create a Queue Class",
"description": [
"Like stacks, queues are a collection of elements. But unlike stacks, queues follow the FIFO (First-In First-Out) principle. Elements added to a queue are pushed to the tail, or the end, of the queue, and only the element at the front of the queue is allowed to be removed.",
"We could use an array to represent a queue, but just like stacks, we want to limit the amount of control we have over our queues.",
"The two main methods of a queue class is the enqueue and the dequeue method. The enqueue method pushes an element to the tail of the queue, and the dequeue method removes and returns the element at the front of the queue. Other useful methods are the front, size, and isEmpty methods.",
"Instructions",
"Write an enqueue method that pushes an element to the tail of the queue, a dequeue method that removes and returns the front element, a front method that lets us see the front element, a size method that shows the length, and an isEmpty method to check if the queue is empty."
],
"challengeSeed": [
"function Queue () { ",
" collection = [];",
" this.print = function() {",
2017-01-17 04:44:38 +00:00
" console.log(collection);",
" };",
2017-01-17 04:44:38 +00:00
" // Only change code below this line",
"",
" // Only change code above this line",
"}"
2017-01-17 04:44:38 +00:00
],
"tests": [
"assert((function(){var test = new Queue(); return (typeof test.enqueue === 'function')}()), 'message: Your <code>Queue</code> class should have a <code>enqueue</code> method.');",
"assert((function(){var test = new Queue(); return (typeof test.dequeue === 'function')}()), 'message: Your <code>Queue</code> class should have a <code>dequeue</code> method.');",
2017-01-17 04:44:38 +00:00
"assert((function(){var test = new Queue(); return (typeof test.front === 'function')}()), 'message: Your <code>Queue</code> class should have a <code>front</code> method.');",
"assert((function(){var test = new Queue(); return (typeof test.size === 'function')}()), 'message: Your <code>Queue</code> class should have a <code>size</code> method.');",
"assert((function(){var test = new Queue(); return (typeof test.isEmpty === 'function')}()), 'message: Your <code>Queue</code> class should have an <code>isEmpty</code> method.');",
2017-01-17 04:44:38 +00:00
"assert((function(){var test = new Queue(); test.enqueue('Smith'); return (test.dequeue() === 'Smith')}()), 'message: The <code>dequeue</code> method should remove and return the front element of the queue');",
"assert((function(){var test = new Queue(); test.enqueue('Smith'); test.enqueue('John'); return (test.front() === 'Smith')}()), 'message: The <code>front</code> method should return value of the front element of the queue');",
"assert((function(){var test = new Queue(); test.enqueue('Smith'); return (test.size() === 1)}()), 'message: The <code>size</code> method should return the length of the queue');",
"assert((function(){var test = new Queue(); test.enqueue('Smith'); return !(test.isEmpty())}()), 'message: The <code>isEmpty</code> method should return <code>false</code> if there are elements in the queue');"
2017-01-17 04:44:38 +00:00
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
2017-01-17 04:44:38 +00:00
"challengeType": 1,
"translations": {}
2017-01-17 04:44:38 +00:00
},
{
"id": "587d8255367417b2b2512c74",
"title": "Create a Priority Queue Class",
2017-01-17 04:44:38 +00:00
"description": [
"In this challenge you will be creating a Priority Queue. A Priority Queue is a special type of Queue in which items may have additional information which specifies their priority. This could be simply represented with an integer. Item priority will override placement order in determining the sequence items are dequeued. If an item with a higher priority is enqueued after items with lower priority, the higher priority item will be dequeued before all the others.",
"For instance, lets imagine we have a priority queue with three items:",
"<code>[[kitten, 2], [dog, 2], [rabbit, 2]]</code>",
"Here the second value (an integer) represents item priority. If we enqueue <code>[human, 1]</code> with a priority of <code>1</code> (assuming lower priorities are given precedence) it would then be the first item to be dequeued. The collection would like this:",
"<code>[[human, 1], [kitten, 2], [dog, 2], [rabbit, 2]]</code>.",
"Weve started writing a <code>PriorityQueue</code> in the code editor. You will need to add an <code>enqueue</code> method for adding items with a priority, a <code>dequeue</code> method for removing items, a <code>size</code> method to return the number of items in the queue, a <code>front</code> method to return the element at the front of the queue, and finally an <code>isEmpty</code> method that will return <code>true</code> if the queue is empty or <code>false</code> if it is not.",
"The <code>enqueue</code> should accept items with the format shown above (<code>['human', 1]</code>) where <code>1</code> represents the priority. The <code>dequeue</code> should return only the current item, not its priority."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"function PriorityQueue () {",
" this.collection = [];",
" this.printCollection = function() {",
" console.log(this.collection);",
" };",
" // Only change code below this line",
2017-01-17 04:44:38 +00:00
"",
" // Only change code above this line",
"}"
2017-01-17 04:44:38 +00:00
],
"tests": [
"assert((function(){var test = new PriorityQueue(); return (typeof test.enqueue === 'function')}()), 'message: Your <code>Queue</code> class should have a <code>enqueue</code> method.');",
"assert((function(){var test = new PriorityQueue(); return (typeof test.dequeue === 'function')}()), 'message: Your <code>Queue</code> class should have a <code>dequeue</code> method.');",
"assert((function(){var test = new PriorityQueue(); return (typeof test.size === 'function')}()), 'message: Your <code>Queue</code> class should have a <code>size</code> method.');",
"assert((function(){var test = new PriorityQueue(); return (typeof test.isEmpty === 'function')}()), 'message: Your <code>Queue</code> class should have an <code>isEmpty</code> method.');",
"assert((function(){var test = new PriorityQueue(); test.enqueue(['David Brown', 2]); test.enqueue(['Jon Snow', 1]); var size1 = test.size(); test.dequeue(); var size2 = test.size(); test.enqueue(['A', 3]); test.enqueue(['B', 3]); test.enqueue(['C', 3]); return (size1 === 2 && size2 === 1 && test.size() === 4)}()), 'message: Your PriorityQueue should correctly keep track of the current number of items using the <code>size</code> method as items are enqueued and dequeued.');",
"assert((function(){var test = new PriorityQueue(); test.enqueue(['A', 1]); test.enqueue(['B', 1]); test.dequeue(); var first = test.isEmpty(); test.dequeue(); return (!first && test.isEmpty()); }()), 'message: The <code>isEmpty</code> method should return <code>true</code> when the queue is empty.');",
"assert((function(){var test = new PriorityQueue(); test.enqueue(['A', 5]); test.enqueue(['B', 5]); test.enqueue(['C', 5]); test.enqueue(['D', 3]); test.enqueue(['E', 1]); test.enqueue(['F', 7]); var result = []; result.push(test.dequeue()); result.push(test.dequeue()); result.push(test.dequeue()); result.push(test.dequeue()); result.push(test.dequeue()); result.push(test.dequeue()); return result.join('') === 'EDABCF';}()), 'message: The priority queue should return items with a higher priority before items with a lower priority and return items in first-in-first-out order otherwise.');"
2017-01-17 04:44:38 +00:00
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [
"function PriorityQueue () { \n this.collection = []; \n this.printCollection = function(){ \n console.log(this.collection); \n }; \n this.size = function() { \n return this.collection.length; \n }; \n this.isEmpty = function() { \n return this.size() > 0 ? false : true; \n }; \n this.enqueue = function (newitem) {\n if (this.isEmpty()) {\n return this.collection.push(newitem);\n }\n\n this.collection = this.collection.reverse();\n var found_index = this.collection.findIndex(function (item) {\n return newitem[1] >= item[1];\n });\n if (found_index === -1) {\n this.collection.push(newitem);\n } else {\n this.collection.splice(found_index, 0, newitem);\n }\n this.collection = this.collection.reverse();\n}; \n this.dequeue = function() { \n if (!this.isEmpty()) { \n return this.collection.shift()[0]; \n } else { \n return 'The queue is empty.' \n } \n }; \n }"
],
2017-01-17 04:44:38 +00:00
"challengeType": 1,
"translations": {}
2017-01-17 04:44:38 +00:00
},
{
"id": "587d8255367417b2b2512c75",
"title": "Create a Circular Queue",
2017-01-17 04:44:38 +00:00
"description": [
"In this challenge you will be creating a Circular Queue. A circular queue is basically a queue that writes to the end of a collection then begins over writing itself at the beginning of the collection. This is type of data structure has some useful applications in certain situations. For example, a circular queue can be used for streaming media. Once the queue is full, new media data simply begins to overwrite old data.",
"A good way to illustrate this concept is with an array:",
"<blockquote>[1, 2, 3, 4, 5]<br> ^Read @ 0<br> ^Write @ 0</blockquote>",
"Here the read and write are both at position <code>0</code>. Now the queue gets 3 new records <code>a</code>, <code>b</code>, and <code>c</code>. Our queue now looks like:",
"<blockquote>[a, b, c, 4, 5]<br> ^Read @ 0<br> ^Write @ 3</blockquote>",
"As the read head reads, it can remove values or keep them:",
"<blockquote>[null, null, null, 4, 5]<br> ^Read @ 3<br> ^Write @ 3</blockquote>",
"Once the write reaches the end of the array it loops back to the beginning:",
"<blockquote>[f, null, null, d, e]<br> ^Read @ 3<br> ^Write @ 1</blockquote>",
"This approach requires a constant amount of memory but allows files of a much larger size to be processed.",
"Instructions:",
"In this challenge we will implement a circular queue. The circular queue should provide <code>enqueue</code> and <code>dequeue</code> methods which allow you to read from and write to the queue. The class itself should also accept an integer which you can use to specify the size of the queue when you create it. We've written the starting version of this class for you in the code editor. When you enqueue items to the queue, the write pointer should advance forward and loop back to the beginning once it reaches the end of the queue. Likewise, the read pointer should advance forward as you dequeue items. The write pointer should not be allowed to move past the read pointer (our class won't let you overwrite data you haven't read yet) and the read pointer should not be able to advance past data you have written.",
"In addition, the <code>enqueue</code> method should return the item you enqueued if it is successfully and otherwise return <code>null</code>. Similarly, when you dequeue an item it should be returned and if you cannot dequeue you should return <code>null</code>."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"class CircularQueue {",
" constructor(size) {",
"",
" this.queue = [];",
" this.read = 0;",
" this.write = 0;",
" this.max = size - 1;",
"",
" while (size > 0) {",
" this.queue.push(null);",
" size--;",
" }",
"",
" }",
"",
" print() {",
" return this.queue;",
" }",
"",
"",
" enqueue(item) {",
" // Only change code below this line",
"",
" // Only change code above this line",
" }",
"",
" dequeue() {",
2017-01-17 04:44:38 +00:00
" // Only change code below this line",
"",
" // Only change code above this line",
" }",
"}"
2017-01-17 04:44:38 +00:00
],
"tests": [
"assert((function(){ var test = new CircularQueue(3); test.enqueue(17); test.enqueue(32); test.enqueue(591); var print = test.print(); return print[0] === 17 && print[1] === 32 && print[2] === 591; })(), 'message: The <code>enqueue</code> method adds items to the circular queue.');",
"assert((function(){ var test = new CircularQueue(3); test.enqueue(17); test.enqueue(32); test.enqueue(591); test.enqueue(13); test.enqueue(25); test.enqueue(59); var print = test.print(); return print[0] === 17 && print[1] === 32 && print[2] === 591; })(), 'message: You cannot enqueue items past the read pointer.');",
"assert((function(){ var test = new CircularQueue(3); test.enqueue(17); test.enqueue(32); test.enqueue(591); return test.dequeue() === 17 && test.dequeue() === 32 && test.dequeue() === 591; })(), 'message: The <code>dequeue</code> method dequeues items from the queue.');",
"assert((function(){ var test = new CircularQueue(3); test.enqueue(17); test.enqueue(32); test.enqueue(672); test.dequeue(); test.dequeue(); var print = test.print(); return print[0] === null && print[1] === null && print[2] === 672; })(), 'message: After an item is dequeued its position in the queue should be reset to <code>null</code>.');",
"assert((function(){ var test = new CircularQueue(3); test.enqueue(17); test.enqueue(32); test.enqueue(591); return test.dequeue() === 17 && test.dequeue() === 32 && test.dequeue() === 591 && test.dequeue() === null && test.dequeue() === null && test.dequeue() === null && test.dequeue() === null && test.enqueue(100) === 100 && test.dequeue() === 100; })(), 'message: Trying to dequeue past the write pointer returns <code>null</code> and does not advance the write pointer.');"
2017-01-17 04:44:38 +00:00
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [
"class CircularQueue { \n constructor(size) { \n this.queue = []; \n this.read = 0; \n this.write = 0; \n this.max = size - 1; \n while (size > 0) { \n this.queue.push(null); \n size--; \n } \n } \n print() { \n return this.queue; \n } \n enqueue(item) { \n if (this.queue[this.write] === null) { \n this.queue[this.write] = item; \n if (this.write === this.max) { \n this.write = 0; \n } else { \n this.write++; \n } \n return item; \n } \n return null; \n } \n dequeue() { \n if (this.queue[this.read] !== null) { \n var item = this.queue[this.read]; \n this.queue[this.read] = null; \n if (this.read === this.max) { \n this.read = 0; \n } else { \n this.read++; \n } \n return item; \n } else { \n return null; \n } \n } \n }"
],
2017-01-17 04:44:38 +00:00
"challengeType": 1,
"translations": {}
2017-01-17 04:44:38 +00:00
},
{
"id": "8d1323c8c441eddfaeb5bdef",
"title": "Create a Set Class",
2017-01-17 04:44:38 +00:00
"description": [
"In the next few exercises we are going to create a function to emulate a data structure called a \"Set\". A Set is like an array, but it cannot contain duplicate values. The typical use for a Set is to simply check for the presence of an item. This can be implemented with an object, for instance:",
2017-02-16 12:43:02 +00:00
"<blockquote>var set = new Object();<br>set.foo = true;<br>// See if foo exists in our set:<br>console.log(set.foo) // true</blockquote>",
"In the next few exercises, we will build a full featured Set from scratch.",
2017-02-16 12:43:02 +00:00
"For this exercise, create a function that will add a value to our set collection as long as the value does not already exist in the set. For example:",
"<blockquote>this.add = function(element) {<br> //some code to add value to the set<br>}</blockquote>",
"The function should return <code>true</code> if the value is successfully added and <code>false</code> otherwise."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"function Set() {",
" // the var collection will hold our set",
" var collection = [];",
" // this method will check for the presence of an element and return true or false",
" this.has = function(element) {",
" return (collection.indexOf(element) !== -1);",
" };",
" // this method will return all the values in the set",
" this.values = function() {",
" return collection;",
" };",
" // change code below this line",
" // change code above this line",
"}"
2017-01-17 04:44:38 +00:00
],
"tests": [
"assert((function(){var test = new Set(); return (typeof test.add === 'function')}()), 'message: Your <code>Set</code> class should have an <code>add</code> method.');",
"assert((function(){var test = new Set(); test.add('a'); test.add('b'); test.add('a'); var vals = test.values(); return (vals[0] === 'a' && vals[1] === 'b' && vals.length === 2)}()), 'message: Your <code>add</code> method should not add duplicate values.');",
"assert((function(){var test = new Set(); var result = test.add('a'); return (result != undefined) && (result === true);}()), 'message: Your <code>add</code> method should return <code>true</code> when a value has been successfully added.');",
"assert((function(){var test = new Set(); test.add('a'); var result = test.add('a'); return (result != undefined) && (result === false);}()), 'message: Your <code>add</code> method should return <code>false</code> when a duplicate value is added.');"
2017-01-17 04:44:38 +00:00
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [
"function Set() {var collection = []; this.has = function(e){return(collection.indexOf(e) !== -1);};this.values = function() {return collection;};this.add = function(element) {if (!this.has(element)) {collection.push(element);return true;} else {return false;}};}"
],
"challengeType": 1,
2017-01-17 04:44:38 +00:00
"translations": {}
},
{
"id": "587d8253367417b2b2512c6b",
"title": "Remove from a Set",
"description": [
"In this exercises we are going to create a delete function for our set. The function should be named <code>this.remove</code>. This function should accept a value and check if it exists in the set. If it does, remove that value from the set, and return true. Otherwise, return false."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"function Set() {",
" // the var collection will hold the set",
" var collection = [];",
" // this method will check for the presence of an element and return true or false",
" this.has = function(element) {",
" return (collection.indexOf(element) !== -1);",
" };",
" // this method will return all the values in the set",
" this.values = function() {",
" return collection;",
" };",
" // this method will add an element to the set",
" this.add = function(element) {",
" if(!this.has(element)){",
" collection.push(element);",
" return true;",
" }",
" return false;",
" };",
" // change code below this line",
" // change code above this line",
2017-02-24 01:48:12 +00:00
"}"
2017-01-17 04:44:38 +00:00
],
"tests": [
"assert((function(){var test = new Set(); return (typeof test.remove === 'function')}()), 'message: Your <code>Set</code> class should have a <code>remove</code> method.');",
"assert.deepEqual((function(){var test = new Set(); test.add('a');test.add('b');test.remove('c'); return test.values(); })(), ['a', 'b'], 'message: Your <code>remove</code> method should only remove items that are present in the set.');",
"assert((function(){var test = new Set(); test.add('a');test.add('b');test.remove('a'); var vals = test.values(); return (vals[0] === 'b' && vals.length === 1)}()), 'message: Your <code>remove</code> method should remove the given item from the set.');"
2017-01-17 04:44:38 +00:00
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [
"function Set() {var collection = []; this.has = function(e){return(collection.indexOf(e) !== -1);};this.values = function() {return collection;};this.add = function(element) {if (!this.has(element)) {collection.push(element);return true;} else {return false;}};this.remove = function(element) {if(this.has(element)) {var i = collection.indexOf(element);collection.splice(i, 1);return true;}return false;};}"
],
"challengeType": 1,
2017-01-17 04:44:38 +00:00
"translations": {}
},
{
"id": "8d1923c8c441eddfaeb5bdef",
"title": "Size of the Set",
2017-01-17 04:44:38 +00:00
"description": [
"In this exercise we are going to create a size function for our Set. This function should be named <code>this.size</code> and it should return the size of the collection."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"function Set() {",
" // the var collection will hold the set",
" var collection = [];",
" // this method will check for the presence of an element and return true or false",
" this.has = function(element) {",
" return (collection.indexOf(element) !== -1);",
" };",
" // this method will return all the values in the set",
" this.values = function() {",
" return collection;",
" };",
" // this method will add an element to the set",
" this.add = function(element) {",
" if(!this.has(element)){",
" collection.push(element);",
" return true;",
" }",
" return false;",
" };",
" // this method will remove an element from a set",
" this.remove = function(element) {",
" if(this.has(element)){",
" var index = collection.indexOf(element);",
2017-01-17 04:44:38 +00:00
" collection.splice(index,1);",
" return true;",
" }",
" return false;",
" };",
" // change code below this line",
" // change code above this line",
"}"
2017-01-17 04:44:38 +00:00
],
"tests": [
"assert((function(){var test = new Set(); return (typeof test.size === 'function')}()), 'message: Your <code>Set</code> class should have a <code>size</code> method.');",
"assert((function(){var test = new Set(); test.add('a');test.add('b');test.remove('a');return (test.size() === 1)}()), 'message: The <code>size</code> method should return the number of elements in the collection.');"
2017-01-17 04:44:38 +00:00
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [
"function Set() {var collection = []; this.has = function(e){return(collection.indexOf(e) !== -1);};this.values = function() {return collection;};this.add = function(element) {if (!this.has(element)) {collection.push(element);return true;} else {return false;}};this.remove = function(element) {if(this.has(element)) {var i = collection.indexOf(element);collection.splice(i, 1);return true;}return false;};this.size = function() {return collection.length;};}"
],
"challengeType": 1,
2017-01-17 04:44:38 +00:00
"translations": {}
},
{
"id": "587d8253367417b2b2512c6c",
"title": "Perform a Union on Two Sets",
2017-01-17 04:44:38 +00:00
"description": [
"In this exercise we are going to perform a union on two sets of data. We will create a method on our <code>Set</code> data structure called <code>union</code>. This method should take another <code>Set</code> as an argument and return the <code>union</code> of the two sets, excluding any duplicate values.",
"For example, if <code>setA = ['a','b','c']</code> and <code>setB = ['a','b','d','e']</code>, then the union of setA and setB is: <code>setA.union(setB) = ['a', 'b', 'c', 'd', 'e']</code>."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"function Set() {",
" // the var collection will hold the set",
" var collection = [];",
" // this method will check for the presence of an element and return true or false",
" this.has = function(element) {",
" return (collection.indexOf(element) !== -1);",
" };",
" // this method will return all the values in the set",
" this.values = function() {",
" return collection;",
" };",
" // this method will add an element to the set",
" this.add = function(element) {",
" if(!this.has(element)){",
" collection.push(element);",
" return true;",
" }",
" return false;",
" };",
" // this method will remove an element from a set",
" this.remove = function(element) {",
" if(this.has(element)){",
" var index = collection.indexOf(element);",
2017-01-17 04:44:38 +00:00
" collection.splice(index,1);",
" return true;",
" }",
" return false;",
" };",
" // this method will return the size of the set",
" this.size = function() {",
" return collection.length;",
" };",
" // change code below this line",
"",
2017-01-17 04:44:38 +00:00
" // change code above this line",
2017-02-25 13:59:02 +00:00
"}"
2017-01-17 04:44:38 +00:00
],
"tests": [
"assert((function(){var test = new Set(); return (typeof test.union === 'function')})(), 'message: Your <code>Set</code> class should have a <code>union</code> method.');",
"assert((function(){var setA = new Set(); var setB = new Set(); setA.add('a'); setA.add('b'); setA.add('c'); setB.add('c'); setB.add('d'); var unionSetAB = setA.union(setB); var final = unionSetAB.values(); return (final.indexOf('a') !== -1 && final.indexOf('b') !== -1 && final.indexOf('c') !== -1 && final.indexOf('d') !== -1 && final.length === 4)})(), 'message: The proper collection was returned');"
2017-01-17 04:44:38 +00:00
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [
"function Set() {var collection = []; this.has = function(e){return(collection.indexOf(e) !== -1);};this.values = function() {return collection;};this.add = function(element) {if (!this.has(element)) {collection.push(element);return true;} else {return false;}};this.remove = function(element) {if(this.has(element)) {var i = collection.indexOf(element);collection.splice(i, 1);return true;}return false;};this.size = function() {return collection.length;};this.union = function(set) {var u = new Set();var c = this.values();var s = set.values();c.forEach(function(element){u.add(element);});s.forEach(function(element){u.add(element);});return u;};}"
],
"challengeType": 1,
2017-01-17 04:44:38 +00:00
"translations": {}
},
{
"id": "587d8253367417b2b2512c6d",
"title": "Perform an Intersection on Two Sets of Data",
2017-01-17 04:44:38 +00:00
"description": [
"In this exercise we are going to perform an intersection on 2 sets of data. We will create a method on our <code>Set</code> data structure called <code>intersection</code>. An intersection of sets represents all values that are common to two or more sets. This method should take another <code>Set</code> as an argument and return the <code>intersection</code> of the two sets.",
"For example, if <code>setA = ['a','b','c']</code> and <code>setB = ['a','b','d','e']</code>, then the intersection of setA and setB is: <code>setA.intersection(setB) = ['a', 'b']</code>."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"function Set() {",
" // the var collection will hold the set",
" var collection = [];",
" // this method will check for the presence of an element and return true or false",
" this.has = function(element) {",
" return (collection.indexOf(element) !== -1);",
" };",
" // this method will return all the values in the set",
" this.values = function() {",
" return collection;",
" };",
" // this method will add an element to the set",
" this.add = function(element) {",
" if(!this.has(element)){",
" collection.push(element);",
" return true;",
" }",
" return false;",
" };",
" // this method will remove an element from a set",
" this.remove = function(element) {",
" if(this.has(element)){",
" var index = collection.indexOf(element);",
2017-01-17 04:44:38 +00:00
" collection.splice(index,1);",
" return true;",
" }",
" return false;",
" };",
" // this method will return the size of the collection",
" this.size = function() {",
" return collection.length;",
" };",
" // this method will return the union of two sets",
" this.union = function(otherSet) {",
" var unionSet = new Set();",
" var firstSet = this.values();",
" var secondSet = otherSet.values();",
" firstSet.forEach(function(e){",
" unionSet.add(e);",
" });",
" secondSet.forEach(function(e){",
" unionSet.add(e);",
" });",
" return unionSet;",
" };",
" // change code below this line",
" // change code above this line",
2017-02-25 13:59:02 +00:00
"}"
2017-01-17 04:44:38 +00:00
],
"tests": [
"assert(function(){var test = new Set(); return (typeof test.intersection === 'function')}, 'message: Your <code>Set</code> class should have a <code>intersection</code> method.');",
"assert(function(){ var setA = new Set(); var setB = new Set(); setA.add('a'); setA.add('b'); setA.add('c'); setB.add('c'); setB.add('d'); var intersectionSetAB = setA.intersection(setB); return (intersectionSetAB.size() === 1 && intersectionSetAB.values()[0] === 'c')}, 'message: The proper collection was returned');"
2017-01-17 04:44:38 +00:00
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [
"function Set() {var collection = []; this.has = function(e){return(collection.indexOf(e) !== -1);};this.values = function() {return collection;};this.add = function(element) {if (!this.has(element)) {collection.push(element);return true;} else {return false;}};this.remove = function(element) {if(this.has(element)) {var i = collection.indexOf(element);collection.splice(i, 1);return true;}return false;};this.size = function() {return collection.length;};this.union = function(set) {var u = new Set();var c = this.values();var s = set.values();c.forEach(function(element){u.add(element);});s.forEach(function(element){u.add(element);});return u;};this.intersection = function(set) {var i = new Set();var c = this.values();c.forEach(function(element){if(s.has(element)) i.add(element);});};}"
],
"challengeType": 1,
2017-01-17 04:44:38 +00:00
"translations": {}
},
{
"id": "587d8254367417b2b2512c6e",
"title": "Perform a Difference on Two Sets of Data",
2017-01-17 04:44:38 +00:00
"description": [
"In this exercise we are going to perform a difference on 2 sets of data. We will create a method on our <code>Set</code> data structure called <code>difference</code>. A difference of sets should compare two sets and return the items present in the first set that are absent in the second. This method should take another <code>Set</code> as an argument and return the <code>difference</code> of the two sets.",
"For example, if <code>setA = ['a','b','c']</code> and <code>setB = ['a','b','d','e']</code>, then the difference of setA and setB is: <code>setA.difference(setB) = ['c']</code>."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"function Set() {",
" // the var collection will hold the set",
" var collection = [];",
" // this method will check for the presence of an element and return true or false",
" this.has = function(element) {",
" return (collection.indexOf(element) !== -1);",
" };",
" // this method will return all the values in the set",
" this.values = function() {",
" return collection;",
" };",
" // this method will add an element to the set",
" this.add = function(element) {",
" if(!this.has(element)){",
" collection.push(element);",
" return true;",
" }",
" return false;",
" };",
" // this method will remove an element from a set",
" this.remove = function(element) {",
" if(this.has(element)){",
" var index = collection.indexOf(element);",
2017-01-17 04:44:38 +00:00
" collection.splice(index,1);",
" return true;",
" }",
" return false;",
" };",
" // this method will return the size of the collection",
" this.size = function() {",
" return collection.length;",
" };",
" // this method will return the union of two sets",
" this.union = function(otherSet) {",
" var unionSet = new Set();",
" var firstSet = this.values();",
" var secondSet = otherSet.values();",
" firstSet.forEach(function(e){",
" unionSet.add(e);",
" });",
" secondSet.forEach(function(e){",
" unionSet.add(e);",
" });",
" return unionSet;",
" };",
" // this method will return the intersection of two sets as a new set",
" this.intersection = function(otherSet) {",
" var intersectionSet = new Set();",
" var firstSet = this.values();",
" firstSet.forEach(function(e){",
" if(otherSet.has(e)){",
" intersectionSet.add(e);",
" }",
" });",
" return intersectionSet;",
" };",
" // change code below this line",
" // change code above this line",
2017-02-25 13:59:02 +00:00
"}"
2017-01-17 04:44:38 +00:00
],
"tests": [
"assert(function(){var test = new Set(); return (typeof test.difference === 'function')}, 'message: Your <code>Set</code> class should have a <code>difference</code> method.');",
"assert(function(){var setA = new Set(); var setB = new Set(); setA.add('a'); setA.add('b'); setA.add('c'); setB.add('c'); setB.add('d'); var differenceSetAB = setA.difference(setB); return (differenceSetAB.size() === 2) && (differenceSetAB.values() === [ 'a', 'b' ])}, 'message: The proper collection was returned');"
2017-01-17 04:44:38 +00:00
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [
"function Set() {var collection = []; this.has = function(e){return(collection.indexOf(e) !== -1);};this.values = function() {return collection;};this.add = function(element) {if (!this.has(element)) {collection.push(element);return true;} else {return false;}};this.remove = function(element) {if(this.has(element)) {var i = collection.indexOf(element);collection.splice(i, 1);return true;}return false;};this.size = function() {return collection.length;};this.union = function(set) {var u = new Set();var c = this.values();var s = set.values();c.forEach(function(element){u.add(element);});s.forEach(function(element){u.add(element);});return u;};this.intersection = function(set) {var i = new Set();var c = this.values();c.forEach(function(element){if(s.has(element)) i.add(element);});};this.difference = function(set) {var d = new Set();var c = this.values();c.forEach(function(e){if(!set.has(e)) d.add(e);});};}"
],
"challengeType": 1,
2017-01-17 04:44:38 +00:00
"translations": {}
},
{
"id": "587d8254367417b2b2512c6f",
"title": "Perform a Subset Check on Two Sets of Data",
2017-01-17 04:44:38 +00:00
"description": [
"In this exercise we are going to perform a subset test on 2 sets of data. We will create a method on our <code>Set</code> data structure called <code>subset</code>. This will compare the first set, against the second and if the first set is fully contained within the Second then it will return true.",
"For example, if <code>setA = ['a','b']</code> and <code>setB = ['a','b','c','d']</code>, then the subset of setA and setB is: <code>setA.subset(setB)</code> should be <code>true</code>."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"function Set() {",
" // the var collection will hold the set",
" var collection = [];",
" // this method will check for the presence of an element and return true or false",
" this.has = function(element) {",
" return (collection.indexOf(element) !== -1);",
" };",
" // this method will return all the values in the set",
" this.values = function() {",
" return collection;",
" };",
" // this method will add an element to the set",
" this.add = function(element) {",
" if(!this.has(element)){",
" collection.push(element);",
" return true;",
" }",
" return false;",
" };",
" // this method will remove an element from a set",
" this.remove = function(element) {",
" if(this.has(element)){",
" var index = collection.indexOf(element);",
2017-01-17 04:44:38 +00:00
" collection.splice(index,1);",
" return true;",
" }",
" return false;",
" };",
" // this method will return the size of the collection",
" this.size = function() {",
" return collection.length;",
" };",
" // this method will return the union of two sets",
" this.union = function(otherSet) {",
" var unionSet = new Set();",
" var firstSet = this.values();",
" var secondSet = otherSet.values();",
" firstSet.forEach(function(e){",
" unionSet.add(e);",
" });",
" secondSet.forEach(function(e){",
" unionSet.add(e);",
" });",
" return unionSet;",
" };",
" // this method will return the intersection of two sets as a new set",
" this.intersection = function(otherSet) {",
" var intersectionSet = new Set();",
" var firstSet = this.values();",
" firstSet.forEach(function(e){",
" if(otherSet.has(e)){",
" intersectionSet.add(e);",
" }",
" });",
" return intersectionSet;",
" };",
" // this method will return the difference of two sets as a new set",
" this.difference = function(otherSet) {",
" var differenceSet = new Set();",
" var firstSet = this.values();",
" firstSet.forEach(function(e){",
" if(!otherSet.has(e)){",
" differenceSet.add(e);",
" }",
" });",
" return differenceSet;",
" };",
" // change code below this line",
" // change code above this line",
2017-02-25 13:59:02 +00:00
"}"
],
"tests": [
"assert(function(){var test = new Set(); return (typeof test.subset === 'function')}, 'message: Your <code>Set</code> class should have a <code>union</code> method.');",
"assert(function(){var setA = new Set(); var setB = new Set(); setA.add('a'); setB.add('b'); setB.add('c'); setB.add('a'); setB.add('d'); var subsetSetAB = setA.subset(setB);return (subsetSetAB === true)}, 'message: The first Set() was contained in the second Set');",
"assert(function(){var setA = new Set(); var setB = new Set(); setA.add('a'); setA.add('b'); setB.add('a'); setB.add('b'); setB.add('c'); setB.add('d'); var subsetSetAB = setA.subset(setB); return (subsetSetAB === true)}, \"message: <code>['a', 'b'].subset(['a', 'b', 'c', 'd'])</code> should return <code>true</code>\");",
"assert(function(){var setA = new Set(); var setB = new Set(); setA.add('a'); setA.add('b'); setA.add('c'); setB.add('a'); setB.add('b'); var subsetSetAB = setA.subset(setB); return (subsetSetAB === false)}, \"message: <code>['a', 'b', 'c'].subset(['a', 'b'])</code> should return <code>false</code>\");",
"assert(function(){var setA = new Set(); var setB = new Set(); var subsetSetAB = setA.subset(setB); return (subsetSetAB === true)}, 'message: <code>[].subset([])</code> should return <code>true</code>');",
"assert(function(){var setA = new Set(); var setB = new Set(); setA.add('a'); setA.add('b'); setB.add('c'); setB.add('d'); var subsetSetAB = setA.subset(setB); return (subsetSetAB === false)}, \"message: <code>['a', 'b'].subset(['c', 'd'])</code> should return <code>false</code>\");"
2017-01-17 04:44:38 +00:00
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [
"function Set() {var collection = []; this.has = function(e){return(collection.indexOf(e) !== -1);};this.values = function() {return collection;};this.add = function(element) {if (!this.has(element)) {collection.push(element);return true;} else {return false;}};this.remove = function(element) {if(this.has(element)) {var i = collection.indexOf(element);collection.splice(i, 1);return true;}return false;};this.size = function() {return collection.length;};this.union = function(set) {var u = new Set();var c = this.values();var s = set.values();c.forEach(function(element){u.add(element);});s.forEach(function(element){u.add(element);});return u;};this.intersection = function(set) {var i = new Set();var c = this.values();c.forEach(function(element){if(s.has(element)) i.add(element);});};this.difference = function(set) {var d = new Set();var c = this.values();c.forEach(function(e){if(!set.has(e)) d.add(e);});};this.subset = function(set) {var isSubset = true;var c = this.values();c.forEach(function(e){if(!set.has(e)) isSubset = false;});return isSubset;};}"
],
"challengeType": 1,
2017-01-17 04:44:38 +00:00
"translations": {}
},
{
"id": "587d8254367417b2b2512c70",
2017-02-23 17:42:29 +00:00
"title": "Create and Add to Sets in ES6",
2017-01-17 04:44:38 +00:00
"description": [
"Now that you have worked through ES5, you are going to perform something similar in ES6. This will be considerably easier. ES6 contains a built-in data structure <code>Set</code> so many of the operations you wrote by hand are now included for you. Let's take a look:",
2017-01-17 04:44:38 +00:00
"To create a new empty set:",
"<code>var set = new Set();</code>",
2017-01-17 04:44:38 +00:00
"You can create a set with a value:",
"<code>var set = new Set(1);</code>",
2017-01-17 04:44:38 +00:00
"You can create a set with an array:",
"<code>var set = new Set([1, 2, 3]);</code>",
"Once you have created a set, you can add the values you wish using the <code>add</code> method:",
"<blockquote>var set = new Set([1, 2, 3]);<br>set.add([4, 5, 6]);</blockquote>",
"As a reminder, a set is a data structure that cannot contain duplicate values:",
"<blockquote>var set = new Set([1, 2, 3, 1, 2, 3]);<br>// set contains [1, 2, 3] only</blockquote>",
"<hr>",
"For this exercise, return a set with the following values: <code>1, 2, 3, 'Taco', 'Cat', 'Awesome'</code>"
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"function checkSet() {",
" var set = new Set([1, 2, 3, 3, 2, 1, 2, 3, 1]);",
" // change code below this line",
" ",
" // change code above this line",
" console.log(set);",
" return set;",
"}",
"",
2017-01-17 04:44:38 +00:00
"checkSet();"
],
"tests": [
"assert(function(){var test = checkSet(); return (test.size == 6) && test.has(1) && test.has(2) && test.has(3) && test.has('Taco') && test.has('Cat') && test.has('Awesome');}, 'message: Your <code>Set</code> should only contains the values <code>1, 2, 3, Taco, Cat, Awesome</code>.');"
2017-01-17 04:44:38 +00:00
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [
"function checkSet(){var set = new Set([1,2,3,'Taco','Cat','Awesome']);\nreturn set;}"
],
"challengeType": 1,
2017-01-17 04:44:38 +00:00
"translations": {}
},
{
"id": "587d8254367417b2b2512c71",
2017-02-23 17:42:29 +00:00
"title": "Remove items from a set in ES6",
2017-01-17 04:44:38 +00:00
"description": [
"Let's practice removimg items from an ES6 Set using the <code>delete</code> method.",
"First, create an ES6 Set",
"<code>var set = new Set([1,2,3]);</code>",
"Now remove an item from your Set with the <code>delete</code> method.",
"<blockquote>set.delete(1);<br>console.log([...set]) // should return [ 2, 3 ]<blockquote>",
"<hr>",
"Now, create a set with the integers 1, 2, 3, 4, & 5. \n Remove the values 2 and 5, and then return the set."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"function checkSet(){",
" var set = //Create a set with values 1, 2, 3, 4, & 5",
" //Remove the value 2",
" //Remove the value 5",
" //Return the set",
" return set;",
"}"
2017-01-17 04:44:38 +00:00
],
"tests": [
"assert(function(){var test = checkSet(); return test.has(1) && test.has(3) && test.has(4) && test.size === 3}, 'message: Your Set should contain the values 1, 3, & 4');"
2017-01-17 04:44:38 +00:00
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [
"function checkSet(){\nvar set = new Set([1,2,3,4,5]);\nset.delete(2);\nset.delete(5);\nreturn set;}"
],
"challengeType": 1,
2017-01-17 04:44:38 +00:00
"translations": {}
},
{
"id": "587d8255367417b2b2512c72",
2017-02-23 17:42:29 +00:00
"title": "Use .has and .size on an ES6 Set",
2017-01-17 04:44:38 +00:00
"description": [
"Let's look at the .has and .size methods available on the ES6 Set object.",
"First, create an ES6 Set",
"<code>var set = new Set([1,2,3]);</code>",
"The .has method will check if the value is contained within the set.",
"<code>var hasTwo = set.has(2);</code>",
"The .size method will return an integer representing the size of the Set",
"<code>var howBig = set.size;</code>",
"<hr>",
"In this exercise we will pass an array and a value to the checkSet() function. Your function should create an ES6 set from the array argument. Find if the set contains the value argument. Find the size of the set. And return those two values in an array."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"function checkSet(arrToBeSet, checkValue){",
"",
2017-01-17 04:44:38 +00:00
" // change code below this line",
"",
2017-01-17 04:44:38 +00:00
" // change code above this line",
"",
"}",
"",
"checkSet([ 1, 2, 3], 2); // Should return [ true, 3 ]"
2017-01-17 04:44:38 +00:00
],
"tests": [
"assert(function(){var test = checkSet([4,5,6], 3); test === [ false, 3 ]}, 'message: <code>checkSet([4, 5, 6], 3)</code> should return [ false, 3 ]');"
2017-01-17 04:44:38 +00:00
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [
"function checkSet(arrToBeSet, checkValue){\nvar set = new Set(arrToBeSet);\nvar result = [\nset.has(checkValue),\nset.size\n];\nreturn result;\n}"
],
"challengeType": 1,
2017-01-17 04:44:38 +00:00
"translations": {}
},
{
"id": "587d8255367417b2b2512c73",
2017-02-23 17:42:29 +00:00
"title": "Use Spread and Notes for ES5 Set() Integration",
2017-01-17 04:44:38 +00:00
"description": [
"Do you remember the ES6 spread operator <code>...</code>?",
"<code>...</code> can take iterable objects in ES6 and turn them into arrays.",
2017-01-17 04:44:38 +00:00
"Let's create a Set, and check out the spread function.",
"<blockquote>var set = new Set([1,2,3]);<br>var setToArr = [...set]<br>console.log(setToArr) // returns [ 1, 2, 3 ]</blockquote>",
"<hr>",
"In this exercise we will pass a set object to the <code>checkSet</code> function. It should return an array containing the values of the Set.",
"Now you've successfully learned how to use the ES6 <code>Set()</code> object, good job!"
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"function checkSet(set){",
" // change code below this line",
"",
2017-01-17 04:44:38 +00:00
" // change code above this line",
2017-02-25 13:59:02 +00:00
"}"
],
"tests": [
"assert(function(){var test = checkSet(new Set([1,2,3,4,5,6,7])); test === [ 1, 2, 3, 4, 5, 6, 7 ]}, 'message: Your Set was returned correctly!');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [
"function checkSet(set){\nreturn [...set];}"
],
"challengeType": 1,
"translations": {}
},
{
"id": "8d5823c8c441eddfaeb5bdef",
"title": "Create a Map Data Structure",
"description": [
"The next few challenges will cover maps and hash tables. Maps are data structurs that store key-value pairs. In JavaScript, these are available to us as objects. Maps provide rapid lookup of stored items based on key values and are very common and useful data structures.",
"Instructions: Let's get some practice creating our own map. Because JavaScript objects provide a much more efficient map structure than anything we could write here, this is intended primarily as a learning exercise. However, JavaScript objects only provide us with certain operations. What if we wanted to define custom operations?",
"Use the <code>Map</code> object provided here as a wrapper around a JavaScript <code>object</code>. Create the following methods and operations on the Map object:",
"<code>add</code> accepts a <code>key, value</code> pair to add to the map",
"<code>remove</code> accepts a key and removes the associated <code>key, value</code> pair",
"<code>get</code> accepts a <code>key</code> and returns the stored <code>value</code>",
"<code>has</code> returns a <code>boolean</code> for the presence or absence of an item",
"<code>values</code> returns an array of all the values in the map",
"<code>size</code> returns the number of items in the map",
"<code>clear</code> empties the map"
],
"challengeSeed": [
"var Map = function() {",
" this.collection = {};",
" // change code below this line",
" // change code above this line",
"};"
],
"tests": [
"assert((function() { var test = false; if (typeof Map !== 'undefined') { test = new Map() }; return (typeof test == 'object')})(), 'message: The Map data structure exists.');",
"assert((function() { var test = false; if (typeof Map !== 'undefined') { test = new Map() }; return (typeof test.add == 'function' && typeof test.remove == 'function' && typeof test.get == 'function' && typeof test.has == 'function' && typeof test.values == 'function' && typeof test.clear == 'function' && typeof test.size == 'function')})(), 'message: The Map object has the following methods: add, remove, get, has, values, clear, and size.');",
"assert((function() { var test = false; if (typeof Map !== 'undefined') { test = new Map() }; test.add(5,6); test.add(2,3); test.add(2,5); return (test.size() == 3)})(), 'message: The add method adds items to the map.');",
"assert((function() { var test = false; if (typeof Map !== 'undefined') { test = new Map() }; test.add('test','value'); return (test.has('test') && !test.has('false'))})(), 'message: The has method returns true for added items and false for absent items.');",
"assert((function() { var test = false; if (typeof Map !== 'undefined') { test = new Map() }; test.add('abc','def'); return (test.get('abc') == 'def')})(), 'message: The get method accepts keys as input and returns the associated values.');",
"assert((function() { var test = false; if (typeof Map !== 'undefined') { test = new Map() }; test.add('a','b'); test.add('c','d'); test.add('e','f'); var vals = test.values(); return (vals.indexOf('b') != -1 && vals.indexOf('d') != -1 && vals.indexOf('f') != -1)})(), 'message: The values method returns all the values stored in the map as strings in an array.');",
"assert((function() { var test = false; if (typeof Map !== 'undefined') { test = new Map() }; test.add('b','b'); test.add('c','d'); test.remove('asdfas'); var init = test.size(); test.clear(); return (init == 2 && test.size() == 0)})(), 'message: The clear method empties the map and the size method returns the number of items present in the map.');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [],
"challengeType": 1,
"translations": {}
},
{
"id": "587d825b367417b2b2512c8d",
"title": "Create an ES6 JavaScript Map",
"description": [
"The new version of JavaScript provides us with a built-in Map object which provides much of the functionality we wrote by hand in the last challenge. This Map object, although similar to regular JavaScript objects, provides some useful functionality that normal objects lack. For example, an ES6 Map tracks the insertion order of items that are added to it. Here is a more complete overview of its methods:",
"<code>.has(key)</code> returns true or false based on the presence of a key",
"<code>.get(key)</code> returns the value associated with a key",
"<code>.set(key, value)</code> sets a new key, value pair",
"<code>.delete(key)</code> removes a key, value pair",
"<code>.clear()</code> removes all key, value pairs",
"<code>.entries()</code> returns an array of all the keys in insertion order",
"<code>.values()</code> returns an array of all the values in insertion order",
"Instructions: Define a JavaScript Map object and assign to it a variable called myMap. Add the key, value pair <code>freeCodeCamp</code>, <code>Awesome!</code> to it."
],
"challengeSeed": [
"// change code below this line"
],
"tests": [
"assert(typeof myMap === 'object', 'message: The myMap object exists.');",
"assert(myMap.get('freeCodeCamp') === 'Awesome!', 'message: myMap contains the key value pair <code>freeCodeCamp</code>, <code>Awesome!</code>.');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [],
"challengeType": 1,
"translations": {}
},
{
"id": "587d825b367417b2b2512c8e",
"title": "Create a Hash Table",
"description": [
"In this challenge we will learn about hash tables. A Hash table is used to implement associative arrays, or mappings of key-value pairs, like the objects and Maps we have just been studying. A JavaScript object could be implemented as a hash table, for instance (its actual implementation will depend on the environment it's running in). The way a hash table works is that it takes a key input and hashes this key in a deterministic way to some numerical value. This numerical value is then used as the actual key the associated value is stored by. Then, if you try to access the same key again, the hashing function will process the key, return the same numerical result, which will then be used to look up the associated value. This provides very efficient O(n) lookup time on average.",
"Hash tables can be implemented as arrays with hash functions producing array indices within a specified range. In this method, the choice of the array size is important, as is the hashing function. For instance, what if the hashing function produces the same value for two different keys? This is called a collision. One way to handle collisions is to just store both key-value pairs at that index. Then, upon lookup of either, you would have to iterate through the bucket of items to find the key you are looking for. A good hashing function will minimize collisions to maintain efficient search time.",
"Here, we won't be concerned with the details of hashing or hash table implementation, we will just try to get a general sense of how they work.",
"Instructions: Let's create the basic functionality of a hash table. We've created a naive hashing function for you to use. You can pass a string value to the function hash and it will return a hashed value you can use as a key for storage. Store items based on this hashed value in the this.collection object. Create these three methods: add, remove, and lookup. The first should accept a key value pair to add to the hash table. The second should remove a key-value pair when passed a key. The third should accept a key and return the associated value or null if the key is not present.",
"Be sure to write your code to account for collisions!"
],
"head": [
" var called = 0;",
" var hash = (string) => {",
" called++;",
" var hash = 0;",
" for (var i = 0; i < string.length; i++) { hash += string.charCodeAt(i); };",
" return hash;",
" };"
],
"challengeSeed": [
"var called = 0;",
"var hash = (string) => {",
" called++;",
" var hash = 0;",
2017-02-25 13:59:02 +00:00
" for (var i = 0; i < string.length; i++) { hash += string.charCodeAt(i); }",
" return hash;",
"};",
"var HashTable = function() {",
" this.collection = {};",
" // change code below this line",
" // change code above this line",
"};"
],
"tests": [
"assert((function() { var test = false; if (typeof HashTable !== 'undefined') { test = new HashTable() }; return (typeof test === 'object')})(), 'message: The HashTable data structure exists.');",
"assert((function() { var test = false; if (typeof HashTable !== 'undefined') { test = new HashTable() }; return ((typeof test.add) === 'function')})(), 'message: The HashTable has an add method.');",
"assert((function() { var test = false; if (typeof HashTable !== 'undefined') { test = new HashTable() }; return ((typeof test.remove) === 'function')})(), 'message: The HashTable has an remove method.');",
"assert((function() { var test = false; if (typeof HashTable !== 'undefined') { test = new HashTable() }; return ((typeof test.lookup) === 'function')})(), 'message: The HashTable has an lookup method.');",
"assert((function() { var test = false; if (typeof HashTable !== 'undefined') { test = new HashTable() }; test.add('key', 'value'); return (test.lookup('key') === 'value')})(), 'message: The add method adds key value pairs and the lookup method returns the values associated with a given key.');",
"assert((function() { var test = false; if (typeof HashTable !== 'undefined') { test = new HashTable() }; test.add('key', 'value'); test.remove('key'); return (test.lookup('key') === null)})(), 'message: The remove method accepts a key as input and removes the associated key value pair.');",
"assert((function() { var test = false; if (typeof HashTable !== 'undefined') { test = new HashTable() }; called = 0; test.add('key1','value1'); test.add('key2','value2'); test.add('key3','value3'); return (called === 3)})(), 'message: Items are added using the hash function.');",
"assert((function() { var test = false; if (typeof HashTable !== 'undefined') { test = new HashTable() }; called = 0; test.add('key1','value1'); test.add('1key','value2'); test.add('ke1y','value3'); return (test.lookup('key1') === 'value1' && test.lookup('1key') == 'value2' && test.lookup('ke1y') == 'value3')})(), 'message: The hash table handles collisions.');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [],
"challengeType": 1,
"translations": {}
},
{
"id": "587d8251367417b2b2512c61",
"title": "Work with Nodes in a Linked List",
"description": [
"Another common data structure you'll run into in computer science is the <dfn>linked list</dfn>. A linked list is a linear collection of data elements, called 'nodes', each of which points to the next. Each <dfn>node</dfn> in a linked list contains two key pieces of information: the <code>element</code> itself, and a reference to the next <code>node</code>.",
"Imagine that you are in a conga line. You have your hands on the next person in the line, and the person behind you has their hands on you. You can see the person straight ahead of you, but they are blocking the view of the other people ahead in line. A node is just like a person in a conga line: they know who they are and they can only see the next person in line, but they are not aware of the other people ahead or behind them.",
"<hr>",
"In our code editor, we've created two nodes, <code>Kitten</code> and <code>Puppy</code>, and we've manually connected the <code>Kitten</code> node to the <code>Puppy</code> node.",
"Create a <code>Cat</code> and <code>Dog</code> node and manually add them to the line."
],
"challengeSeed": [
"var Node = function(element){",
" this.element = element; ",
" this.next = null; ",
2017-01-17 04:44:38 +00:00
"};",
"var Kitten = new Node(\"Kitten\");",
"var Puppy = new Node(\"Puppy\");",
"",
"Kitten.next = Puppy;",
"// only add code below this line",
"",
"// test your code",
"console.log(Kitten.next);"
],
"tests": [
"assert(Puppy.next.element === \"Cat\", 'message: Your <code>Puppy</code> node should have a reference to a <code>Cat</code> node.');",
"assert(Cat.next.element === \"Dog\", 'message: Your <code>Cat</code> node should have a reference to a <code>Dog</code> node.');"
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
},
{
"id": "587d8251367417b2b2512c62",
"title": "Create a Linked List Class",
"description": [
"Let's create a <code>linked list</code> class. Every linked list should start out with a few basic properties: a <code>head</code> (the first item in your list) and a <code>length</code> (number of items in your list). Sometimes you'll see implementations of linked lists that incorporate a <code>tail</code> for the last element of the list, but for now we'll just stick with these two. Whenever we add an element to the linked list, our <code>length</code> property should be incremented by one.",
"We'll want to have a way to add items to our linked list, so the first method we'll want to create is the <code>add</code> method.",
"If our list is empty, adding an element to our linked list is straightforward enough: we just wrap that element in a <code>Node</code> class, and we assign that node to the <code>head</code> of our linked list." ,
"But what if our list already has one or more members? How do we add an element to the list? Recall that each node in a linked list has a <code>next</code> property. To add a node to the list, find the last node in the list, and point that last node's <code>next</code> property at our new node. (Hint: you know you've reached the end of a linked list when a node's <code>next</code> property is <code>null</code>.)",
"<hr>",
"Write an add method that assigns the first node you push to the linked list to the <code>head</code>; after that, whenever adding a node, every node should be referenced by the previous node's <code>next</code> property.",
"Note",
"Your list's <code>length</code> should increase by one every time an element is added to the linked list."
],
"challengeSeed": [
"function LinkedList() { ",
" var length = 0; ",
" var head = null; ",
"",
" var Node = function(element){",
" this.element = element; ",
" this.next = null; ",
" }; ",
"",
" this.head = function(){",
" return head;",
" };",
"",
" this.size = function(){",
" return length;",
" };",
"",
" this.add = function(element){",
" // Only change code below this line",
"",
" // Only change code above this line",
" };",
2017-02-25 13:59:02 +00:00
"}"
2017-01-17 04:44:38 +00:00
],
"tests": [
"assert((function(){var test = new LinkedList(); return (typeof test.add === 'function')}()), 'message: Your <code>LinkedList</code> class should have a <code>add</code> method.');",
"assert((function(){var test = new LinkedList(); test.add('cat'); return test.head().element === 'cat'}()), 'message: Your <code>LinkedList</code> class should assign <code>head</code> to the first node added.');",
"assert((function(){var test = new LinkedList(); test.add('cat'); test.add('dog'); return test.head().next.element === 'dog'}()), 'message: The previous <code>node</code> in your <code>LinkedList</code> class should have reference to the newest node created.');",
"assert((function(){var test = new LinkedList(); test.add('cat'); test.add('dog'); return test.size() === 2}()), 'message: The <code>size</code> of your <code>LinkedList</code> class should equal the amount of nodes in the linked list.');"
2017-01-17 04:44:38 +00:00
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
2017-01-17 04:44:38 +00:00
},
{
"id": "587d8251367417b2b2512c63",
"title": "Remove Elements from a Linked List",
2017-01-17 04:44:38 +00:00
"description": [
"The next important method that any implementation of a linked list will need is a <code>remove</code> method. This method should take the element we want to remove as an argument, and then search the list to find and remove the node that contains that element.",
"Whenever we remove a node from a linked list, it's important that we don't accidentally orphan the rest of the list in doing so. Recall that every node's <code>next</code> property points to the node that follows it in the list. If we're removing the middle element, say, we'll want to make sure that we have a connection from that element's previous node's <code>next</code> property to the middle element's <code>next</code> property (which is the next node in the list!)",
"This might sound really confusing, so let's return to the conga line example so we have a good conceptual model. Picture yourself in a conga line, and the person directly in front of you leaves the line. The person who just left the line no longer has her hands on anyone in line--and you no longer have your hands on the person that left. You step forward and put your hands on next person you see.",
"If the element we wish to remove is the <code>head</code> element, we reassign the <code>head</code> to the second node of the linked list.",
"<hr>",
"Write a <code>remove</code> method that takes an element and removes it from the linked list.",
"Note",
"The <code>length</code> of the list should decrease by one every time an element is removed from the linked list."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"function LinkedList() { ",
" var length = 0; ",
" var head = null; ",
"",
" var Node = function(element){ ",
" this.element = element; ",
" this.next = null; ",
" }; ",
"",
" this.size = function(){",
" return length;",
" };",
"",
" this.head = function(){",
" return head;",
" };",
"",
" this.add = function(element){",
" var node = new Node(element);",
" if(head === null){",
" head = node;",
" } else {",
" currentNode = head;",
"",
" while(currentNode.next){",
" currentNode = currentNode.next;",
" }",
"",
" currentNode.next = node;",
" }",
"",
" length++;",
" }; ",
"",
" this.remove = function(element){",
2017-01-17 04:44:38 +00:00
" // Only change code below this line",
"",
2017-01-17 04:44:38 +00:00
" // Only change code above this line",
" };",
2017-02-25 13:59:02 +00:00
"}"
2017-01-17 04:44:38 +00:00
],
"tests": [
"assert((function(){var test = new LinkedList(); return (typeof test.remove === 'function')}()), 'message: Your <code>LinkedList</code> class should have a <code>remove</code> method.');",
"assert((function(){var test = new LinkedList(); test.add('cat'); test.add('dog'); test.remove('cat'); return test.head().element === 'dog'}()), 'message: Your <code>remove</code> method should reassign <code>head</code> to the second node when the first node is removed.');",
"assert((function(){var test = new LinkedList(); test.add('cat'); test.add('dog'); test.remove('cat'); return test.size() === 1})(), 'message: Your <code>remove</code> method should decrease the <code>length</code> of the linked list by one for every node removed.');",
"assert((function(){var test = new LinkedList(); test.add('cat'); test.add('dog');test.add('kitten'); test.remove('dog'); return test.head().next.element === 'kitten'})(), 'message: Your <code>remove</code> method should reassign the reference of the previous node of the removed node to the removed node&apos;s <code>next</code> reference.');"
],
"solutions": [
"class Node {\n constructor (element) {\n this.element = element;\n this.next = null;\n }\n}\n\nclass LinkedList {\n constructor () {\n this._length = 0;\n this._head = null;\n }\n\n head () {\n return this._head;\n }\n\n size () {\n return this._length;\n }\n\n add (element) {\n const node = new Node(element);\n\n if (this._head === null) {\n this._head = node;\n } else {\n let current = this._head;\n\n while (current.next !== null) {\n current = current.next;\n }\n\n current.next = node; \n }\n \n ++this._length;\n }\n \n remove (element) {\n if (this._head === null) return;\n \n let previous;\n let current = this._head;\n \n while (current.next !== null && current.element !== element) {\n previous = current;\n current = current.next;\n }\n \n if (previous) {\n previous.next = current.next;\n } else {\n this._head = current.next;\n }\n \n --this._length;\n }\n}"
2017-01-17 04:44:38 +00:00
],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
2017-01-17 04:44:38 +00:00
},
{
"id": "587d8251367417b2b2512c64",
"title": "Search within a Linked List",
2017-01-17 04:44:38 +00:00
"description": [
"Let's add a few more useful methods to our linked list class. Wouldn't it be useful if we could tell if our list was empty or not, as with our <code>Stack</code> and <code>Queue</code> classes?",
"We should also be able to find specific elements in our linked list. Traversing through data structures is something you'll want to get a lot of practice with! Let's create an <code>indexOf</code> method that takes an <code>element</code> as an argument, and returns that element's <code>index</code> in the linked list. If the element is not found in the linked list, return <code>-1</code>.",
"Let's also implement a method that does the opposite: an <code>elementAt</code> method that takes an <code>index</code> as an argument and returns the <code>element</code> at the given <code>index</code>. If no <code>element</code> is found, return <code>undefined</code>.",
"<hr>",
"Write an <code>isEmpty</code> method that checks if the linked list is empty, an <code>indexOf</code> method that returns the <code>index</code> of a given element, and an <code>elementAt</code> that returns an <code>element</code> at a given <code>index."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"function LinkedList() { ",
" var length = 0; ",
" var head = null; ",
"",
" var Node = function(element){ // {1} ",
" this.element = element; ",
" this.next = null; ",
" }; ",
"",
" this.size = function() {",
" return length;",
" };",
"",
" this.head = function(){",
" return head;",
" };",
"",
" this.add = function(element){",
" var node = new Node(element);",
" if(head === null){",
" head = node;",
" } else {",
" currentNode = head;",
"",
" while(currentNode.next){",
" currentNode = currentNode.next;",
" }",
"",
" currentNode.next = node;",
" }",
"",
" length++;",
" }; ",
"",
" this.remove = function(element){",
" var currentNode = head;",
" var previousNode;",
" if(currentNode.element === element){",
" head = currentNode.next;",
" } else {",
" while(currentNode.element !== element) {",
" previousNode = currentNode;",
" currentNode = currentNode.next;",
" }",
"",
" previousNode.next = currentNode.next;",
" }",
"",
" length --;",
" };",
"",
" // Only change code below this line",
"",
" // Only change code above this line",
2017-02-25 13:59:02 +00:00
"}"
2017-01-17 04:44:38 +00:00
],
"tests": [
"assert((function(){var test = new LinkedList(); return (typeof test.indexOf === 'function')}()), 'message: Your <code>LinkedList</code> class should have a <code>indexOf</code> method.');",
"assert((function(){var test = new LinkedList(); return (typeof test.elementAt === 'function')}()), 'message: Your <code>LinkedList</code> class should have a <code>elementAt</code> method.');",
"assert((function(){var test = new LinkedList(); test.add('cat'); test.add('dog'); test.add('kitten'); return test.size() === 3}()), 'message: Your <code>size</code> method should return the length of the linked list');",
"assert((function(){var test = new LinkedList(); test.add('cat'); test.add('dog'); test.add('kitten'); return test.indexOf('kitten') === 2}()), 'message: Your <code>indexOf</code> method should return the index of the given element.');",
"assert((function(){var test = new LinkedList(); test.add('cat'); test.add('dog'); test.add('kitten'); return test.elementAt(1) === 'dog'}()), 'message: Your <code>elementAt</code> method should return at element at a given index.');"
2017-01-17 04:44:38 +00:00
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
2017-01-17 04:44:38 +00:00
},
{
"id": "587d8251367417b2b2512c65",
"title": "Remove Elements from a Linked List by Index",
2017-01-17 04:44:38 +00:00
"description": [
"Before we move on to another data structure, let's get a couple of last bits of practice with linked lists.",
"Let's write a <code>removeAt</code> method that removes the <code>element</code> at a given <code>index</code>. The method should be called <code>removeAt(index)</code>. To remove an <code>element</code> at a certain <code>index</code>, we'll need to keep a running count of each node as we move along the linked list.",
"A common technique used to iterate through the elements of a linked list involves a <dfn>'runner'</dfn>, or sentinel, that 'points' at the nodes that your code is comparing. In our case, starting at the <code>head</code> of our list, we start with a <code>currentIndex</code> variable that starts at <code>0</code>. The <code>currentIndex</code> should increment by one for each node we pass.",
"Just like our <code>remove(element)</code> method, we need to be careful not to orphan the rest of our list when we remove the node in our removeAt(index) method. We keep our nodes contiguous by making sure that the node that has reference to the removed node has a reference to the next node.",
"<hr>",
"Write a <code>removeAt(index)</code> method that removes and returns a node at a given <code>index</code>. The method should return <code>null</code> if the given <code>index</code> is either negative, or greater than or equal to the <code>length</code> of the linked list.",
"Note",
"Remember to keep count of the <code>currentIndex</code>."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"function LinkedList() { ",
" var length = 0; ",
" var head = null; ",
"",
" var Node = function(element){ // {1} ",
" this.element = element; ",
" this.next = null; ",
" }; ",
"",
" this.size = function(){",
" return length;",
" };",
"",
" this.head = function(){",
" return head;",
" };",
"",
" this.add = function(element){",
" var node = new Node(element);",
" if(head === null){",
" head = node;",
" } else {",
" currentNode = head;",
"",
" while(currentNode.next){",
" currentNode = currentNode.next;",
" }",
"",
" currentNode.next = node;",
" }",
"",
" length++;",
" }; ",
"",
" this.remove = function(element){",
" var currentNode = head;",
" var previousNode;",
" if(currentNode.element === element){",
" head = currentNode.next;",
" } else {",
" while(currentNode.element !== element) {",
" previousNode = currentNode;",
" currentNode = currentNode.next;",
" }",
"",
" previousNode.next = currentNode.next;",
" }",
"",
" length --;",
" };",
"",
" // Only change code below this line",
"",
" // Only change code above this line",
2017-02-25 13:59:02 +00:00
"}"
2017-01-17 04:44:38 +00:00
],
"tests": [
"assert((function(){var test = new LinkedList(); return (typeof test.removeAt === 'function')}()), 'message: Your <code>LinkedList</code> class should have a <code>removeAt</code> method.');",
"assert((function(){var test = new LinkedList(); test.add('cat'); test.add('dog'); test.add('kitten'); test.removeAt(1); return test.size() === 2}()), 'message: Your <code>removeAt</code> method should reduce the <code>length</code> of the linked list');",
"assert((function(){var test = new LinkedList(); test.add('cat'); test.add('dog'); test.add('kitten'); return test.removeAt(1) === 'dog'}()), 'message: Your <code>removeAt</code> method should also return the element of the removed node.');",
"assert((function(){var test = new LinkedList(); test.add('cat'); test.add('dog'); test.add('kitten'); return (test.removeAt(-1) === null)}()), 'message: Your <code>removeAt</code> method should also return <code>null</code> if the given index is less than <code>0</code>');",
"assert((function(){var test = new LinkedList(); test.add('cat'); test.add('dog'); test.add('kitten'); return (test.removeAt(3) === null)}()), 'message: Your <code>removeAt</code> method should also return <code>null</code> if the given index is equal or more than the <code>length</code> of the linked list.');"
2017-01-17 04:44:38 +00:00
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
2017-01-17 04:44:38 +00:00
},
{
"id": "587d8252367417b2b2512c67",
"title": "Add Elements at a Specific Index in a Linked List",
2017-01-17 04:44:38 +00:00
"description": [
"Let's create a addAt(index,element) method that adds an element at a given index.",
"Just like how we remove elements at a given index, we need to keep track of the currentIndex as we traverse the linked list. When the currentIndex matches the given index, we would need to reassign the previous node's next property to reference the new added node. And the new node should reference the next node in the currentIndex.",
"Returning to the conga line example, a new person wants to join the line, but he wants to join in the middle. You are in the middle of the line, so you take your hands off of the person ahead of you. The new person walks over and puts his hands on the person you once had hands on, and you now have your hands on the new person.",
2017-01-17 04:44:38 +00:00
"Instructions",
"Create an addAt(index,element) method that adds an element at a given index. Return false if an element was unable to be added.",
"Note",
"Remember to check if the given index is a negative or is longer than the length of the linked list."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"function LinkedList() { ",
" var length = 0; ",
" var head = null; ",
"",
" var Node = function(element){",
" this.element = element; ",
" this.next = null; ",
" }; ",
"",
" this.size = function(){",
" return length;",
" };",
"",
" this.head = function(){",
" return head;",
" };",
"",
" this.add = function(element){",
" var node = new Node(element);",
" if(head === null){",
" head = node;",
" } else {",
" currentNode = head;",
"",
" while(currentNode.next){",
" currentNode = currentNode.next;",
" }",
"",
" currentNode.next = node;",
" }",
"",
" length++;",
" }; ",
"",
" // Only change code below this line",
"",
" // Only change code above this line",
"",
2017-02-25 13:59:02 +00:00
"}"
2017-01-17 04:44:38 +00:00
],
"tests": [
"assert((function(){var test = new LinkedList(); test.add('cat'); test.add('dog'); test.addAt(0,'cat'); return test.head().element === 'cat'}()), 'message: Your <code>addAt</code> method should reassign <code>head</code> to the new node when the given index is 0.');",
"assert((function(){var test = new LinkedList(); test.add('cat'); test.add('dog'); test.addAt(0,'cat'); return test.size() === 3}()), 'message: Your <code>addAt</code> method should increase the length of the linked list by one for each new node added to the linked list.');",
"assert((function(){var test = new LinkedList(); test.add('cat'); test.add('dog'); return (test.addAt(4,'cat') === false); }()), 'message: Your <code>addAt</code> method should return <code>false</code> if a node was unable to be added.');"
2017-01-17 04:44:38 +00:00
],
"solutions": [],
"hints": [],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {}
2017-01-17 04:44:38 +00:00
},
{
"id": "587d825a367417b2b2512c87",
"title": "Create a Doubly Linked List",
2017-01-17 04:44:38 +00:00
"description": [
2017-02-21 00:17:47 +00:00
"All of the linked lists we've created so far are singly linked lists. Here, we'll create a <dfn>doubly linked list</dfn>. As the name implies, nodes in a doubly linked list have references to the next and previous node in the list.",
"This allows us to traverse the list in both directions but it also requires more memory to be used because every node must contain an additional reference to the previous node in the list.",
"<hr>",
"We've provided a <code>Node</code> object and started our <code>DoublyLinkedList</code>. Let's add two methods to our doubly linked list called <code>add</code> and <code>remove</code>. The <code>add</code> method should add the given element to the list while the <code>remove</code> method should remove all occurrences of a given element in the list.",
"Be careful to handle any possible edge cases when writing these methods, such as deletions for the first or last element. Also, removing any item on an empty list should return <code>null</code>."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"var Node = function(data, prev) {",
" this.data = data;",
" this.prev = prev;",
" this.next = null;",
"};",
"var DoublyLinkedList = function() {",
" this.head = null;",
" this.tail = null;",
" // change code below this line",
" // change code above this line",
"};"
],
"tail": [
"DoublyLinkedList.prototype = {",
" print() {",
" if (this.head == null) {",
" return null;",
" } else {",
" var result = new Array();",
" var node = this.head;",
" while (node.next != null) {",
" result.push(node.data);",
" node = node.next;",
" };",
" result.push(node.data);",
" return result;",
" };",
" },",
" printReverse() {",
" if (this.tail == null) {",
" return null;",
" } else {",
" var result = new Array();",
" var node = this.tail;",
" while (node.prev != null) {",
" result.push(node.data);",
" node = node.prev;",
" };",
" result.push(node.data);",
" return result;",
" };",
" } ",
"};"
2017-01-17 04:44:38 +00:00
],
"tests": [
"assert((function() { var test = false; if (typeof DoublyLinkedList !== 'undefined') { test = new DoublyLinkedList() }; return (typeof test == 'object')})(), 'message: The DoublyLinkedList data structure exists.');",
"assert((function() { var test = false; if (typeof DoublyLinkedList !== 'undefined') { test = new DoublyLinkedList() }; if (test.add == undefined) { return false; }; return (typeof test.add == 'function')})(), 'message: The DoublyLinkedList has a method called add.');",
"assert((function() { var test = false; if (typeof DoublyLinkedList !== 'undefined') { test = new DoublyLinkedList() }; if (test.remove == undefined) { return false; }; return (typeof test.remove == 'function')})(), 'message: The DoublyLinkedList has a method called remove.');",
"assert((function() { var test = false; if (typeof DoublyLinkedList !== 'undefined') { test = new DoublyLinkedList() }; return (test.remove(100) == null); })(), 'message: Removing an item from an empty list returns null.');",
"assert((function() { var test = false; if (typeof DoublyLinkedList !== 'undefined') { test = new DoublyLinkedList() }; test.add(5); test.add(6); test.add(723); return (test.print().join('') == '56723'); })(), 'message: The add method adds items to the list.');",
"assert((function() { var test = false; if (typeof DoublyLinkedList !== 'undefined') { test = new DoublyLinkedList() }; test.add(50); test.add(68); test.add(73); return (test.printReverse().join('') == '736850'); })(), 'message: Each node keeps track of the previous node.');",
"assert((function() { var test = false; if (typeof DoublyLinkedList !== 'undefined') { test = new DoublyLinkedList() }; test.add(25); test.add(35); test.add(60); test.remove(25); return ( test.print().join('') == '3560' ) })(), 'message: The first item can be removed from the list.');",
"assert((function() { var test = false; if (typeof DoublyLinkedList !== 'undefined') { test = new DoublyLinkedList() }; test.add(25); test.add(35); test.add(60); test.remove(60); return ( test.print().join('') == '2535' ) })(), 'message: The last item can be removed from the list.');"
2017-01-17 04:44:38 +00:00
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
2017-01-17 04:44:38 +00:00
"solutions": [],
"challengeType": 1,
2017-01-17 04:44:38 +00:00
"translations": {}
},
{
"id": "587d825a367417b2b2512c88",
"title": "Reverse a Doubly Linked List",
2017-01-17 04:44:38 +00:00
"description": [
"Let's create one more method for our doubly linked list called reverse which reverses the list in place. Once the method is executed the head should point to the previous tail and the tail should point to the previous head. Now, if we traverse the list from head to tail we should meet the nodes in a reverse order compared to the original list. Trying to reverse an empty list should return null."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"var Node = function(data, prev) {",
" this.data = data;",
" this.prev = prev;",
" this.next = null;",
"};",
"var DoublyLinkedList = function() {",
" this.head = null;",
" this.tail = null;",
" // change code below this line",
" // change code above this line",
"};"
2017-01-17 04:44:38 +00:00
],
"tests": [
"assert((function() { var test = false; if (typeof DoublyLinkedList !== 'undefined') { test = new DoublyLinkedList() }; return (typeof test == 'object')})(), 'message: The DoublyLinkedList data structure exists.');",
"assert((function() { var test = false; if (typeof DoublyLinkedList !== 'undefined') { test = new DoublyLinkedList() }; if (test.add == undefined) { return false; }; return (typeof test.add == 'function')})(), 'message: The DoublyLinkedList has a method called add.');",
"assert((function() { var test = false; if (typeof DoublyLinkedList !== 'undefined') { test = new DoublyLinkedList() }; if (test.reverse == undefined) { return false; }; return (typeof test.reverse == 'function')})(), 'message: The DoublyLinkedList has a method called reverse.');",
"assert((function() { var test = false; if (typeof DoublyLinkedList !== 'undefined') { test = new DoublyLinkedList() }; return (test.reverse() == null); })(), 'message: Reversing an empty list returns null.');",
"assert((function() { var test = false; if (typeof DoublyLinkedList !== 'undefined') { test = new DoublyLinkedList() }; test.add(58); test.add(61); test.add(32); test.reverse(); return (test.print().join('') == '326158'); })(), 'message: The reverse method reverses the list.');",
"assert((function() { var test = false; if (typeof DoublyLinkedList !== 'undefined') { test = new DoublyLinkedList() }; test.add(11); test.add(22); test.add(33); test.reverse(); return (test.printReverse().join('') == '112233'); })(), 'message: The next and previous references are correctly maintained when a list is reversed.');"
],
"tail": [
"DoublyLinkedList.prototype = {",
" add(data) {",
" if (this.head == null) {",
" this.head = new Node(data, null);",
" this.tail = this.head;",
" } else {",
" var node = this.head;",
" var prev = null;",
" while (node.next != null) {",
" prev = node;",
" node = node.next;",
" };",
" var newNode = new Node(data, node);",
" node.next = newNode;",
" this.tail = newNode;",
" };",
" },",
" print() {",
" if (this.head == null) {",
" return null;",
" } else {",
" var result = new Array();",
" var node = this.head;",
" while (node.next != null) {",
" result.push(node.data);",
" node = node.next;",
" };",
" result.push(node.data);",
" return result;",
" };",
" },",
" printReverse() {",
" if (this.tail == null) {",
" return null;",
" } else {",
" var result = new Array();",
" var node = this.tail;",
" while (node.prev != null) {",
" result.push(node.data);",
" node = node.prev;",
" };",
" result.push(node.data);",
" return result;",
" };",
" }",
"};"
2017-01-17 04:44:38 +00:00
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
2017-01-17 04:44:38 +00:00
"solutions": [],
"challengeType": 1,
2017-01-17 04:44:38 +00:00
"translations": {}
},
{
"id": "587d8256367417b2b2512c7a",
"title": "Find the Minimum and Maximum Value in a Binary Search Tree",
"description": [
"This series of challenges will introduce the tree data structure. Trees are an important and versatile data structure in computer science. Of course, their name comes from the fact that when visualized they look much like the trees we are familiar with in the natural world. A tree data structure begins with one node, typically referred to as the root, and from here branches out to additional nodes, each of which may have more child nodes, and so on and so forth. The data structure is usually visualized with the root node at the top; you can think of it as a natural tree flipped upside down.",
"First, let's describe some common terminology we will encounter with trees. The root node is the top of the tree. Data points in the tree are called nodes. Nodes with branches leading to other nodes are referred to as the parent of the node the branch leads to (the child). Other more complicated familial terms apply as you might expect. A subtree refers to all the descendants of a particular node, branches may be referred to as edges, and leaf nodes are nodes at the end of the tree that have no children. Finally, note that trees are inherently recursive data structures. That is, any children of a node are parents of their own subtree, and so on. The recursive nature of trees is important to understand when designing algorithms for common tree operations.",
"To begin, we will discuss a particular type of a tree, the binary tree. In fact, we will actually discuss a particular binary tree, a binary search tree. Let's describe what this means. While the tree data structure can have any number of branches at a single node, a binary tree can only have two branches for every node. Furthermore, a binary search tree is ordered with respect to the child subtrees, such that the value of each node in the left subtree is less than or equal to the value of the parent node, and the value of each node in the right subtree is greater than or equal to the value of the parent node. It's very helpful to visualize this relationship in order to understand it better:",
"<div style='width: 100%; display: flex; justify-content: center; align-items: center;'><img style='width: 100%; max-width: 350px;' src='https://user-images.githubusercontent.com/18563015/32136009-1e665d98-bbd6-11e7-9133-63184f9f9182.png'></div>",
"Now this ordered relationship is very easy to see. Note that every value to the left of 8, the root node, is less than 8, and every value to the right is greater than 8. Also notice that this relationship applies to each of the subtrees as well. For example, the first left child is a subtree. 3 is the parent node, and it has exactly two child nodes &mdash; by the rules governing binary search trees, we know without even looking that the left child of this node (and any of its children) will be less than 3, and the right child (and any of its children) will be greater than 3 (but also less than the structure's root value), and so on.",
"Binary search trees are very common and useful data structures because they provide logarithmic time in the average case for several common operations such as lookup, insertion, and deletion.",
"Instructions: We'll start simple. We've defined the skeleton of a binary search tree structure here in addition to a function to create nodes for our tree. Observe that each node may have a left and right value. These will be assigned child subtrees if they exist. In our binary search tree, define two methods, <code>findMin</code> and <code>findMax</code>. These methods should return the minimum and maximum value held in the binary search tree (don't worry about adding values to the tree for now, we have added some in the background). If you get stuck, reflect on the invariant that must be true for binary search trees: each left subtree is less than or equal to its parent and each right subtree is greater than or equal to its parent. Let's also say that our tree can only store integer values. If the tree is empty, either method should return <code>null</code>."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"var displayTree = (tree) => console.log(JSON.stringify(tree, null, 2));",
2017-01-17 04:44:38 +00:00
"function Node(value) {",
" this.value = value;",
" this.left = null;",
" this.right = null;",
2017-02-25 13:59:02 +00:00
"}",
2017-01-17 04:44:38 +00:00
"function BinarySearchTree() {",
" this.root = null;",
" // change code below this line",
" // change code above this line",
2017-02-25 13:59:02 +00:00
"}"
2017-01-17 04:44:38 +00:00
],
"tests": [
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() }; return (typeof test == 'object')})(), 'message: The <code>BinarySearchTree</code> data structure exists.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; return (typeof test.findMin == 'function')})(), 'message: The binary search tree has a method called <code>findMin</code>.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; return (typeof test.findMax == 'function')})(), 'message: The binary search tree has a method called <code>findMax</code>.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.findMin !== 'function') { return false; }; test.add(4); test.add(1); test.add(7); test.add(87); test.add(34); test.add(45); test.add(73); test.add(8); return test.findMin() == 1; })(), 'message: The <code>findMin</code> method returns the minimum value in the binary search tree.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.findMax !== 'function') { return false; }; test.add(4); test.add(1); test.add(7); test.add(87); test.add(34); test.add(45); test.add(73); test.add(8); return test.findMax() == 87; })(), 'message: The <code>findMax</code> method returns the maximum value in the binary search tree.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.findMin !== 'function') { return false; }; if (typeof test.findMax !== 'function') { return false; }; return (test.findMin() == null && test.findMax() == null) })(), 'message: The <code>findMin</code> and <code>findMax</code> methods return <code>null</code> for an empty tree.');"
2017-01-17 04:44:38 +00:00
],
"tail": [
"BinarySearchTree.prototype = {",
" add: function(value) {",
" var node = this.root;",
2017-01-17 04:44:38 +00:00
" if (node == null) {",
" this.root = new Node(value);",
" return;",
" } else {",
" function searchTree(node) {",
" if (value < node.value) {",
" if (node.left == null) {",
" node.left = new Node(value);",
" return;",
" } else if (node.left != null) {",
" return searchTree(node.left)",
" };",
" } else if (value > node.value) {",
" if (node.right == null) {",
" node.right = new Node(value);",
" return;",
" } else if (node.right != null) {",
" return searchTree(node.right);",
" };",
" } else {",
" return null;",
" };",
" };",
" return searchTree(node);",
" };",
" }",
"};"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
2017-01-17 04:44:38 +00:00
"solutions": [],
"challengeType": 1,
2017-01-17 04:44:38 +00:00
"translations": {}
},
{
"id": "587d8257367417b2b2512c7b",
"title": "Add a New Element to a Binary Search Tree",
"description": [
"Now that we have an idea of the basics lets write a more complex method.",
"In this challenge, we will create a method to add new values to our binary search tree. The method should be called <code>add</code> and it should accept an integer value to add to the tree. Take care to maintain the invariant of a binary search tree: the value in each left child should be less than or equal to the parent value, and the value in each right child should be greater than or equal to the parent value. Here, let's make it so our tree cannot hold duplicate values. If we try to add a value that already exists, the method should return <code>null</code>. Otherwise, if the addition is successful, <code>undefined</code> should be returned.",
2017-01-17 04:44:38 +00:00
"Hint: trees are naturally recursive data structures!"
],
"challengeSeed": [
"var displayTree = (tree) => console.log(JSON.stringify(tree, null, 2));",
2017-01-17 04:44:38 +00:00
"function Node(value) {",
" this.value = value;",
" this.left = null;",
" this.right = null;",
2017-02-25 13:59:02 +00:00
"}",
2017-01-17 04:44:38 +00:00
"function BinarySearchTree() {",
" this.root = null;",
" // change code below this line",
" // change code above this line",
2017-02-25 13:59:02 +00:00
"}"
2017-01-17 04:44:38 +00:00
],
"tail": [
"BinarySearchTree.prototype = {",
" isBinarySearchTree() {",
" if (this.root == null) {",
" return null;",
" } else {",
" var check = true;",
2017-01-17 04:44:38 +00:00
" function checkTree(node) {",
" if (node.left != null) {",
" var left = node.left;",
2017-01-17 04:44:38 +00:00
" if (left.value > node.value) {",
" check = false;",
" } else {",
" checkTree(left);",
" }",
" }",
" if (node.right != null) {",
" var right = node.right;",
2017-01-17 04:44:38 +00:00
" if (right.value < node.value) {",
" check = false;",
" } else {",
" checkTree(right);",
" };",
" };",
" };",
" checkTree(this.root);",
" return check;",
" };",
" }",
"};"
],
"tests": [
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() }; return (typeof test == 'object')})(), 'message: The <code>BinarySearchTree</code> data structure exists.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; return (typeof test.add == 'function')})(), 'message: The binary search tree has a method called <code>add</code>.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.add !== 'function') { return false; }; test.add(4); test.add(1); test.add(7); test.add(87); test.add(34); test.add(45); test.add(73); test.add(8); return (test.isBinarySearchTree()); })(), 'message: The add method adds elements according to the binary search tree rules.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.add !== 'function') { return false; }; test.add(4); return test.add(4) == null; })(), 'message: Adding an element that already exists returns <code>null</code>');"
2017-01-17 04:44:38 +00:00
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
2017-01-17 04:44:38 +00:00
"solutions": [],
"challengeType": 1,
2017-01-17 04:44:38 +00:00
"translations": {}
},
{
"id": "587d8257367417b2b2512c7c",
"title": "Check if an Element is Present in a Binary Search Tree",
"description": [
"Now that we have a general sense of what a binary search tree is let's talk about it in a little more detail. Binary search trees provide logarithmic time for the common operations of lookup, insertion, and deletion in the average case, and linear time in the worst case. Why is this? Each of those basic operations requires us to find an item in the tree (or in the case of insertion to find where it should go) and because of the tree structure at each parent node we are branching left or right and effectively excluding half the size of the remaining tree. This makes the search proportional to the logarithm of the number of nodes in the tree, which creates logarithmic time for these operations in the average case.",
"Ok, but what about the worst case? Well, consider constructing a tree from the following values, adding them left to right: <code>10</code>, <code>12</code>, <code>17</code>, <code>25</code>. Following our rules for a binary search tree, we will add <code>12</code> to the right of <code>10</code>, <code>17</code> to the right of this, and <code>25</code> to the right of this. Now our tree resembles a linked list and traversing it to find <code>25</code> would require us to traverse all the items in linear fashion. Hence, linear time in the worst case. The problem here is that the tree is unbalanced. We'll look a little more into what this means in the following challenges.",
"Instructions: In this challenge, we will create a utility for our tree. Write a method <code>isPresent</code> which takes an integer value as input and returns a boolean value for the presence or absence of that value in the binary search tree."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"var displayTree = (tree) => console.log(JSON.stringify(tree, null, 2));",
2017-01-17 04:44:38 +00:00
"function Node(value) {",
" this.value = value;",
" this.left = null;",
" this.right = null;",
2017-02-25 13:59:02 +00:00
"}",
2017-01-17 04:44:38 +00:00
"function BinarySearchTree() { ",
" this.root = null;",
" // change code below this line",
" // change code above this line",
2017-02-25 13:59:02 +00:00
"}"
2017-01-17 04:44:38 +00:00
],
"tail": [
"BinarySearchTree.prototype = {",
" add: function(value) {",
" var node = this.root;",
2017-01-17 04:44:38 +00:00
" if (node == null) {",
" this.root = new Node(value);",
" return;",
" } else {",
" function searchTree(node) {",
" if (value < node.value) {",
" if (node.left == null) {",
" node.left = new Node(value);",
" return;",
" } else if (node.left != null) {",
" return searchTree(node.left)",
" };",
" } else if (value > node.value) {",
" if (node.right == null) {",
" node.right = new Node(value);",
" return;",
" } else if (node.right != null) {",
" return searchTree(node.right);",
" };",
" } else {",
" return null;",
" };",
" };",
" return searchTree(node);",
" };",
" }",
"};"
],
"tests": [
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() }; return (typeof test == 'object')})(), 'message: The <code>BinarySearchTree</code> data structure exists.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; return (typeof test.isPresent == 'function')})(), 'message: The binary search tree has a method called <code>isPresent</code>.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.isPresent !== 'function') { return false; }; test.add(4); test.add(7); test.add(411); test.add(452); return ( test.isPresent(452) && test.isPresent(411) && test.isPresent(7) && !test.isPresent(100) ); })(), 'message: The <code>isPresent</code> method correctly checks for the presence or absence of elements added to the tree.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.isPresent !== 'function') { return false; }; return test.isPresent(5) == false; })(), 'message: <code>isPresent</code> handles cases where the tree is empty.');"
2017-01-17 04:44:38 +00:00
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
2017-01-17 04:44:38 +00:00
"solutions": [],
"challengeType": 1,
2017-01-17 04:44:38 +00:00
"translations": {}
},
{
"id": "587d8257367417b2b2512c7d",
"title": "Find the Minimum and Maximum Height of a Binary Search Tree",
"description": [
"In the last challenge we described a scenario in which a tree could become unbalanced. To understand the concept of balance, let's take a look at another tree property: height. Height in a tree represents the distance from the root node to any given leaf node. Different paths in a highly branched tree structure may have different heights, but for a given tree there will be a minimum and maximum height. If the tree is balanced, these values will differ at most by one. This means that in a balanced tree, all the leaf nodes exist within the same level, or if they are not within the same level they are at most one level apart.",
"The property of balance is important for trees because it is what determines the efficiency of tree operations. As we explained in the last challenge, we face worst case time complexity for heavily unbalanced trees. Self-balancing trees are commonly used to account for this issue in trees with dynamic data sets. Common examples of these include AVL trees, red-black trees, and B-trees. These trees all contain additional internal logic which re-balance the tree when insertions or deletions create a state of imbalance.",
"Note: A similar property to height is depth, which refers to how far a given node is from the root node.",
"Instructions: Write two methods for our binary tree: <code>findMinHeight</code> and <code>findMaxHeight</code>. These methods should return an integer value for the minimum and maximum height within a given binary tree, respectively. If the node is empty let's assign it a height of <code>-1</code> (that's the base case). Finally, add a third method <code>isBalanced</code> which returns <code>true</code> or <code>false</code> depending on whether the tree is balanced or not. You can use the first two methods you just wrote to determine this."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"var displayTree = (tree) => console.log(JSON.stringify(tree, null, 2));",
2017-01-17 04:44:38 +00:00
"function Node(value) {",
" this.value = value;",
" this.left = null;",
" this.right = null;",
2017-02-25 13:59:02 +00:00
"}",
2017-01-17 04:44:38 +00:00
"function BinarySearchTree() {",
" this.root = null;",
" // change code below this line",
" // change code above this line",
2017-02-25 13:59:02 +00:00
"}"
2017-01-17 04:44:38 +00:00
],
"tail": [
"BinarySearchTree.prototype = {",
" add: function(value) {",
" var node = this.root;",
2017-01-17 04:44:38 +00:00
" if (node == null) {",
" this.root = new Node(value);",
" return;",
" } else {",
" function searchTree(node) {",
" if (value < node.value) {",
" if (node.left == null) {",
" node.left = new Node(value);",
" return;",
" } else if (node.left != null) {",
" return searchTree(node.left)",
" };",
" } else if (value > node.value) {",
" if (node.right == null) {",
" node.right = new Node(value);",
" return;",
" } else if (node.right != null) {",
" return searchTree(node.right);",
" };",
" } else {",
" return null;",
" };",
" };",
" return searchTree(node);",
" };",
" }",
"};"
],
"tests": [
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() }; return (typeof test == 'object')})(), 'message: The <code>BinarySearchTree</code> data structure exists.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; return (typeof test.findMinHeight == 'function')})(), 'message: The binary search tree has a method called <code>findMinHeight</code>.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; return (typeof test.findMaxHeight == 'function')})(), 'message: The binary search tree has a method called <code>findMaxHeight</code>.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; return (typeof test.isBalanced == 'function')})(), 'message: The binary search tree has a method called <code>isBalanced</code>.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.findMinHeight !== 'function') { return false; }; test.add(4); test.add(1); test.add(7); test.add(87); test.add(34); test.add(45); test.add(73); test.add(8); return (test.findMinHeight() == 1); })(), 'message: The <code>findMinHeight</code> method returns the minimum height of the tree.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.findMaxHeight !== 'function') { return false; }; test.add(4); test.add(1); test.add(7); test.add(87); test.add(34); test.add(45); test.add(73); test.add(8); return (test.findMaxHeight() == 5); })(), 'message: The <code>findMaxHeight</code> method returns the maximum height of the tree.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.findMaxHeight !== 'function') { return false; }; return (test.findMaxHeight() == -1); })(), 'message: An empty tree returns a height of <code>-1</code>.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.isBalanced !== 'function') { return false; }; test.add(4); test.add(1); test.add(7); test.add(87); test.add(34); test.add(45); test.add(73); test.add(8); return test.isBalanced(); })(), 'message: The <code>isBalanced</code> method returns true if the tree is a balanced binary search tree.');"
2017-01-17 04:44:38 +00:00
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
2017-01-17 04:44:38 +00:00
"solutions": [],
"challengeType": 1,
2017-01-17 04:44:38 +00:00
"translations": {}
},
{
"id": "587d8257367417b2b2512c7e",
"title": "Use Depth First Search in a Binary Search Tree",
"description": [
"We know how to search a binary search tree for a specific value. But what if we just want to explore the entire tree? Or what if we don't have an ordered tree and we need to just search for a value? Here we will introduce some tree traversal methods which can be used to explore tree data structures. First up is depth-first search. In depth-first search, a given subtree is explored as deeply as possible before the search continues on to another subtree. There are three ways this can be done:",
"In-order: Begin the search at the left-most node and end at the right-most node.",
"Pre-order: Explore all the roots before the leaves.",
"Post-order: Explore all the leaves before the roots.",
"As you may guess, you may choose different search methods depending on what type of data your tree is storing and what you are looking for. For a binary search tree, an inorder traversal returns the nodes in sorted order.",
"Instructions: Here we will create these three search methods on our binary search tree. Depth-first search is an inherently recursive operation which continues to explore further subtrees so long as child nodes are present. Once you understand this basic concept, you can simply rearrange the order in which you explore the nodes and subtrees to produce any of the three searches above. For example, in post-order search we would want to recurse all the way to a leaf node before we begin to return any of the nodes themselves, whereas in pre-order search we would want to return the nodes first, and then continue recursing down the tree.",
"Define <code>inorder</code>, <code>preorder</code>, and <code>postorder</code> methods on our tree. Each of these methods should return an array of items which represent the tree traversal. Be sure to return the integer values at each node in the array, not the nodes themselves. Finally, return <code>null</code> if the tree is empty."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"var displayTree = (tree) => console.log(JSON.stringify(tree, null, 2));",
2017-01-17 04:44:38 +00:00
"function Node(value) {",
" this.value = value;",
" this.left = null;",
" this.right = null;",
2017-02-25 13:59:02 +00:00
"}",
2017-01-17 04:44:38 +00:00
"function BinarySearchTree() {",
" this.root = null;",
" // change code below this line",
" // change code above this line",
2017-02-25 13:59:02 +00:00
"}"
2017-01-17 04:44:38 +00:00
],
"tail": [
"BinarySearchTree.prototype = {",
" add: function(value) {",
" var node = this.root;",
2017-01-17 04:44:38 +00:00
" if (node == null) {",
" this.root = new Node(value);",
" return;",
" } else {",
" function searchTree(node) {",
" if (value < node.value) {",
" if (node.left == null) {",
" node.left = new Node(value);",
" return;",
" } else if (node.left != null) {",
" return searchTree(node.left)",
" };",
" } else if (value > node.value) {",
" if (node.right == null) {",
" node.right = new Node(value);",
" return;",
" } else if (node.right != null) {",
" return searchTree(node.right);",
" };",
" } else {",
" return null;",
" };",
" };",
" return searchTree(node);",
" };",
" }",
"};"
],
"tests": [
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() }; return (typeof test == 'object')})(), 'message: The <code>BinarySearchTree</code> data structure exists.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; return (typeof test.inorder == 'function')})(), 'message: The binary search tree has a method called <code>inorder</code>.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; return (typeof test.preorder == 'function')})(), 'message: The binary search tree has a method called <code>preorder</code>.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; return (typeof test.postorder == 'function')})(), 'message: The binary search tree has a method called <code>postorder</code>.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.inorder !== 'function') { return false; }; test.add(7); test.add(1); test.add(9); test.add(0); test.add(3); test.add(8); test.add(10); test.add(2); test.add(5); test.add(4); test.add(6); return (test.inorder().join('') == '012345678910'); })(), 'message: The <code>inorder</code> method returns an array of the node values that result from an inorder traversal.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.preorder !== 'function') { return false; }; test.add(7); test.add(1); test.add(9); test.add(0); test.add(3); test.add(8); test.add(10); test.add(2); test.add(5); test.add(4); test.add(6); return (test.preorder().join('') == '710325469810'); })(), 'message: The <code>preorder</code> method returns an array of the node values that result from a preorder traversal.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.postorder !== 'function') { return false; }; test.add(7); test.add(1); test.add(9); test.add(0); test.add(3); test.add(8); test.add(10); test.add(2); test.add(5); test.add(4); test.add(6); return (test.postorder().join('') == '024653181097'); })(), 'message: The <code>postorder</code> method returns an array of the node values that result from a postorder traversal.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.inorder !== 'function') { return false; }; return (test.inorder() == null); })(), 'message: The <code>inorder</code> method returns <code>null</code> for an empty tree.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.preorder !== 'function') { return false; }; return (test.preorder() == null); })(), 'message: The <code>preorder</code> method returns <code>null</code> for an empty tree.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.postorder !== 'function') { return false; }; return (test.postorder() == null); })(), 'message: The <code>postorder</code> method returns <code>null</code> for an empty tree.');"
],
2017-01-17 04:44:38 +00:00
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
2017-01-17 04:44:38 +00:00
"solutions": [],
"challengeType": 1,
2017-01-17 04:44:38 +00:00
"translations": {}
},
{
"id": "587d8258367417b2b2512c7f",
"title": "Use Breadth First Search in a Binary Search Tree",
2017-01-17 04:44:38 +00:00
"description": [
"Here we will introduce another tree traversal method: breadth-first search. In contrast to the depth-first search methods from the last challenge, breadth-first search explores all the nodes in a given level within a tree before continuing on to the next level. Typically, queues are utilized as helper data structures in the design of breadth-first search algorithms.",
"In this method, we start by adding the root node to a queue. Then we begin a loop where we dequeue the first item in the queue, add it to a new array, and then inspect both its child subtrees. If its children are not null, they are each enqueued. This process continues until the queue is empty.",
"Instructions: Let's create a breadth-first search method in our tree called <code>levelOrder</code>. This method should return an array containing the values of all the tree nodes, explored in a breadth-first manner. Be sure to return the values in the array, not the nodes themselves. A level should be traversed from left to right. Next, let's write a similar method called <code>reverseLevelOrder</code> which performs the same search but in the reverse direction (right to left) at each level."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"var displayTree = (tree) => console.log(JSON.stringify(tree, null, 2));",
2017-01-17 04:44:38 +00:00
"function Node(value) {",
" this.value = value;",
" this.left = null;",
" this.right = null;",
2017-02-25 13:59:02 +00:00
"}",
2017-01-17 04:44:38 +00:00
"function BinarySearchTree() {",
" this.root = null;",
" // change code below this line",
" // change code above this line",
2017-02-25 13:59:02 +00:00
"}"
2017-01-17 04:44:38 +00:00
],
"tail": [
"BinarySearchTree.prototype = {",
" add: function(value) {",
" var node = this.root;",
2017-01-17 04:44:38 +00:00
" if (node == null) {",
" this.root = new Node(value);",
" return;",
" } else {",
" function searchTree(node) {",
" if (value < node.value) {",
" if (node.left == null) {",
" node.left = new Node(value);",
" return;",
" } else if (node.left != null) {",
" return searchTree(node.left)",
" };",
" } else if (value > node.value) {",
" if (node.right == null) {",
" node.right = new Node(value);",
" return;",
" } else if (node.right != null) {",
" return searchTree(node.right);",
" };",
" } else {",
" return null;",
" };",
" };",
" return searchTree(node);",
" };",
" }",
"};"
],
"tests": [
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() }; return (typeof test == 'object')})(), 'message: The <code>BinarySearchTree</code> data structure exists.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; return (typeof test.levelOrder == 'function')})(), 'message: The binary search tree has a method called <code>levelOrder</code>.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; return (typeof test.reverseLevelOrder == 'function')})(), 'message: The binary search tree has a method called <code>reverseLevelOrder</code>.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.levelOrder !== 'function') { return false; }; test.add(7); test.add(1); test.add(9); test.add(0); test.add(3); test.add(8); test.add(10); test.add(2); test.add(5); test.add(4); test.add(6); return (test.levelOrder().join('') == '719038102546'); })(), 'message: The <code>levelOrder</code> method returns an array of the tree node values explored in level order.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.reverseLevelOrder !== 'function') { return false; }; test.add(7); test.add(1); test.add(9); test.add(0); test.add(3); test.add(8); test.add(10); test.add(2); test.add(5); test.add(4); test.add(6); return (test.reverseLevelOrder().join('') == '791108305264'); })(), 'message: The <code>reverseLevelOrder</code> method returns an array of the tree node values explored in reverse level order.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.levelOrder !== 'function') { return false; }; return (test.levelOrder() == null); })(), 'message: The <code>levelOrder</code> method returns <code>null</code> for an empty tree.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.reverseLevelOrder !== 'function') { return false; }; return (test.reverseLevelOrder() == null); })(), 'message: The <code>reverseLevelOrder</code> method returns <code>null</code> for an empty tree.');"
],
2017-01-17 04:44:38 +00:00
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
2017-01-17 04:44:38 +00:00
"solutions": [],
"challengeType": 1,
2017-01-17 04:44:38 +00:00
"translations": {}
},
{
"id": "587d8258367417b2b2512c80",
"title": "Delete a Leaf Node in a Binary Search Tree",
2017-01-17 04:44:38 +00:00
"description": [
"This is the first of three challenges where we will implement a more difficult operation in binary search trees: deletion. Deletion is difficult because removing nodes breaks links in the tree. These links must be carefully reestablished to ensure the binary tree structure is maintained. For some deletions, this means the tree must be rearranged. In general, you will encounter one of three cases when trying to delete a node:",
"Leaf Node: The target to delete has zero children.",
"One Child: The target to delete only has one child.",
"Two Children: The target to delete has two child nodes.",
"Removing a leaf node is easy, we simply remove it. Deleting a node with one child is also relatively easy, we simply remove it and link its parent to child of the node we deleted. Removing a node with two children is more difficult, however, because this creates two child nodes that need to be reconnected to the parent tree. We'll see how to deal with this case in the third challenge. Additionally, you need to be mindful of some edge cases when handling deletion. What if the tree is empty? What if the node to delete is the root node? What if there are only two elements in the tree? For now, let's handle the first case where we delete a leaf node.",
"Instructions: Create a method on our binary tree called <code>remove</code>. We'll build the logic for our deletion operation in here. First, you'll want to create a function within remove that finds the node we are trying to delete in the current tree. If the node is not present in the tree, <code>remove</code> should return <code>null</code>. Now, if the target node is a leaf node with no children, then the parent reference to it should be set to <code>null</code>. This effectively deletes the node from the tree. To do this, you will have to keep track of the parent of the node we are trying to delete as well. It will also be useful to create a way to track the number of children the target node has, as this will determine which case our deletion falls under.",
"We will handle the second and third cases in the next challenges. Good luck!"
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"var displayTree = (tree) => console.log(JSON.stringify(tree, null, 2));",
2017-01-17 04:44:38 +00:00
"function Node(value) {",
" this.value = value;",
" this.left = null;",
" this.right = null;",
2017-02-25 13:59:02 +00:00
"}",
"",
2017-01-17 04:44:38 +00:00
"function BinarySearchTree() {",
" this.root = null;",
" // case 1: target has no children, change code below this line",
2017-02-25 13:59:02 +00:00
"}"
2017-01-17 04:44:38 +00:00
],
"tests": [
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() }; return (typeof test == 'object')})(), 'message: The <code>BinarySearchTree</code> data structure exists.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; return (typeof test.remove == 'function')})(), 'message: The binary search tree has a method called <code>remove</code>.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.remove !== 'function') { return false; }; return (test.remove(100) == null); })(), 'message: Trying to remove an element that does not exist returns <code>null</code>.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.remove !== 'function') { return false; }; test.add(500); test.remove(500); return (test.inorder() == null); })(), 'message: If the root node has no children, deleting it sets the root to <code>null</code>.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.remove !== 'function') { return false; }; test.add(5); test.add(3); test.add(7); test.add(6); test.add(10); test.add(12); test.remove(3); test.remove(12); test.remove(10); return (test.inorder().join('') == '567'); })(), 'message: The <code>remove</code> method removes leaf nodes from the tree');"
2017-01-17 04:44:38 +00:00
],
"tail": [
"BinarySearchTree.prototype = {",
" add: function(value) {",
" var node = this.root;",
2017-01-17 04:44:38 +00:00
" if (node == null) {",
" this.root = new Node(value);",
" return;",
" } else {",
" function searchTree(node) {",
" if (value < node.value) {",
" if (node.left == null) {",
" node.left = new Node(value);",
" return;",
" } else if (node.left != null) {",
" return searchTree(node.left)",
" };",
" } else if (value > node.value) {",
" if (node.right == null) {",
" node.right = new Node(value);",
" return;",
" } else if (node.right != null) {",
" return searchTree(node.right);",
" };",
" } else {",
" return null;",
" };",
" };",
" return searchTree(node);",
" };",
" },",
" inorder: function() {",
" if (this.root == null) {",
" return null;",
" } else {",
" var result = new Array();",
" function traverseInOrder(node) {",
" if (node.left != null) {",
" traverseInOrder(node.left);",
" };",
" result.push(node.value);",
" if (node.right != null) {",
" traverseInOrder(node.right);",
" };",
" }",
" traverseInOrder(this.root);",
" return result;",
" };",
" }, ",
" isBinarySearchTree() {",
" if (this.root == null) {",
" return null;",
" } else {",
" var check = true;",
2017-01-17 04:44:38 +00:00
" function checkTree(node) {",
" if (node.left != null) {",
" var left = node.left;",
2017-01-17 04:44:38 +00:00
" if (left.value > node.value) {",
" check = false;",
" } else {",
" checkTree(left);",
" }",
" }",
" if (node.right != null) {",
" var right = node.right;",
2017-01-17 04:44:38 +00:00
" if (right.value < node.value) {",
" check = false;",
" } else {",
" checkTree(right);",
" };",
" };",
" };",
" checkTree(this.root);",
" return check;",
" }",
" }",
"};"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
2017-01-17 04:44:38 +00:00
"solutions": [],
"challengeType": 1,
2017-01-17 04:44:38 +00:00
"translations": {}
},
{
"id": "587d8258367417b2b2512c81",
"title": "Delete a Node with One Child in a Binary Search Tree",
2017-01-17 04:44:38 +00:00
"description": [
"Now that we can delete leaf nodes let's move on to the second case: deleting a node with one child. For this case, say we have a tree with the following nodes 1 — 2 — 3 where 1 is the root. To delete 2, we simply need to make the right reference in 1 point to 3. More generally to delete a node with only one child, we make that node's parent reference the next node in the tree.",
"Instructions: We've provided some code in our <code>remove</code> method that accomplishes the tasks from the last challenge. We find the target to delete and its parent and define the number of children the target node has. Let's add the next case here for target nodes with only one child. Here, we'll have to determine if the single child is a left or right branch in the tree and then set the correct reference in the parent to point to this node. In addition, let's account for the case where the target is the root node (this means the parent node will be <code>null</code>). Feel free to replace all the starter code with your own as long as it passes the tests."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"var displayTree = (tree) => console.log(JSON.stringify(tree, null, 2));",
2017-01-17 04:44:38 +00:00
"function Node(value) {",
" this.value = value;",
" this.left = null;",
" this.right = null;",
2017-02-25 13:59:02 +00:00
"}",
"",
2017-01-17 04:44:38 +00:00
"function BinarySearchTree() {",
" this.root = null;",
" this.remove = function(value) {",
" if (this.root === null) {",
" return null;",
" }",
" var target;",
" var parent = null;",
" // find the target value and its parent",
" (function findValue(node = this.root) {",
" if (value == node.value) {",
" target = node;",
" } else if (value < node.value && node.left !== null) {",
" parent = node;",
" return findValue(node.left);",
" } else if (value < node.value && node.left === null) {",
" return null;",
" } else if (value > node.value && node.right !== null) {",
" parent = node;",
" return findValue(node.right);",
" } else {",
" return null;",
" }",
" }).bind(this)();",
" if (target === null) {",
" return null;",
" }",
" // count the children of the target to delete",
" var children = (target.left !== null ? 1 : 0) + (target.right !== null ? 1 : 0);",
" // case 1: target has no children",
" if (children === 0) {",
" if (target == this.root) {",
" this.root = null;",
" }",
" else {",
" if (parent.left == target) {",
" parent.left = null;",
" } else {",
" parent.right = null;",
" }",
" }",
" }",
" // case 2: target has one child, change code below this line",
" };",
2017-02-25 13:59:02 +00:00
"}"
2017-01-17 04:44:38 +00:00
],
"tests": [
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() }; return (typeof test == 'object')})(), 'message: The <code>BinarySearchTree</code> data structure exists.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; return (typeof test.remove == 'function')})(), 'message: The binary search tree has a method called <code>remove</code>.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.remove !== 'function') { return false; }; return (test.remove(100) == null); })(), 'message: Trying to remove an element that does not exist returns <code>null</code>.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.remove !== 'function') { return false; }; test.add(500); test.remove(500); return (test.inorder() == null); })(), 'message: If the root node has no children, deleting it sets the root to <code>null</code>.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.remove !== 'function') { return false; }; test.add(5); test.add(3); test.add(7); test.add(6); test.add(10); test.add(12); test.remove(3); test.remove(12); test.remove(10); return (test.inorder().join('') == '567'); })(), 'message: The <code>remove</code> method removes leaf nodes from the tree');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.remove !== 'function') { return false; }; test.add(-1); test.add(3); test.add(7); test.add(16); test.remove(16); test.remove(7); test.remove(3); return (test.inorder().join('') == '-1'); })(), 'message: The <code>remove</code> method removes nodes with one child.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.remove !== 'function') { return false; }; test.add(15); test.add(27); test.remove(15); return (test.inorder().join('') == '27'); })(), 'message: Removing the root in a tree with two nodes sets the second to be the root.');"
],
2017-01-17 04:44:38 +00:00
"tail": [
"BinarySearchTree.prototype = {",
" add: function(value) {",
" var node = this.root;",
2017-01-17 04:44:38 +00:00
" if (node == null) {",
" this.root = new Node(value);",
" return;",
" } else {",
" function searchTree(node) {",
" if (value < node.value) {",
" if (node.left == null) {",
" node.left = new Node(value);",
" return;",
" } else if (node.left != null) {",
" return searchTree(node.left)",
" };",
" } else if (value > node.value) {",
" if (node.right == null) {",
" node.right = new Node(value);",
" return;",
" } else if (node.right != null) {",
" return searchTree(node.right);",
" };",
" } else {",
" return null;",
" };",
" };",
" return searchTree(node);",
" };",
" },",
" inorder: function() {",
" if (this.root == null) {",
" return null;",
" } else {",
" var result = new Array();",
" function traverseInOrder(node) {",
" if (node.left != null) {",
" traverseInOrder(node.left);",
" };",
" result.push(node.value);",
" if (node.right != null) {",
" traverseInOrder(node.right);",
" };",
" }",
" traverseInOrder(this.root);",
" return result;",
" };",
" }, ",
" isBinarySearchTree() {",
" if (this.root == null) {",
" return null;",
" } else {",
" var check = true;",
" function checkTree(node) {",
" if (node.left != null) {",
" var left = node.left;",
" if (left.value > node.value) {",
" check = false;",
" } else {",
" checkTree(left);",
" }",
" }",
" if (node.right != null) {",
" var right = node.right;",
" if (right.value < node.value) {",
" check = false;",
" } else {",
" checkTree(right);",
" };",
" };",
" };",
" checkTree(this.root);",
" return check;",
" }",
2017-01-17 04:44:38 +00:00
" }",
"};"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
2017-01-17 04:44:38 +00:00
"solutions": [],
"challengeType": 1,
2017-01-17 04:44:38 +00:00
"translations": {}
},
{
"id": "587d8258367417b2b2512c82",
"title": "Delete a Node with Two Children in a Binary Search Tree",
2017-01-17 04:44:38 +00:00
"description": [
"Removing nodes that have two children is the hardest case to implement. Removing a node like this produces two subtrees that are no longer connected to the original tree structure. How can we reconnect them? One method is to find the smallest value in the right subtree of the target node and replace the target node with this value. Selecting the replacement in this way ensures that it is greater than every node in the left subtree it becomes the new parent of but also less than every node in the right subtree it becomes the new parent of.",
"Once this replacement is made the replacement node must be removed from the right subtree. Even this operation is tricky because the replacement may be a leaf or it may itself be the parent of a right subtree. If it is a leaf we must remove its parent's reference to it. Otherwise, it must be the right child of the target. In this case, we must replace the target value with the replacement value and make the target reference the replacement's right child.",
"Instructions: Let's finish our <code>remove</code> method by handling the third case. We've provided some code again for the first two cases. Add some code now to handle target nodes with two children. Any edge cases to be aware of? What if the tree has only three nodes? Once you are finished this will complete our deletion operation for binary search trees. Nice job, this is a pretty hard problem!"
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"var displayTree = (tree) => console.log(JSON.stringify(tree, null, 2));",
"function Node(value) {",
" this.value = value;",
" this.left = null;",
" this.right = null;",
2017-02-25 13:59:02 +00:00
"}",
"",
"function BinarySearchTree() {",
" this.root = null;",
" this.remove = function(value) {",
" if (this.root === null) {",
" return null;",
" }",
" var target;",
" var parent = null;",
" // find the target value and its parent",
" (function findValue(node = this.root) {",
" if (value == node.value) {",
" target = node;",
" } else if (value < node.value && node.left !== null) {",
" parent = node;",
" return findValue(node.left);",
" } else if (value < node.value && node.left === null) {",
" return null;",
" } else if (value > node.value && node.right !== null) {",
" parent = node;",
" return findValue(node.right);",
" } else {",
" return null;",
" }",
" }).bind(this)();",
" if (target === null) {",
" return null;",
" }",
" // count the children of the target to delete",
" var children = (target.left !== null ? 1 : 0) + (target.right !== null ? 1 : 0);",
" // case 1: target has no children",
" if (children === 0) {",
" if (target == this.root) {",
" this.root = null;",
" }",
" else {",
" if (parent.left == target) {",
" parent.left = null;",
" } else {",
" parent.right = null;",
" }",
" }",
" }",
" // case 2: target has one child",
" else if (children == 1) {",
" var newChild = (target.left !== null) ? target.left : target.right;",
" if (parent === null) {",
" target.value = newChild.value;",
" target.left = null;",
" target.right = null;",
" } else if (newChild.value < parent.value) {",
" parent.left = newChild;",
" } else {",
" parent.right = newChild;",
" }",
" target = null;",
" }",
" // case 3: target has two children, change code below this line",
" };",
2017-02-25 13:59:02 +00:00
"}"
2017-01-17 04:44:38 +00:00
],
"tests": [
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() }; return (typeof test == 'object')})(), 'message: The <code>BinarySearchTree</code> data structure exists.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; return (typeof test.remove == 'function')})(), 'message: The binary search tree has a method called <code>remove</code>.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; return (typeof test.remove == 'function') ? (test.remove(100) == null) : false})(), 'message: Trying to remove an element that does not exist returns <code>null</code>.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; test.add(500); test.remove(500); return (typeof test.remove == 'function') ? (test.inorder() == null) : false})(), 'message: If the root node has no children, deleting it sets the root to <code>null</code>.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; test.add(5); test.add(3); test.add(7); test.add(6); test.add(10); test.add(12); test.remove(3); test.remove(12); test.remove(10); return (typeof test.remove == 'function') ? (test.inorder().join('') == '567') : false})(), 'message: The <code>remove</code> method removes leaf nodes from the tree');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.remove !== 'function') { return false; }; test.add(-1); test.add(3); test.add(7); test.add(16); test.remove(16); test.remove(7); test.remove(3); return (test.inorder().join('') == '-1'); })(), 'message: The <code>remove</code> method removes nodes with one child.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.remove !== 'function') { return false; }; test.add(15); test.add(27); test.remove(15); return (test.inorder().join('') == '27'); })(), 'message: Removing the root in a tree with two nodes sets the second to be the root.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.remove !== 'function') { return false; }; test.add(1); test.add(4); test.add(3); test.add(7); test.add(9); test.add(11); test.add(14); test.add(15); test.add(19); test.add(50); test.remove(9); if (!test.isBinarySearchTree()) { return false; }; test.remove(11); if (!test.isBinarySearchTree()) { return false; }; test.remove(14); if (!test.isBinarySearchTree()) { return false; }; test.remove(19); if (!test.isBinarySearchTree()) { return false; }; test.remove(3); if (!test.isBinarySearchTree()) { return false; }; test.remove(50); if (!test.isBinarySearchTree()) { return false; }; test.remove(15); if (!test.isBinarySearchTree()) { return false; }; return (test.inorder().join('') == '147'); })(), 'message: The <code>remove</code> method removes nodes with two children while maintaining the binary search tree structure.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.remove !== 'function') { return false; }; test.add(100); test.add(50); test.add(300); test.remove(100); return (test.inorder().join('') == 50300); })(), 'message: The root can be removed on a tree of three nodes.');"
2017-01-17 04:44:38 +00:00
],
"tail": [
"BinarySearchTree.prototype = {",
" add: function(value) {",
" var node = this.root;",
" if (node == null) {",
" this.root = new Node(value);",
" return;",
" } else {",
" function searchTree(node) {",
" if (value < node.value) {",
" if (node.left == null) {",
" node.left = new Node(value);",
" return;",
" } else if (node.left != null) {",
" return searchTree(node.left)",
" };",
" } else if (value > node.value) {",
" if (node.right == null) {",
" node.right = new Node(value);",
" return;",
" } else if (node.right != null) {",
" return searchTree(node.right);",
" };",
" } else {",
" return null;",
" };",
" };",
" return searchTree(node);",
" };",
" },",
" inorder: function() {",
" if (this.root == null) {",
" return null;",
" } else {",
" var result = new Array();",
" function traverseInOrder(node) {",
" if (node.left != null) {",
" traverseInOrder(node.left);",
" };",
" result.push(node.value);",
" if (node.right != null) {",
" traverseInOrder(node.right);",
" };",
" }",
" traverseInOrder(this.root);",
" return result;",
" };",
" }, ",
" isBinarySearchTree() {",
" if (this.root == null) {",
" return null;",
" } else {",
" var check = true;",
" function checkTree(node) {",
" if (node.left != null) {",
" var left = node.left;",
" if (left.value > node.value) {",
" check = false;",
" } else {",
" checkTree(left);",
" }",
" }",
" if (node.right != null) {",
" var right = node.right;",
" if (right.value < node.value) {",
" check = false;",
" } else {",
" checkTree(right);",
" };",
" };",
" };",
" checkTree(this.root);",
" return check;",
" }",
" }",
2017-01-17 04:44:38 +00:00
"};"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
2017-01-17 04:44:38 +00:00
"solutions": [],
"challengeType": 1,
2017-01-17 04:44:38 +00:00
"translations": {}
},
{
"id": "587d8259367417b2b2512c83",
"title": "Invert a Binary Tree",
2017-01-17 04:44:38 +00:00
"description": [
"Here will we create a function to invert a binary tree. Given a binary tree, we want to produce a new tree that is equivalently the mirror image of this tree. Running an inorder traversal on an inverted tree will explore the nodes in reverse order when compared to the inorder traversal of the original tree. Write a method to do this called <code>invert</code> on our binary tree. Calling this method should invert the current tree structure. Ideally, we would like to do this in-place in linear time. That is, we only visit each node once and we modify the existing tree structure as we go, without using any additional memory. Good luck!"
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"var displayTree = (tree) => console.log(JSON.stringify(tree, null, 2));",
"function Node(value) {",
" this.value = value;",
" this.left = null;",
" this.right = null;",
2017-02-25 13:59:02 +00:00
"}",
"function BinarySearchTree() {",
" this.root = null;",
" // change code below this line",
" // change code above this line",
2017-02-25 13:59:02 +00:00
"}"
2017-01-17 04:44:38 +00:00
],
"tail": [
"BinarySearchTree.prototype = {",
" add: function(value) {",
" var node = this.root;",
" if (node == null) {",
" this.root = new Node(value);",
" return;",
" } else {",
" function searchTree(node) {",
" if (value < node.value) {",
" if (node.left == null) {",
" node.left = new Node(value);",
" return;",
" } else if (node.left != null) {",
" return searchTree(node.left)",
" };",
" } else if (value > node.value) {",
" if (node.right == null) {",
" node.right = new Node(value);",
" return;",
" } else if (node.right != null) {",
" return searchTree(node.right);",
" };",
" } else {",
" return null;",
" };",
" };",
" return searchTree(node);",
" };",
" },",
" inorder: function() {",
" if (this.root == null) {",
" return null;",
" } else {",
" var result = new Array();",
" function traverseInOrder(node) {",
" if (node.left != null) {",
" traverseInOrder(node.left);",
" };",
" result.push(node.value);",
" if (node.right != null) {",
" traverseInOrder(node.right);",
" };",
" }",
" traverseInOrder(this.root);",
" return result;",
" };",
" }",
2017-01-17 04:44:38 +00:00
"};"
],
"tests": [
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() }; return (typeof test == 'object')})(), 'message: The <code>BinarySearchTree</code> data structure exists.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; return (typeof test.invert == 'function')})(), 'message: The binary search tree has a method called <code>invert</code>.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.invert !== 'function') { return false; }; test.add(4); test.add(1); test.add(7); test.add(87); test.add(34); test.add(45); test.add(73); test.add(8); test.invert(); return test.inorder().join('') == '877345348741'; })(), 'message: The <code>invert</code> method correctly inverts the tree structure.');",
"assert((function() { var test = false; if (typeof BinarySearchTree !== 'undefined') { test = new BinarySearchTree() } else { return false; }; if (typeof test.invert !== 'function') { return false; }; return (test.invert() == null); })(), 'message: Inverting an empty tree returns <code>null</code>.');"
],
2017-01-17 04:44:38 +00:00
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
2017-01-17 04:44:38 +00:00
"solutions": [],
"challengeType": 1,
2017-01-17 04:44:38 +00:00
"translations": {}
},
{
"id": "587d8259367417b2b2512c84",
"title": "Create a Trie Search Tree",
2017-01-17 04:44:38 +00:00
"description": [
"Here we will move on from binary search trees and take a look at another type of tree structure called a trie. A trie is an ordered search tree commonly used to hold strings, or more generically associative arrays or dynamic datasets in which the keys are strings. They are very good at storing sets of data when many keys will have overlapping prefixes, for example, all the words in a dictionary.",
"Unlike a binary tree, nodes are not associated with actual values. Instead, the path to a node represents a specific key. For instance, if we wanted to store the string code in a trie, we would have four nodes, one for each letter: c — o — d — e. Following that path through all these nodes will then create code as a string — that path is the key we stored. Then, if we wanted to add the string coding, it would share the first three nodes of code before branching away after the d. In this way, large datasets can be stored very compactly. In addition, search can be very quick because it is effectively limited to the length of the string you are storing. Furthermore, unlike binary trees a node can store any number of child nodes.",
"As you might have guessed from the above example, some metadata is commonly stored at nodes that hold the end of a key so that on later traversals that key can still be retrieved. For instance, if we added codes in our example above we would need some way to know that the e in code represents the end of a key that was previously entered. Otherwise, this information would effectively be lost when we add codes.",
"Instructions: Let's create a trie to store words. It will accept words through an add method and store these in a trie data structure. It will also allow us to query if a given string is a word with an isWord method, and retrieve all the words entered into the trie with a print method. isWord should return a boolean value and print should return an array of all these words as string values.",
"In order for us to verify that this data structure is implemented correctly, we've provided a Node structure for each node in the tree. Each node will be an object with a keys property which is a JavaScript Map object. This will hold the individual letters that are valid keys of each node. We've also created an end property on the nodes that can be set to true if the node represents the termination of a word."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"var displayTree = (tree) => console.log(JSON.stringify(tree, null, 2));",
"var Node = function() {",
" this.keys = new Map();",
" this.end = false;",
" this.setEnd = function() {",
" this.end = true;",
" };",
" this.isEnd = function() {",
" return this.end;",
" };",
"};",
"var Trie = function() {",
2017-01-17 04:44:38 +00:00
" // change code below this line",
" // change code above this line",
"};"
],
"tests": [
"assert((function testTrie() { var test = false; if (typeof Trie !== 'undefined') { test = new Trie() } else { return false; }; return (typeof test.add == 'function') }()), 'message: The Trie has an add method.');",
"assert((function testTrie() { var test = false; if (typeof Trie !== 'undefined') { test = new Trie() } else { return false; }; return (typeof test.print == 'function') }()), 'message: The Trie has a print method.');",
"assert((function testTrie() { var test = false; if (typeof Trie !== 'undefined') { test = new Trie() } else { return false; }; return (typeof test.isWord == 'function') }()), 'message: The Trie has an isWord method.');",
"assert((function testTrie() { var test = false; if (typeof Trie !== 'undefined') { test = new Trie() } else { return false; }; test.add('jump'); test.add('jumps'); test.add('jumped'); test.add('house'); test.add('mouse'); var added = test.print(); return (added.indexOf('jump') != -1 && added.indexOf('jumps') != -1 && added.indexOf('jumped') != -1 && added.indexOf('house') != -1 && added.indexOf('mouse') != -1 && added.length == 5); }()), 'message: The print method returns all items added to the trie as strings in an array.');",
"assert((function testTrie() { var test = false; if (typeof Trie !== 'undefined') { test = new Trie() } else { return false; }; test.add('hop'); test.add('hops'); test.add('hopped'); test.add('hoppy'); test.add('hope'); return (test.isWord('hop') && !test.isWord('ho') && test.isWord('hopped') && !test.isWord('hopp') && test.isWord('hoppy') && !test.isWord('hoping')); }()), 'message: The isWord method returns true only for words added to the trie and false for all other words.');"
2017-01-17 04:44:38 +00:00
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
2017-01-17 04:44:38 +00:00
"solutions": [],
"challengeType": 1,
2017-01-17 04:44:38 +00:00
"translations": {}
},
{
"id": "587d825a367417b2b2512c8a",
"title": "Insert an Element into a Max Heap",
"description": [
"Now we will move on to another tree data structure, the binary heap. A binary heap is a partially ordered binary tree which satisfies the heap property. The heap property specifies a relationship between parent and child nodes. You may have a max heap, in which all parent nodes are greater than or equal to their child nodes, or a min heap, in which the reverse is true. Binary heaps are also complete binary trees. This means that all levels of the tree are fully filled and if the last level is partially filled it is filled from left to right.",
"While binary heaps may be implemented as tree structures with nodes that contain left and right references, the partial ordering according to the heap property allows us to represent the heap with an array. The parent-children relationship is what we're interested in and with simple arithmetic we can compute the children of any parent and the parent of any child node.",
"For instance, consider this array representation of a binary min heap:",
"<code>[ 6, 22, 30, 37, 63, 48, 42, 76 ]</code>",
"The root node is the first element, 6. Its children are 22 and 30. If we look at the relationship between the array indices of these values, for index i the children are 2 * i + 1 and 2 * i + 2. Similarly, the element at index 0 is the parent of these two children at indices 1 and 2. More generally, we can find the parent of a node at any index with the following: (i - 1) / 2. These patterns will hold true as the binary tree grows to any size. Finally, we can make a slight adjustment to make this arithmetic even easier by skipping the first element in the array. Doing this creates the following relationship for any element at a given index i:",
"Example Array representation:",
"<code>[ null, 6, 22, 30, 37, 63, 48, 42, 76 ]</code>",
2017-01-17 04:44:38 +00:00
"An element's left child: i * 2",
"An element's right child: i * 2 + 1",
"An element's parent: i / 2",
"Once you wrap your head around the math, using an array representation is very useful because node locations can be quickly determined with this arithmetic and memory usage is diminished because you don't need to maintain references to child nodes.",
"Instructions: Here we will create a max heap. Start by just creating an insert method which adds elements to our heap. During insertion, it is important to always maintain the heap property. For a max heap this means the root element should always have the greatest value in the tree and all parent nodes should be greater than their children. For an array implementation of a heap, this is typically accomplished in three steps:",
"Add the new element to the end of the array.",
"If the element is larger than its parents, switch them.",
"Continue switching until the new element is either smaller than its parent or you reach the root of the tree.",
"Finally, add a print method which returns an array of all the items that have been added to the heap."
],
"challengeSeed": [
"var MaxHeap = function() {",
2017-01-17 04:44:38 +00:00
" // change code below this line",
" // change code above this line",
"};"
],
"tests": [
"assert((function() { var test = false; if (typeof MaxHeap !== 'undefined') { test = new MaxHeap() }; return (typeof test == 'object')})(), 'message: The MaxHeap data structure exists.');",
"assert((function() { var test = false; if (typeof MaxHeap !== 'undefined') { test = new MaxHeap() } else { return false; }; return (typeof test.insert == 'function')})(), 'message: MaxHeap has a method called insert.');",
"assert((function() { var test = false; if (typeof MaxHeap !== 'undefined') { test = new MaxHeap() } else { return false; }; return (typeof test.print == 'function')})(), 'message: MaxHeap has a method called print.');",
"assert((function() { var test = false; if (typeof MaxHeap !== 'undefined') { test = new MaxHeap() } else { return false; }; test.insert(50); test.insert(100); test.insert(700); test.insert(32); test.insert(51); let result = test.print(); return ((result.length == 5) ? result[0] == 700 : result[1] == 700) })(), 'message: The insert method adds elements according to the max heap property.');"
2017-01-17 04:44:38 +00:00
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
2017-01-17 04:44:38 +00:00
"solutions": [],
"challengeType": 1,
2017-01-17 04:44:38 +00:00
"translations": {}
},
{
"id": "587d825b367417b2b2512c8b",
"title": "Remove an Element from a Max Heap",
"description": [
"Now that we can add elements to our heap let's see how we can remove elements. Removing and inserting elements both require similar logic. In a max heap you will usually want to remove the greatest value, so this involves simply extracting it from the root of our tree. This will break the heap property of our tree, so we must reestablish it in some way. Typically, for a max heap this is done in the following way:",
"Move the last element in the heap into the root position.",
"If either child of the root is greater than it, swap the root with the child of greater value.",
"Continue swapping until the parent is greater than both children, or you reach the last level in the tree.",
"Instructions: Add a method to our max heap called remove. This method should return the greatest value that has been added to our max heap and remove it from the heap. It should also reorder the heap so the heap property is maintained. After removing an element, the next greatest element remaining in the heap should become the root. Add your insert method again here as well."
],
"challengeSeed": [
"var MaxHeap = function() {",
2017-01-17 04:44:38 +00:00
" // change code below this line",
" // change code above this line",
"};"
],
"tests": [
"assert((function() { var test = false; if (typeof MaxHeap !== 'undefined') { test = new MaxHeap() }; return (typeof test == 'object')})(), 'message: The MaxHeap data structure exists.');",
"assert((function() { var test = false; if (typeof MaxHeap !== 'undefined') { test = new MaxHeap() } else { return false; }; return (typeof test.print == 'function')})(), 'message: MaxHeap has a method called print.');",
"assert((function() { var test = false; if (typeof MaxHeap !== 'undefined') { test = new MaxHeap() } else { return false; }; return (typeof test.insert == 'function')})(), 'message: MaxHeap has a method called insert.');",
"assert((function() { var test = false; if (typeof MaxHeap !== 'undefined') { test = new MaxHeap() } else { return false; }; return (typeof test.remove == 'function')})(), 'message: MaxHeap has a method called remove.');",
"assert((function() { var test = false; if (typeof MaxHeap !== 'undefined') { test = new MaxHeap() } else { return false; }; test.insert(30); test.insert(300); test.insert(500); test.insert(10); let result = []; result.push(test.remove()); result.push(test.remove()); result.push(test.remove()); result.push(test.remove()); return (result.join('') == '5003003010') })(), 'message: The remove method removes the greatest element from the max heap while maintaining the max heap property.');"
2017-01-17 04:44:38 +00:00
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
2017-01-17 04:44:38 +00:00
"solutions": [],
"challengeType": 1,
2017-01-17 04:44:38 +00:00
"translations": {}
},
{
"id": "587d825b367417b2b2512c8c",
"title": "Implement Heap Sort with a Min Heap",
"description": [
"Now that we can add and remove elements let's see some of the applications heaps can be used for. Heaps are commonly used to implement priority queues because they always store an item of greatest or least value in first position. In addition, they are used to implement a sorting algorithm called heap sort. We'll see how to do this here. Heap sort uses a min heap, the reverse of a max heap. A min heap always stores the element of least value in the root position.",
"Heap sort works by taking an unsorted array, adding each item in the array into a min heap, and then extracting every item out of the min heap into a new array. The min heap structure ensures that the new array will contain the original items in least to greatest order. This is one of the most efficient sorting algorithms with average and worst case performance of O(nlog(n)).",
"Instructions: Let's implement heap sort with a min heap. Feel free to adapt your max heap code here. Create an object MinHeap with insert, remove, and sort methods. The sort method should return an array of all the elements in the min heap sorted from smallest to largest."
],
"challengeSeed": [
"// check if array is sorted",
"function isSorted(arr) {",
" var check = (i) => (i == arr.length - 1) ? true : (arr[i] > arr[i + 1]) ? false : check(i + 1);",
2017-01-17 04:44:38 +00:00
" return check(0);",
2017-02-25 13:59:02 +00:00
"}",
2017-01-17 04:44:38 +00:00
"// generate a randomly filled array",
"var array = new Array();",
2017-01-17 04:44:38 +00:00
"(function createArray(size = 5) {",
" array.push(+(Math.random() * 100).toFixed(0));",
" return (size > 1) ? createArray(size - 1) : undefined;",
"})(25);",
"var MinHeap = function() {",
2017-01-17 04:44:38 +00:00
" // change code below this line",
" // change code above this line",
"};"
],
"tests": [
"assert((function() { var test = false; if (typeof MinHeap !== 'undefined') { test = new MinHeap() }; return (typeof test == 'object')})(), 'message: The MinHeap data structure exists.');",
"assert((function() { var test = false; if (typeof MinHeap !== 'undefined') { test = new MinHeap() } else { return false; }; return (typeof test.insert == 'function')})(), 'message: MinHeap has a method called insert.');",
"assert((function() { var test = false; if (typeof MinHeap !== 'undefined') { test = new MinHeap() } else { return false; }; return (typeof test.remove == 'function')})(), 'message: MinHeap has a method called remove.');",
"assert((function() { var test = false; if (typeof MinHeap !== 'undefined') { test = new MinHeap() } else { return false; }; return (typeof test.sort == 'function')})(), 'message: MinHeap has a method called sort.');",
"assert((function() { var test = false; if (typeof MinHeap !== 'undefined') { test = new MinHeap() } else { return false; }; test.insert(3); test.insert(12); test.insert(5); test.insert(10); test.insert(1); test.insert(27); test.insert(42); test.insert(57); test.insert(5); var result = test.sort(); return (isSorted(result)); })(), 'message: The sort method returns an array containing all items added to the min heap in sorted order.');"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [],
"challengeType": 1,
"translations": {}
},
{
"id": "587d8255367417b2b2512c76",
"title": "Introduction to Graphs",
"description": [
[
"https://i.stack.imgur.com/XfuFe.gif",
"Picture of an X-Y coordinate graph seen in typical math classes",
"This challenge starts a series of challenges that will teach graph data structures and some algorithms involving graphs. You may be familiar with graphs with an x- and y-axis found in your math classes. However, here graphs mean a different thing.",
""
],
[
"https://upload.wikimedia.org/wikipedia/commons/5/5b/6n-graf.svg",
"Figure of undirected network with 6 nodes",
"The data structure of <dfn>graphs</dfn> are collections of things and the relationships or connections among them. Graphs are also known as networks.<br><br>When talking about graphs, the precise term for \"objects\" are <dfn>nodes</dfn> or <dfn>vertices</dfn>. Similarly, the precise term for \"connections\" is <dfn>edges</dfn>.",
""
],
[
"https://upload.wikimedia.org/wikipedia/commons/b/b6/Moreno_Sociogram_2nd_Grade.png",
"Figure of psychologist Moreno's social network of a 2nd grade class",
"One example of graphs is a social network where the <dfn>nodes</dfn> are you and other people, and the edges are whether two people are friends with each other.",
""
],
[
"https://i.stack.imgur.com/5xkVt.png",
"Figures of directed graphs with arrows on edges while undirected graphs do not have directions on edges",
"There are two major types of graphs: <dfn>directed</dfn> and <dfn>undirected</dfn>. Undirected graphs are graphs without any direction on the edges between nodes. Directed graphs, in contrast, are graphs with a direction in its edges.<br><br>An example of an undirected graph could be a social network. The nodes are people and the edges are friendship. An example of a directed network could be the internet and web page links. Here, the nodes are web pages and the directed edges are links to other pages, which might not necessarily point the other way.",
""
]
],
"challengeSeed": [],
"tests": [],
2017-01-17 04:44:38 +00:00
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
2017-01-17 04:44:38 +00:00
"solutions": [],
"challengeType": 7,
2017-01-17 04:44:38 +00:00
"translations": {}
},
{
"id": "587d8256367417b2b2512c77",
"title": "Adjacency List",
2017-01-17 04:44:38 +00:00
"description": [
"Graphs can be represented in different ways. Here we describe one way, which is called an <dfn>adjacency list</dfn>.",
"An adjacency list is essentially a bulleted list where the left side is the node and the right side lists all the other nodes it's connected to. Below is a representation of an adjacency list.",
"<blockquote>Node1: Node2, Node3<br>Node2: Node1<br>Node3: Node1</blockquote>",
"Above is an undirected graph because <code>Node1</code> is connected to <code>Node2</code> and <code>Node3</code>, and that information is consistent with the connections <code>Node2</code> and <code>Node3</code> show. An adjacency list for a directed graph would mean each row of the list shows direction. If the above was directed, then <code>Node2: Node1</code> would mean there the directed edge is pointing from <code>Node2</code> towards <code>Node1</code>.",
"We can represent the undirected graph above as an adjacency list by putting it within a JavaScript object.",
2017-07-11 01:25:26 +00:00
"<blockquote>var undirectedG = {<br> Node1: [\"Node2\", \"Node3\"],<br> Node2: [\"Node1\"],<br> Node3: [\"Node1\"]<br>};</blockquote>",
"This can also be more simply represented as an array where the nodes just have numbers rather than string labels.",
2017-07-11 01:25:26 +00:00
"<blockquote>var undirectedGArr = [<br> [1, 2], # Node1<br> [0], # Node2<br> [0] # Node3<br>];</blockquote>",
"<hr>",
"Create a social network as an undirected graph with 4 nodes/people named <code>James</code>, <code>Jill</code>, <code>Jenny</code>, and <code>Jeff</code>. There are edges/relationships between James and Jeff, Jill and Jenny, and Jeff and Jenny."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"var undirectedAdjList = {",
"};"
2017-01-17 04:44:38 +00:00
],
"tests": [
"assert(Object.keys(undirectedAdjList).length === 4, 'message: <code>undirectedAdjList</code> should only contain four nodes.');",
2017-02-20 20:42:50 +00:00
"assert(undirectedAdjList.James.indexOf(\"Jeff\") !== -1 && undirectedAdjList.Jeff.indexOf(\"James\") !== -1, 'message: There should be an edge between <code>Jeff</code> and <code>James</code>.');",
"assert(undirectedAdjList.Jill.indexOf(\"Jenny\") !== -1 && undirectedAdjList.Jill.indexOf(\"Jenny\") !== -1, 'message: There should be an edge between <code>Jill</code> and <code>Jenny</code>.');",
"assert(undirectedAdjList.Jeff.indexOf(\"Jenny\") !== -1 && undirectedAdjList.Jenny.indexOf(\"Jeff\") !== -1, 'message: There should be an edge between <code>Jeff</code> and <code>Jenny</code>.');"
2017-01-17 04:44:38 +00:00
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [
"var undirectedAdjList = {\n\"James\": [\"Jeff\"],\"Jill\": [\"Jenny\"],\"Jenny\": [\"Jill\", \"Jeff\"],\n\"Jeff\": [\"James\", \"Jenny\"]\n};"
],
"challengeType": 1,
2017-01-17 04:44:38 +00:00
"translations": {}
},
{
"id": "587d8256367417b2b2512c78",
"title": "Adjacency Matrix",
2017-01-17 04:44:38 +00:00
"description": [
"Another way to represent a graph is to put it in an <dfn>adjacency matrix</dfn>.",
"An <dfn>adjacency matrix</dfn> is a two-dimensional (2D) array where each nested array has the same number of elements as the outer array. In other words, it is a matrix or grid of numbers, where the numbers represent the edges. Zeros mean there is no edge or relationship.",
"<blockquote> 1 2 3<br> ------<br>1 | 0 1 1<br>2 | 1 0 0<br>3 | 1 0 0</blockquote>",
"Above is a very simple, undirected graph where you have three nodes, where the first node is connected to the second and third node. <strong>Note</strong>: The numbers to the top and left of the matrix are just labels for the nodes.",
"Below is a JavaScript implementation of the same thing.",
"<blockquote>var adjMat = [<br> [0, 1, 1],<br> [1, 0, 0],<br> [1, 0, 0]<br>];</blockquote>",
"Unlike an adjacency list, each \"row\" of the matrix has to have the same number of elements as nodes in the graph. Here we have a three by three matrix, which means we have three nodes in our graph.",
"A directed graph would look similar. Below is a graph where the first node has an edge pointing toward the second node, and then the second node has an edge pointing to the third node.",
"<blockquote>var adjMatDirected = [<br> [0, 1, 0],<br> [0, 0, 1],<br> [0, 0, 0]<br>];</blockquote>",
"Graphs can also have <dfn>weights</dfn> on their edges. So far, we have <dfn>unweighted</dfn> edges where just the presence and lack of edge is binary (<code>0</code> or <code>1</code>). You can have different weights depending on your application.",
"<hr>",
"Create an adjacency matrix of an undirected graph with five nodes. This matrix should be in a multi-dimensional array. These five nodes have relationships between the first and fourth node, the first and third node, the third and fifth node, and the fourth and fifth node. All edge weights are one."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"var adjMatUndirected = [",
"];"
2017-01-17 04:44:38 +00:00
],
"tests": [
"assert((adjMatUndirected.length === 5) && adjMatUndirected.map(function(x) { return x.length === 5 }).reduce(function(a, b) { return a && b }) , 'message: <code>undirectedAdjList</code> should only contain five nodes.');",
"assert((adjMatUndirected[0][3] === 1) && (adjMatUndirected[3][0] === 1), 'message: There should be an edge between the first and fourth node.');",
"assert((adjMatUndirected[0][2] === 1) && (adjMatUndirected[2][0] === 1), 'message: There should be an edge between the first and third node.');",
"assert((adjMatUndirected[2][4] === 1) && (adjMatUndirected[4][2] === 1), 'message: There should be an edge between the third and fifth node.');",
"assert((adjMatUndirected[3][4] === 1) && (adjMatUndirected[4][3] === 1), 'message: There should be an edge between the fourth and fifth node.');"
2017-01-17 04:44:38 +00:00
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [
"var adjMatUndirected = [[0, 0, 1, 1, 0],[0, 0, 0, 0, 0],[1, 0, 0, 0, 1],[1, 0, 0, 0, 1],[0, 0, 1, 1, 0]];"
],
"challengeType": 1,
2017-01-17 04:44:38 +00:00
"translations": {}
},
{
"id": "587d8256367417b2b2512c79",
"title": "Incidence Matrix",
2017-01-17 04:44:38 +00:00
"description": [
"Yet another way to represent a graph is to put it in an <dfn>incidence matrix.</dfn>",
"An <dfn>incidence matrix</dfn> is a two-dimensional (2D) array. Generally speaking, an incidence matrix relates two different classes of objects between its two dimensions. This kind of matrix is similar to an adjacency matrix. However, the rows and columns mean something else here.",
"In graphs, we have edges and nodes. These will be our \"two different classes of objects\". This matrix will have the rows be the nodes and columns be the edges. This means that we can have an uneven number of rows and columns.",
"Each column will represent a unique edge. Also, each edge connects two nodes. To show that there is an edge between two nodes, you will put a 1 in the two rows of a particular column. Below is a 3 node graph with one edge between node 1 and node 3.",
"<blockquote> 1<br> ---<br>1 | 1<br>2 | 0<br>3 | 1</blockquote>",
"Here is an example of an <code>incidence matrix</code> with 4 edges and 4 nodes. Remember, the columns are the edges and rows are the nodes themselves.",
"<blockquote> 1 2 3 4<br> --------<br>1 | 0 1 1 1<br>2 | 1 1 0 0<br>3 | 1 0 0 1<br>4 | 0 0 1 0</blockquote>",
"Below is a JavaScript implementation of the same thing.",
"<blockquote>var incMat = [<br> [0, 1, 1, 1],<br> [1, 1, 0, 0],<br> [1, 0, 0, 1],<br> [0, 0, 1, 0]<br>];</blockquote>",
"To make a directed graph, use <code>-1</code> for an edge leaving a particular node and <code>1</code> for an edge entering a node.",
"<blockquote>var incMatDirected = [<br> [ 0, -1, 1, -1],<br> [-1, 1, 0, 0],<br> [ 1, 0, 0, 1],<br> [ 0, 0, -1, 0]<br>];</blockquote>",
"Graphs can also have <dfn>weights</dfn> on their edges. So far, we have <dfn>unweighted</dfn> edges where just the presence and lack of edge is binary (<code>0</code> or <code>1</code>). You can have different weights depending on your application. A different weight is represented as numbers greater than 1.",
"<hr>",
"Create an incidence matrix of an undirected graph with five nodes and four edges. This matrix should be in a multi-dimensional array.",
"These five nodes have relationships following relationships. The first edge is between the first and second node. The second edge is between the second and third node. The third edge is between the third and fifth node. And four edge is between the fourth and second node. All edge weights are one and the edge order matters."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"var incMatUndirected = [",
" ",
"];"
2017-01-17 04:44:38 +00:00
],
"tests": [
"assert((incMatUndirected.length === 5) && incMatUndirected.map(function(x) { return x.length === 4 }).reduce(function(a, b) { return a && b }) , 'message: <code>incMatUndirected</code> should only contain five nodes.');",
"assert((incMatUndirected[0][0] === 1) && (incMatUndirected[1][0] === 1), 'message: There should be a first edge between the first and second node.');",
"assert((incMatUndirected[1][1] === 1) && (incMatUndirected[2][1] === 1), 'message: There should be a second edge between the second and third node.');",
"assert((incMatUndirected[2][2] === 1) && (incMatUndirected[4][2] === 1), 'message: There should be a third edge between the third and fifth node.');",
"assert((incMatUndirected[1][3] === 1) && (incMatUndirected[3][3] === 1), 'message: There should be a fourth edge between the second and fourth node.');"
2017-01-17 04:44:38 +00:00
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [
"var incMatUndirected = [[1, 0, 0, 0],[1, 1, 0, 1],[0, 1, 1, 0],[0, 0, 0, 1],[0, 0, 1, 0]];"
],
"challengeType": 1,
2017-01-17 04:44:38 +00:00
"translations": {}
},
{
"id": "587d825c367417b2b2512c90",
"title": "Breadth-First Search",
"description": [
"So far, we've learned different ways of creating representations of graphs. What now? One natural question to have is what are the distances between any two nodes in the graph? Enter <dfn>graph traversal algorithms</dfn>.",
"<dfn>Traversal algorithms</dfn> are algorithms to traverse or visit nodes in a graph. One type of traversal algorithm is the breadth-first search algorithm.",
2017-01-17 04:44:38 +00:00
"This algorithm starts at one node, first visits all its neighbors that are one edge away, then goes on to visiting each of their neighbors.",
"Visually, this is what the algorithm is doing.",
"<img class='img-responsive' src='https://camo.githubusercontent.com/2f57e6239884a1a03402912f13c49555dec76d06/68747470733a2f2f75706c6f61642e77696b696d656469612e6f72672f77696b6970656469612f636f6d6d6f6e732f342f34362f416e696d617465645f4246532e676966'>",
2017-01-17 04:44:38 +00:00
"To implement this algorithm, you'll need to input a graph structure and a node you want to start at.",
"First, you'll want to be aware of the distances from the start node. This you'll want to start all your distances initially some large number, like <code>Infinity</code>. This gives a reference for the case where a node may not be reachable from your start node.",
2017-01-17 04:44:38 +00:00
"Next, you'll want to go from the start node to its neighbors. These neighbors are one edge away and at this point you should add one unit of distance to the distances you're keeping track of.",
"Last, an important data structure that will help implement the breadth-first search algorithm is the queue. This is an array where you can add elements to one end and remove elements from the other end. This is also known as a <dfn>FIFO</dfn> or <dfn>First-In-First-Out</dfn> data structure.",
"<hr>",
"Write a function <code>bfs()</code> that takes an adjacency matrix graph (a two-dimensional array) and a node label root as parameters. The node label will just be the integer value of the node between <code>0</code> and <code>n - 1</code>, where <code>n</code> is the total number of nodes in the graph.",
"Your function will output a JavaScript object key-value pairs with the node and its distance from the root. If the node could not be reached, it should have a distance of <code>Infinity</code>."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"function bfs(graph, root) {",
" // Distance object returned",
" var nodesLen = {};",
" ",
" return nodesLen;",
2017-02-25 13:59:02 +00:00
"};",
"",
2017-01-17 04:44:38 +00:00
"var exBFSGraph = [",
" [0, 1, 0, 0],",
" [1, 0, 1, 0],",
" [0, 1, 0, 1],",
" [0, 0, 1, 0]",
"];",
"console.log(bfs(exBFSGraph, 3));"
],
"tests": [
"assert((function() { var graph = [[0, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 1], [0, 0, 1, 0]]; var results = bfs(graph, 1); return isEquivalent(results, {0: 1, 1: 0, 2: 1, 3: 2})})(), 'message: The input graph <code>[[0, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 1], [0, 0, 1, 0]]</code> with a start node of <code>1</code> should return <code>{0: 1, 1: 0, 2: 1, 3: 2}</code>');",
"assert((function() { var graph = [[0, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 0]]; var results = bfs(graph, 1); return isEquivalent(results, {0: 1, 1: 0, 2: 1, 3: Infinity})})(), 'message: The input graph <code>[[0, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 0]]</code> with a start node of <code>1</code> should return <code>{0: 1, 1: 0, 2: 1, 3: Infinity}</code>');",
2017-01-17 04:44:38 +00:00
"assert((function() { var graph = [[0, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 1], [0, 0, 1, 0]]; var results = bfs(graph, 0); return isEquivalent(results, {0: 0, 1: 1, 2: 2, 3: 3})})(), 'message: The input graph <code>[[0, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 1], [0, 0, 1, 0]]</code> with a start node of <code>0</code> should return <code>{0: 0, 1: 1, 2: 2, 3: 3}</code>');",
"assert((function() { var graph = [[0, 1], [1, 0]]; var results = bfs(graph, 0); return isEquivalent(results, {0: 0, 1: 1})})(), 'message: The input graph <code>[[0, 1], [1, 0]]</code> with a start node of <code>0</code> should return <code>{0: 0, 1: 1}</code>');"
],
"tail": [
"// Source: http://adripofjavascript.com/blog/drips/object-equality-in-javascript.html",
"function isEquivalent(a, b) {",
" // Create arrays of property names",
" var aProps = Object.getOwnPropertyNames(a);",
" var bProps = Object.getOwnPropertyNames(b);",
" // If number of properties is different,",
" // objects are not equivalent",
" if (aProps.length != bProps.length) {",
" return false;",
" }",
" for (var i = 0; i < aProps.length; i++) {",
" var propName = aProps[i];",
" // If values of same property are not equal,",
" // objects are not equivalent",
" if (a[propName] !== b[propName]) {",
" return false;",
" }",
" }",
" // If we made it this far, objects",
" // are considered equivalent",
" return true;",
"}"
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [
"function bfs(graph, root) {\n// Distance object returned\nvar nodesLen = {};\n// Set all distances to infinity\nfor (var i = 0; i < graph.length; i++) {\nnodesLen[i] = Infinity;\n}\nnodesLen[root] = 0; // ...except root node\nvar queue = [root]; // Keep track of nodes to visit\nvar current; // Current node traversing\n// Keep on going until no more nodes to traverse\nwhile (queue.length !== 0) {\ncurrent = queue.shift();\n// Get adjacent nodes from current node\nvar curConnected = graph[current]; // Get layer of edges from current\nvar neighborIdx = []; // List of nodes with edges\nvar idx = curConnected.indexOf(1); // Get first edge connection\nwhile (idx !== -1) {\nneighborIdx.push(idx); // Add to list of neighbors\nidx = curConnected.indexOf(1, idx + 1); // Keep on searching\n}\n// Loop through neighbors and get lengths\nfor (var j = 0; j < neighborIdx.length; j++) {\n// Increment distance for nodes traversed\nif (nodesLen[neighborIdx[j]] === Infinity) {\nnodesLen[neighborIdx[j]] = nodesLen[current] + 1;\nqueue.push(neighborIdx[j]); // Add new neighbors to queue\n}\n}\n}\nreturn nodesLen;}"
],
"challengeType": 1,
2017-01-17 04:44:38 +00:00
"translations": {}
},
{
"id": "587d825d367417b2b2512c96",
"title": "Depth-First Search",
"description": [
"Similar to <dfn>breadth-first search</dfn>, here we will learn about another graph traversal algorithm called <dfn>depth-first search</dfn>.",
"Whereas the breadth-first search searches incremental edge lengths away from the source node, <dfn>depth-first search</dfn> first goes down a path of edges as far as it can.",
2017-01-17 04:44:38 +00:00
"Once it reaches one end of a path, the search will backtrack to the last node with an un-visited edge path and continue searching.",
"Visually, this is what the algorithm is doing where the top node is the starting point of the search.",
"<img class='img-responsive' src='https://camo.githubusercontent.com/aaad9e39961daf34d967c616edeb50abf3bf1235/68747470733a2f2f75706c6f61642e77696b696d656469612e6f72672f77696b6970656469612f636f6d6d6f6e732f372f37662f44657074682d46697273742d5365617263682e676966'>",
2017-01-17 04:44:38 +00:00
"A simple output of this algorithm is a list of nodes which are reachable from a given node. So when implementing this algorithm, you'll need to keep track of the nodes you visit.",
"<hr>",
"Write a function <code>dfs()</code> that takes an undirected, adjacency matrix <code>graph</code> and a node label <code>root</code> as parameters. The node label will just be the numeric value of the node between <code>0</code> and <code>n - 1</code>, where <code>n</code> is the total number of nodes in the graph.",
"Your function should output an array of all nodes reachable from <code>root</code>."
2017-01-17 04:44:38 +00:00
],
"challengeSeed": [
"function dfs(graph, root) {",
" ",
"}",
"",
2017-01-17 04:44:38 +00:00
"var exDFSGraph = [",
" [0, 1, 0, 0],",
" [1, 0, 1, 0],",
" [0, 1, 0, 1],",
" [0, 0, 1, 0]",
"];",
"console.log(dfs(exDFSGraph, 3));"
],
"tests": [
"assert.sameMembers((function() { var graph = [[0, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 1], [0, 0, 1, 0]]; return dfs(graph, 1);})(), [0, 1, 2, 3], 'message: The input graph <code>[[0, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 1], [0, 0, 1, 0]]</code> with a start node of <code>1</code> should return an array with <code>0</code>, <code>1</code>, <code>2</code>, and <code>3</code>.');",
"assert((function() { var graph = [[0, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 1], [0, 0, 1, 0]]; return dfs(graph, 1);})().length === 4, 'message: The input graph <code>[[0, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 1], [0, 0, 1, 0]]</code> with a start node of <code>1</code> should return an array with four elements.');",
"assert.sameMembers((function() { var graph = [[0, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 0]]; return dfs(graph, 3);})(), [3], 'message: The input graph <code>[[0, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 0]]</code> with a start node of <code>3</code> should return an array with <code>3</code>.');",
"assert((function() { var graph = [[0, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 0]]; return dfs(graph, 3);})().length === 1, 'message: The input graph <code>[[0, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 0]]</code> with a start node of <code>3</code> should return an array with one element.');",
"assert.sameMembers((function() { var graph = [[0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]; return dfs(graph, 3);})(), [2, 3], 'message: The input graph <code>[[0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]</code> with a start node of <code>3</code> should return an array with <code>2</code> and <code>3</code>.');",
"assert((function() { var graph = [[0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]; return dfs(graph, 3);})().length === 2, 'message: The input graph <code>[[0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]</code> with a start node of <code>3</code> should return an array with two elements.');",
"assert.sameMembers((function() { var graph = [[0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]; return dfs(graph, 0);})(), [0, 1], 'message: The input graph <code>[[0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]</code> with a start node of <code>0</code> should return an array with <code>0</code> and <code>1</code>.');",
"assert((function() { var graph = [[0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]; return dfs(graph, 0);})().length === 2, 'message: The input graph <code>[[0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]</code> with a start node of <code>0</code> should return an array with two elements.');"
2017-01-17 04:44:38 +00:00
],
"type": "waypoint",
"releasedOn": "Feb 17, 2017",
"solutions": [
"function dfs(graph, root) { var stack = []; var tempV; var visited = []; var tempVNeighbors = []; stack.push(root); while (stack.length > 0) { tempV = stack.pop(); if (visited.indexOf(tempV) == -1) { visited.push(tempV); tempVNeighbors = graph[tempV]; for (var i = 0; i < tempVNeighbors.length; i++) { if (tempVNeighbors[i] == 1) { stack.push(i); }}}} return visited;}"
],
"challengeType": 1,
2017-01-17 04:44:38 +00:00
"translations": {}
}
]
}