├── 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 | --------------------------------------------------------------------------------