├── LICENSE.txt
└── README.md
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Kenny Chan
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Interview Algorithm Questions in Javascript() {...}
2 | *A mostly reasonable collection of technical software development interview questions solved in Javascript in ES5 and ES6*
3 |
4 | ## Table of Contents
5 | 1. [Array](#array)
6 | 1. [Strings](#strings)
7 | 1. [Stacks and Queues](#stacks-and-queues)
8 | 1. [Recursion](#recursion)
9 | 1. [Numbers](#numbers)
10 | 1. [Javascript Specific](#javascript)
11 | 1. To Be Continued
12 |
13 | ## Array
14 |
15 | - **[1.1](#array--product) Given an array of integers, find the largest product yielded from three of the integers**
16 | ```javascript
17 | var unsortedArray = [-10, 7, 29, 30, 5, -10, -70];
18 |
19 | computeProduct(unsortedArray); // 21000
20 |
21 | function sortIntegers(a, b) {
22 | return a - b;
23 | }
24 |
25 | // Greatest product is either (min1 * min2 * max1 || max1 * max2 * max3)
26 | function computeProduct(unsorted) {
27 | var sortedArray = unsorted.sort(sortIntegers),
28 | product1 = 1,
29 | product2 = 1,
30 | array_n_element = sortedArray.length - 1;
31 |
32 | // Get the product of three largest integers in sorted array
33 | for (var x = array_n_element; x > array_n_element - 3; x--) {
34 | product1 = product1 * sortedArray[x];
35 | }
36 |
37 | product2 = sortedArray[0] * sortedArray[1] * sortedArray[array_n_element];
38 |
39 | if (product1 > product2) return product1;
40 |
41 | return product2;
42 | }
43 | ```
44 | **View on Codepen:** https://codepen.io/kennymkchan/pen/LxoMvm?editors=0012
45 |
46 |
47 | - **[1.2](#array--consecutive--sum) Being told that an unsorted array contains (n - 1) of n consecutive numbers (where the bounds are defined), find the missing number in `O(n)` time**
48 | ```javascript
49 | // The output of the function should be 8
50 | var arrayOfIntegers = [2, 5, 1, 4, 9, 6, 3, 7];
51 | var upperBound = 9;
52 | var lowerBound = 1;
53 |
54 | findMissingNumber(arrayOfIntegers, upperBound, lowerBound); // 8
55 |
56 | function findMissingNumber(arrayOfIntegers, upperBound, lowerBound) {
57 | // Iterate through array to find the sum of the numbers
58 | var sumOfIntegers = 0;
59 | for (var i = 0; i < arrayOfIntegers.length; i++) {
60 | sumOfIntegers += arrayOfIntegers[i];
61 | }
62 |
63 | // Find theoretical sum of the consecutive numbers using a variation of Gauss Sum.
64 | // Formula: [(N * (N + 1)) / 2] - [(M * (M - 1)) / 2];
65 | // N is the upper bound and M is the lower bound
66 |
67 | upperLimitSum = (upperBound * (upperBound + 1)) / 2;
68 | lowerLimitSum = (lowerBound * (lowerBound - 1)) / 2;
69 |
70 | theoreticalSum = upperLimitSum - lowerLimitSum;
71 |
72 | return theoreticalSum - sumOfIntegers;
73 | }
74 | ```
75 | **View on Codepen:** http://codepen.io/kennymkchan/pen/rjgoXw?editors=0012
76 |
77 |
78 | - **[1.3](#array--unique) Removing duplicates of an array and returning an array of only unique elements**
79 | ```javascript
80 | // ES6 Implementation
81 | var array = [1, 2, 3, 5, 1, 5, 9, 1, 2, 8];
82 |
83 | Array.from(new Set(array)); // [1, 2, 3, 5, 9, 8]
84 |
85 | // ES5 Implementation
86 | var array = [1, 2, 3, 5, 1, 5, 9, 1, 2, 8];
87 |
88 | uniqueArray(array); // [1, 2, 3, 5, 9, 8]
89 |
90 | function uniqueArray(array) {
91 | var hashmap = {};
92 | var unique = [];
93 |
94 | for(var i = 0; i < array.length; i++) {
95 | // If key returns undefined (unique), it is evaluated as false.
96 | if(!hashmap.hasOwnProperty(array[i])) {
97 | hashmap[array[i]] = 1;
98 | unique.push(array[i]);
99 | }
100 | }
101 |
102 | return unique;
103 | }
104 | ```
105 | **View on Codepen:** http://codepen.io/kennymkchan/pen/ZLNwze?editors=0012
106 |
107 |
108 | - **[1.4](#array--largest-difference) Given an array of integers, find the largest difference between two elements such that the element of lesser value must come before the greater element**
109 | ```javascript
110 | var array = [7, 8, 4, 9, 9, 15, 3, 1, 10];
111 | // [7, 8, 4, 9, 9, 15, 3, 1, 10] would return `11` based on the difference between `4` and `15`
112 | // Notice: It is not `14` from the difference between `15` and `1` because 15 comes before 1.
113 |
114 | findLargestDifference(array);
115 |
116 | function findLargestDifference(array) {
117 | // If there is only one element, there is no difference
118 | if (array.length <= 1) return -1;
119 |
120 | // currentMin will keep track of the current lowest
121 | var currentMin = array[0];
122 | var currentMaxDifference = 0;
123 |
124 | // We will iterate through the array and keep track of the current max difference
125 | // If we find a greater max difference, we will set the current max difference to that variable
126 | // Keep track of the current min as we iterate through the array, since we know the greatest
127 | // difference is yield from `largest value in future` - `smallest value before it`
128 |
129 | for (var i = 1; i < array.length; i++) {
130 | if (array[i] > currentMin && (array[i] - currentMin > currentMaxDifference)) {
131 | currentMaxDifference = array[i] - currentMin;
132 | } else if (array[i] <= currentMin) {
133 | currentMin = array[i];
134 | }
135 | }
136 |
137 | // If negative or 0, there is no largest difference
138 | if (currentMaxDifference <= 0) return -1;
139 |
140 | return currentMaxDifference;
141 | }
142 | ```
143 | **View on Codepen:** http://codepen.io/kennymkchan/pen/MJdLWJ?editors=0012
144 |
145 |
146 | - **[1.5](#array--product-other-than-itself) Given an array of integers, return an output array such that output[i] is equal to the product of all the elements in the array other than itself. (Solve this in O(n) without division)**
147 | ```javascript
148 | var firstArray = [2, 2, 4, 1];
149 | var secondArray = [0, 0, 0, 2];
150 | var thirdArray = [-2, -2, -3, 2];
151 |
152 | productExceptSelf(firstArray); // [8, 8, 4, 16]
153 | productExceptSelf(secondArray); // [0, 0, 0, 0]
154 | productExceptSelf(thirdArray); // [12, 12, 8, -12]
155 |
156 | function productExceptSelf(numArray) {
157 | var product = 1;
158 | var size = numArray.length;
159 | var output = [];
160 |
161 | // From first array: [1, 2, 4, 16]
162 | // The last number in this case is already in the right spot (allows for us)
163 | // to just multiply by 1 in the next step.
164 | // This step essentially gets the product to the left of the index at index + 1
165 | for (var x = 0; x < size; x++) {
166 | output.push(product);
167 | product = product * numArray[x];
168 | }
169 |
170 | // From the back, we multiply the current output element (which represents the product
171 | // on the left of the index, and multiplies it by the product on the right of the element)
172 | var product = 1;
173 | for (var i = size - 1; i > -1; i--) {
174 | output[i] = output[i] * product;
175 | product = product * numArray[i];
176 | }
177 |
178 | return output;
179 | }
180 | ```
181 | **View on Codepen:** http://codepen.io/kennymkchan/pen/OWYdJK?editors=0012
182 |
183 |
184 | - **[1.6](#array--intersection) Find the intersection of two arrays. An intersection would be the common elements that exists within both arrays. In this case, these elements should be unique!**
185 | ```javascript
186 | var firstArray = [2, 2, 4, 1];
187 | var secondArray = [1, 2, 0, 2];
188 |
189 | intersection(firstArray, secondArray); // [2, 1]
190 |
191 | function intersection(firstArray, secondArray) {
192 | // The logic here is to create a hashmap with the elements of the firstArray as the keys.
193 | // After that, you can use the hashmap's O(1) look up time to check if the element exists in the hash
194 | // If it does exist, add that element to the new array.
195 |
196 | var hashmap = {};
197 | var intersectionArray = [];
198 |
199 | firstArray.forEach(function(element) {
200 | hashmap[element] = 1;
201 | });
202 |
203 | // Since we only want to push unique elements in our case... we can implement a counter to keep track of what we already added
204 | secondArray.forEach(function(element) {
205 | if (hashmap[element] === 1) {
206 | intersectionArray.push(element);
207 | hashmap[element]++;
208 | }
209 | });
210 |
211 | return intersectionArray;
212 |
213 | // Time complexity O(n), Space complexity O(n)
214 | }
215 | ```
216 | **View on Codepen:** http://codepen.io/kennymkchan/pen/vgwbEb?editors=0012
217 |
218 | **[⬆ back to top](#table-of-contents)**
219 |
220 | ## Strings
221 |
222 | - **[2.1](#string--reverse) Given a string, reverse each word in the sentence**
223 | `"Welcome to this Javascript Guide!"` should be become `"emocleW ot siht tpircsavaJ !ediuG"`
224 | ```javascript
225 | var string = "Welcome to this Javascript Guide!";
226 |
227 | // Output becomes !ediuG tpircsavaJ siht ot emocleW
228 | var reverseEntireSentence = reverseBySeparator(string, "");
229 |
230 | // Output becomes emocleW ot siht tpircsavaJ !ediuG
231 | var reverseEachWord = reverseBySeparator(reverseEntireSentence, " ");
232 |
233 | function reverseBySeparator(string, separator) {
234 | return string.split(separator).reverse().join(separator);
235 | }
236 | ```
237 | **View on Codepen:** http://codepen.io/kennymkchan/pen/VPOONZ?editors=0012
238 |
239 |
240 | - **[2.2](#string--anagram) Given two strings, return true if they are anagrams of one another**
241 | `"Mary" is an anagram of "Army"`
242 | ```javascript
243 | var firstWord = "Mary";
244 | var secondWord = "Army";
245 |
246 | isAnagram(firstWord, secondWord); // true
247 |
248 | function isAnagram(first, second) {
249 | // For case insensitivity, change both words to lowercase.
250 | var a = first.toLowerCase();
251 | var b = second.toLowerCase();
252 |
253 | // Sort the strings, and join the resulting array to a string. Compare the results
254 | a = a.split("").sort().join("");
255 | b = b.split("").sort().join("");
256 |
257 | return a === b;
258 | }
259 | ```
260 | **View on Codepen:** http://codepen.io/kennymkchan/pen/NdVVVj?editors=0012
261 |
262 |
263 | - **[2.3](#string--palindrome) Check if a given string is a palindrome**
264 | `"racecar" is a palindrome. "race car" should also be considered a palindrome. Case sensitivity should be taken into account`
265 | ```javascript
266 | isPalindrome("racecar"); // true
267 | isPalindrome("race Car"); // true
268 |
269 | function isPalindrome(word) {
270 | // Replace all non-letter chars with "" and change to lowercase
271 | var lettersOnly = word.toLowerCase().replace(/\s/g, "");
272 |
273 | // Compare the string with the reversed version of the string
274 | return lettersOnly === lettersOnly.split("").reverse().join("");
275 | }
276 | ```
277 | **View on Codepen:** http://codepen.io/kennymkchan/pen/xgNNNB?editors=0012
278 |
279 |
280 | - **[2.3](#string--palindrome) Check if a given string is a isomorphic**
281 |
282 | ```
283 | For two strings to be isomorphic, all occurrences of a character in string A can be replaced with another character
284 | to get string B. The order of the characters must be preserved. There must be one-to-one mapping for ever char of
285 | string A to every char of string B.
286 |
287 | `paper` and `title` would return true.
288 | `egg` and `sad` would return false.
289 | `dgg` and `add` would return true.
290 | ```
291 | ```javascript
292 | isIsomorphic("egg", 'add'); // true
293 | isIsomorphic("paper", 'title'); // true
294 | isIsomorphic("kick", 'side'); // false
295 |
296 | function isIsomorphic(firstString, secondString) {
297 |
298 | // Check if the same lenght. If not, they cannot be isomorphic
299 | if (firstString.length !== secondString.length) return false
300 |
301 | var letterMap = {};
302 |
303 | for (var i = 0; i < firstString.length; i++) {
304 | var letterA = firstString[i],
305 | letterB = secondString[i];
306 |
307 | // If the letter does not exist, create a map and map it to the value
308 | // of the second letter
309 | if (letterMap[letterA] === undefined) {
310 | // If letterB has already been added to letterMap, then we can say: they are not isomorphic.
311 | if(secondString.indexOf(letterB) < i){
312 | return false;
313 | } else {
314 | letterMap[letterA] = letterB;
315 | }
316 | } else if (letterMap[letterA] !== letterB) {
317 | // Eles if letterA already exists in the map, but it does not map to
318 | // letterB, that means that A is mapping to more than one letter.
319 | return false;
320 | }
321 | }
322 | // If after iterating through and conditions are satisfied, return true.
323 | // They are isomorphic
324 | return true;
325 | }
326 | ```
327 | **View on Codepen:** http://codepen.io/kennymkchan/pen/mRZgaj?editors=0012
328 |
329 | **[⬆ back to top](#table-of-contents)**
330 |
331 | ## Stacks and Queues
332 |
333 |
334 | - **[3.1](#stack-queue--stack-as-queue) Implement enqueue and dequeue using only two stacks**
335 | ```javascript
336 | var inputStack = []; // First stack
337 | var outputStack = []; // Second stack
338 |
339 | // For enqueue, just push the item into the first stack
340 | function enqueue(stackInput, item) {
341 | return stackInput.push(item);
342 | }
343 |
344 | function dequeue(stackInput, stackOutput) {
345 | // Reverse the stack such that the first element of the output stack is the
346 | // last element of the input stack. After that, pop the top of the output to
347 | // get the first element that was ever pushed into the input stack
348 | if (stackOutput.length <= 0) {
349 | while(stackInput.length > 0) {
350 | var elementToOutput = stackInput.pop();
351 | stackOutput.push(elementToOutput);
352 | }
353 | }
354 |
355 | return stackOutput.pop();
356 | }
357 | ```
358 | **View on Codepen:** http://codepen.io/kennymkchan/pen/mRYYZV?editors=0012
359 |
360 |
361 | - **[3.2](#stack-queue--parentheses-balancing) Create a function that will evaluate if a given expression has balanced parentheses -- Using stacks**
362 | In this example, we will only consider "{}" as valid parentheses
363 | `{}{}` would be considered balancing. `{{{}}` is not balanced
364 | ```javascript
365 | var expression = "{{}}{}{}"
366 | var expressionFalse = "{}{{}";
367 |
368 | isBalanced(expression); // true
369 | isBalanced(expressionFalse); // false
370 | isBalanced(""); // true
371 |
372 | function isBalanced(expression) {
373 | var checkString = expression;
374 | var stack = [];
375 |
376 | // If empty, parentheses are technically balanced
377 | if (checkString.length <= 0) return true;
378 |
379 | for (var i = 0; i < checkString.length; i++) {
380 | if(checkString[i] === '{') {
381 | stack.push(checkString[i]);
382 | } else if (checkString[i] === '}') {
383 | // Pop on an empty array is undefined
384 | if (stack.length > 0) {
385 | stack.pop();
386 | } else {
387 | return false;
388 | }
389 | }
390 | }
391 |
392 | // If the array is not empty, it is not balanced
393 | if (stack.pop()) return false;
394 | return true;
395 | }
396 | ```
397 | **View on Codepen:** http://codepen.io/kennymkchan/pen/egaawj?editors=0012
398 |
399 | **[⬆ back to top](#table-of-contents)**
400 |
401 | ## Recursion
402 |
403 | - **[4.1](#recursion--decimal-to-binary) Write a recursive function that returns the binary string of a given decimal number**
404 | Given `4` as the decimal input, the function should return `100`
405 |
406 | ```javascript
407 | decimalToBinary(3); // 11
408 | decimalToBinary(8); // 1000
409 | decimalToBinary(1000); // 1111101000
410 |
411 | function decimalToBinary(digit) {
412 | if(digit >= 1) {
413 | // If digit is not divisible by 2 then recursively return proceeding
414 | // binary of the digit minus 1, 1 is added for the leftover 1 digit
415 | if (digit % 2) {
416 | return decimalToBinary((digit - 1) / 2) + 1;
417 | } else {
418 | // Recursively return proceeding binary digits
419 | return decimalToBinary(digit / 2) + 0;
420 | }
421 | } else {
422 | // Exit condition
423 | return '';
424 | }
425 | }
426 | ```
427 | **View on Codepen:** http://codepen.io/kennymkchan/pen/OWYYKb?editors=0012
428 |
429 |
430 | - **[4.2](#recursion--binary-search) Write a recursive function that performs a binary search**
431 |
432 | ```javascript
433 | function recursiveBinarySearch(array, value, leftPosition, rightPosition) {
434 | // Value DNE
435 | if (leftPosition > rightPosition) return -1;
436 |
437 | var middlePivot = Math.floor((leftPosition + rightPosition) / 2);
438 | if (array[middlePivot] === value) {
439 | return middlePivot;
440 | } else if (array[middlePivot] > value) {
441 | return recursiveBinarySearch(array, value, leftPosition, middlePivot - 1);
442 | } else {
443 | return recursiveBinarySearch(array, value, middlePivot + 1, rightPosition);
444 | }
445 | }
446 | ```
447 | **View on Codepen:** http://codepen.io/kennymkchan/pen/ygWWmK?editors=0012
448 |
449 | **[⬆ back to top](#table-of-contents)**
450 |
451 | ## Numbers
452 |
453 | - **[5.1](#numbers--power-of-two) Given an integer, determine if it is a power of 2. If so,
454 | return that number, else return -1. (0 is not a power of two)**
455 | ```javascript
456 | isPowerOfTwo(4); // true
457 | isPowerOfTwo(64); // true
458 | isPowerOfTwo(1); // true
459 | isPowerOfTwo(0); // false
460 | isPowerOfTwo(-1); // false
461 |
462 | // For the non-zero case:
463 | function isPowerOfTwo(number) {
464 | // `&` uses the bitwise n.
465 | // In the case of number = 4; the expression would be identical to:
466 | // `return (4 & 3 === 0)`
467 | // In bitwise, 4 is 100, and 3 is 011. Using &, if two values at the same
468 | // spot is 1, then result is 1, else 0. In this case, it would return 000,
469 | // and thus, 4 satisfies are expression.
470 | // In turn, if the expression is `return (5 & 4 === 0)`, it would be false
471 | // since it returns 101 & 100 = 100 (NOT === 0)
472 |
473 | return number & (number - 1) === 0;
474 | }
475 |
476 | // For zero-case:
477 | function isPowerOfTwoZeroCase(number) {
478 | return (number !== 0) && ((number & (number - 1)) === 0);
479 | }
480 | ```
481 | **View on Codepen:** http://codepen.io/kennymkchan/pen/qRGGeG?editors=0012
482 |
483 | **[⬆ back to top](#table-of-contents)**
484 |
485 | ## Javascript
486 |
487 | - **[6.1](#javascript--hosting) Explain what is hoisting in Javascript**
488 |
489 | ```
490 | Hoisting is the concept in which Javascript, by default, moves all declarations to the top
491 | of the current scope. As such, a variable can be used before it has been declared. Note that
492 | Javascript only hoists declarations and not initializations
493 | ```
494 |
495 |
496 | - **[6.2](#javascript--use-strict) Describe the functionality of the `use strict;` directive**
497 | ```
498 | the `use strict` directive defines that the Javascript should be executed in `strict mode`.
499 | One major benefit that strict mode provides is that it prevents developers from using
500 | undeclared variables. Older versions of javascript would ignore this directive declaration
501 | ```
502 |
503 | ```javascript
504 | // Example of strict mode
505 | "use strict";
506 |
507 | catchThemAll();
508 | function catchThemAll() {
509 | x = 3.14; // Error will be thrown
510 | return x * x;
511 | }
512 | ```
513 |
514 | - **[6.3](#javascript--event-bubbling) Explain `event bubbling` and how one may prevent it**
515 | ```
516 | Event bubbling is the concept in which an event triggers at the deepest possible element,
517 | and triggers on parent elements in nesting order. As a result, when clicking on a child element
518 | one may exhibit the handler of the parent activating.
519 |
520 | One way to prevent event bubbling is using `event.stopPropagation()` or `event.cancelBubble`
521 | on IE < 9
522 | ```
523 |
524 | - **[6.4](#javascript--strict-operators) What is the difference between `==` and `===` in JS?**
525 | ```
526 | `===` is known as a strict operator. The key difference between `==` and `===` is that the
527 | strict operator matches for both value and type, as opposed to just the value.
528 | ```
529 |
530 | ```javascript
531 | // Example of comparators
532 | 0 == false; // true
533 | 0 === false; // false
534 |
535 | 2 == '2'; // true
536 | 2 === '2'; // false
537 | ```
538 |
539 |
540 | - **[6.5](#javascript--null-undefined) What is the difference between `null` and `undefined`**
541 |
542 | ```
543 | In Javascript, null is an assignment value, and can be assigned to a variable representing that
544 | it has no value. Undefined, on the other hand, represents that a variable has been declared but
545 | there is no value associated with it
546 | ```
547 |
548 |
549 | - **[6.6](#javascript--difference-inheritance) How does `prototypal inheritance` differ from `classical inheritance`**
550 |
551 | ```
552 | In classical inheritance, classes are immutable, may or may not support multiple
553 | inheritance, and may contain interfaces, final classes, and abstract classes. In contrast,
554 | prototypes are much more flexible in the sense that they may be mutable or immutable. The object
555 | may inherit from multiple prototypes, and only contains objects.
556 | ```
557 |
558 | **[⬆ back to top](#table-of-contents)**
559 |
--------------------------------------------------------------------------------