├── .editorconfig ├── .eslintrc ├── .gitattributes ├── .gitignore ├── .travis.yml ├── GruntFile.js ├── LICENSE ├── README.md ├── package.json ├── src ├── check-if-a-binary-tree-is-balanced │ └── index.js ├── divide-without-divide │ ├── README.md │ └── index.js ├── fibonacci-sequence │ ├── README.md │ └── index.js ├── find-median-of-two-sorted-arrays │ └── index.js ├── get-all-combinations-of-a-set │ ├── README.md │ └── index.js ├── get-all-permutations-of-a-set │ ├── README.md │ └── index.js ├── is-palindrome │ ├── README.md │ └── index.js ├── kth-last-element-in-linked-list │ └── singly-linked-list.js ├── max-aware-stack │ ├── README.md │ ├── max-aware-stack-optimised.js │ └── max-aware-stack.js ├── random7-from-random5 │ ├── README.md │ └── index.js ├── reverse-a-linked-list │ ├── README.md │ ├── doubly-linked-list.js │ └── singly-linked-list.js ├── reverse-a-string │ ├── README.md │ └── index.js ├── two-stack-queue │ ├── README.md │ └── index.js └── two-sum │ ├── linear.js │ ├── naive.js │ └── sorted.js └── test ├── check-if-a-binary-tree-is-balanced-spec.js ├── divide-without-divide-spec.js ├── fibonacci-sequence-spec.js ├── find-median-of-two-sorted-arrays-spec.js ├── get-all-combinations-of-a-set-spec.js ├── get-all-permutations-of-a-set-spec.js ├── is-palindrome-spec.js ├── kth-last-element-in-linked-list-spec.js ├── max-aware-stack-optimised-spec.js ├── max-aware-stack-spec.js ├── random7-from-random5-spec.js ├── reverse-a-linked-list-spec.js ├── reverse-a-string-spec.js ├── two-stack-queue-spec.js ├── two-sum-linear-spec.js ├── two-sum-naive-spec.js └── two-sum-sorted-spec.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "node": true 4 | }, 5 | "rules": { 6 | "quotes": [1, "single"] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | coverage 2 | doc 3 | node_modules 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - "0.11" 5 | - "0.10" 6 | 7 | addons: 8 | code_climate: 9 | repo_token: 28cf64c87da0b29047a4d4746f30091d99a7b98377d173fb4e8a5f5a4c8b9226 10 | 11 | before_install: 12 | - npm install -g grunt-cli 13 | - npm install -g codeclimate-test-reporter 14 | 15 | install: 16 | - npm install 17 | - grunt 18 | 19 | after_script: 20 | - cat coverage/lcov.info | codeclimate 21 | -------------------------------------------------------------------------------- /GruntFile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 'use strict'; 3 | 4 | grunt.initConfig({ 5 | pkg: grunt.file.readJSON('package.json'), 6 | 7 | jasmine_node: { 8 | options: { 9 | coverage: {}, 10 | forceExit: true, 11 | match: '.', 12 | matchAll: false, 13 | specFolders: ['test'], 14 | extensions: 'js', 15 | specNameMatcher: 'spec', 16 | captureExceptions: true, 17 | junitreport: { 18 | report: false, 19 | savePath : './build/reports/jasmine/', 20 | useDotNotation: true, 21 | consolidate: true 22 | } 23 | }, 24 | src: ['src/**/*.js'] 25 | }, 26 | 27 | eslint: { 28 | options: { 29 | configFile: '.eslintrc', 30 | }, 31 | src: ['src/**/*.js'] 32 | } 33 | }); 34 | 35 | grunt.loadNpmTasks('grunt-jsdoc'); 36 | grunt.config('jsdoc', { 37 | dist : { 38 | src: ['index.js', 'src/**/*.js'], 39 | options: { 40 | destination: 'doc', 41 | readme: 'README.md' 42 | } 43 | } 44 | }); 45 | 46 | var tasks = [ 47 | 'grunt-jasmine-node-coverage', 48 | 'grunt-eslint' 49 | ]; 50 | 51 | for (var i = 0; i < tasks.length; i++) { 52 | grunt.loadNpmTasks(tasks[i]); 53 | } 54 | grunt.registerTask('coverage', [ 55 | 'jasmine_node' 56 | ]); 57 | 58 | grunt.registerTask('default', [ 59 | 'eslint', 60 | 'jsdoc', 61 | 'coverage' 62 | ]); 63 | }; 64 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Daniel Imms, http://www.growingwiththeweb.com 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # js-interview-questions 2 | 3 | [![Build Status](https://travis-ci.org/gwtw/js-interview-questions.svg?branch=master)](http://travis-ci.org/gwtw/js-interview-questions) 4 | 5 | A collection of interview question answers written in JavaScript. 6 | 7 | 8 | 9 | ## Testing 10 | 11 | ```bash 12 | npm install 13 | npm test 14 | 15 | # generate coverage report in ./coverage/ 16 | grunt coverage 17 | ``` 18 | 19 | 20 | 21 | ## License 22 | 23 | MIT © [Daniel Imms](http://www.growingwiththeweb.com) 24 | 25 | 26 | 27 | ## See also 28 | 29 | * [js-data-structures](https://github.com/gwtw/js-data-structures) 30 | * [js-design-patterns](https://github.com/gwtw/js-design-patterns) 31 | * [js-sorting](https://github.com/gwtw/js-sorting) 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-interview-questions", 3 | "version": "1.0.1", 4 | "description": "A collection of interview question answers written in JavaScript", 5 | "scripts": { 6 | "test": "jasmine-node ." 7 | }, 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/gwtw/js-interview-questions.git" 11 | }, 12 | "keywords": [ 13 | "interview question", 14 | "computer science", 15 | "software engineering" 16 | ], 17 | "author": "Daniel Imms (http://www.growingwiththeweb.com)", 18 | "license": "MIT", 19 | "bugs": { 20 | "url": "https://github.com/gwtw/js-interview-questions/issues" 21 | }, 22 | "homepage": "https://github.com/gwtw/js-interview-questions", 23 | "devDependencies": { 24 | "grunt": "^0.4.5", 25 | "grunt-eslint": "^17.0.0", 26 | "grunt-jasmine-node-coverage": "^0.4.1", 27 | "grunt-jsdoc": "^1.0.0", 28 | "jasmine-node": "^1.14.3", 29 | "jasmine-reporters": ">=0.2.0 <2.0.0" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/check-if-a-binary-tree-is-balanced/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/check-if-a-binary-tree-is-balanced/index 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | /** 8 | * Creates a binary tree node. 9 | * 10 | * @constructor 11 | * @param {Object} data The data associated with this node. 12 | * @param {BinaryTreeNode} left The left child node. 13 | * @param {BinaryTreeNode} right The right child node. 14 | */ 15 | function BinaryTreeNode(data, left, right) { 16 | this.data = data; 17 | this.left = left; 18 | this.right = right; 19 | } 20 | 21 | /** 22 | * Determines the minimum depth of a binary tree node. 23 | * 24 | * @param {BinaryTreeNode} node The node to check. 25 | * @return The minimum depth of a binary tree node. 26 | */ 27 | function minDepth(node) { 28 | if (typeof node === 'undefined') { 29 | return 0; 30 | } 31 | return 1 + Math.min(minDepth(node.left), minDepth(node.right)); 32 | } 33 | 34 | /** 35 | * Determines the maximum depth of a binary tree node. 36 | * 37 | * @param {BinaryTreeNode} node The node to check. 38 | * @return The maximum depth of a binary tree node. 39 | */ 40 | function maxDepth(node) { 41 | if (typeof node === 'undefined') { 42 | return 0; 43 | } 44 | return 1 + Math.max(maxDepth(node.left), maxDepth(node.right)); 45 | } 46 | 47 | /** 48 | * Determines whether a binary tree is balanced. 49 | * 50 | * @param {BinaryTreeNode} root The root of the tree. 51 | * @returns Whether the tree is balanced. 52 | */ 53 | function isBinaryTreeBalanced(root) { 54 | if (typeof root === 'undefined') { 55 | return undefined; 56 | } 57 | return maxDepth(root) - minDepth(root) <= 1; 58 | } 59 | 60 | module.exports = { 61 | BinaryTreeNode: BinaryTreeNode, 62 | isBinaryTreeBalanced: isBinaryTreeBalanced 63 | }; 64 | -------------------------------------------------------------------------------- /src/divide-without-divide/README.md: -------------------------------------------------------------------------------- 1 | **Question:** Implement a function that performs integer division on two integers without the use of the division / operator. For example for the input of 10 and 4 should result in the output of 2. 2 | 3 | [Link to analysis and answer](http://www.growingwiththeweb.com/2013/06/algorithm-integer-division-without.html) 4 | -------------------------------------------------------------------------------- /src/divide-without-divide/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/divide-without-divide 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | /** 8 | * Use integer division on two numbers 9 | * @param {integer} a The numerator. 10 | * @param {integer} b The denominator. 11 | * @returns {integer} The result of a / b. 12 | */ 13 | function integerDivideWithoutDivide(a, b) { 14 | if (b === 0) { 15 | throw 'Division by zero is undefined: ' + a + '/' + b; 16 | } 17 | var sign = 1; 18 | if (a < 0) { 19 | a = -a; 20 | sign = -sign; 21 | } 22 | if (b < 0) { 23 | b = -b; 24 | sign = -sign; 25 | } 26 | var result = 0; 27 | while (a >= 0) { 28 | a -= b; 29 | result++; 30 | } 31 | return (result - 1) * sign; 32 | } 33 | 34 | module.exports = integerDivideWithoutDivide; 35 | -------------------------------------------------------------------------------- /src/fibonacci-sequence/README.md: -------------------------------------------------------------------------------- 1 | **Question:** Implement a function that returns the Fibonnaci number for a given integer input. 2 | 3 | [Link to analysis and answer](http://www.growingwiththeweb.com/2013/09/algorithm-fibonacci-sequence.html) 4 | -------------------------------------------------------------------------------- /src/fibonacci-sequence/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/fibonacci-sequence 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | /** 8 | * Gets the Fibonacci number using a recursive algorithm. 9 | * @param {number} n The Fibonacci number to get. 10 | * @returns {number} The nth Fibonacci number 11 | */ 12 | function fibonacciRecursive(n) { 13 | if (n < 0) 14 | throw 'n must be >= 0'; 15 | if (n === 0) 16 | return 0; 17 | if (n === 1) 18 | return 1; 19 | 20 | return fibonacciRecursive(n - 1) + fibonacciRecursive(n - 2); 21 | } 22 | 23 | /** 24 | * Gets the Fibonacci number using a recursive algorithm that caches recursive 25 | * calls so fibonacciOptimised(x) only gets queried once for a given x. 26 | * @param {number} n The Fibonacci number to get. 27 | * @returns {number} The nth Fibonacci number 28 | */ 29 | function fibonacciOptimised(n, map) { 30 | if (n < 0) 31 | throw 'n must be >= 0'; 32 | if (n === 0) 33 | return 0; 34 | if (n === 1) 35 | return 1; 36 | if (!map) 37 | map = {}; 38 | if (!map[n]) 39 | map[n] = fibonacciOptimised(n - 1, map) + fibonacciOptimised(n - 2, map); 40 | 41 | return map[n]; 42 | } 43 | 44 | /** 45 | * Gets the Fibonacci number using an interative algorithm. 46 | * @param {number} n The Fibonacci number to get. 47 | * @returns {number} The nth Fibonacci number 48 | */ 49 | function fibonacciIterative(n) { 50 | if (n < 0) 51 | throw 'n must be >= 0'; 52 | if (n === 0) 53 | return 0; 54 | if (n === 1) 55 | return 1; 56 | 57 | var first = 0; 58 | var second = 1; 59 | var counter = 1; 60 | var temp; 61 | 62 | while (counter < n) { 63 | temp = first; 64 | first = second; 65 | second = temp + first; 66 | counter++; 67 | } 68 | 69 | return second; 70 | } 71 | 72 | module.exports = { 73 | fibonacciRecursive: fibonacciRecursive, 74 | fibonacciOptimised: fibonacciOptimised, 75 | fibonacciIterative: fibonacciIterative 76 | }; 77 | -------------------------------------------------------------------------------- /src/find-median-of-two-sorted-arrays/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/find-median-of-two-sorted-arrays 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | /** 8 | * Gets the median of a single sorted array. 9 | * 10 | * @param {number[]} array The sorted array to get the median of. 11 | * @return {number} The median of the array. 12 | */ 13 | function medianOfArray(array) { 14 | var mid = Math.floor(array.length / 2); 15 | if (array.length % 2 === 0) { 16 | return (array[mid] + array[mid - 1]) / 2; 17 | } 18 | return array[mid]; 19 | } 20 | 21 | /** 22 | * Gets the median of a sorted array with an even number of elements plus an 23 | * additional value. 24 | * 25 | * @param {number[]} array The sorted array. 26 | * @param {number} arrayMedian The median of the array excluding the additional 27 | * value. 28 | * @param {number} value The additional value to include in median calculation. 29 | * @return {number} The median of the array including the additional value. 30 | */ 31 | function findMedianOfArrayAndValueEvenCase(array, arrayMedian, value) { 32 | if (arrayMedian > value) { 33 | var left = array[array.length / 2 - 1]; 34 | return Math.max(left, value); 35 | } else { 36 | var right = array[array.length / 2]; 37 | return Math.min(right, value); 38 | } 39 | } 40 | 41 | /** 42 | * Gets the median of a sorted array with an odd number of elements plus an 43 | * additional value. 44 | * 45 | * @param {number[]} array The sorted array. 46 | * @param {number} arrayMedian The median of the array excluding the additional 47 | * value. 48 | * @param {number} value The additional value to include in median calculation. 49 | * @return {number} The median of the array including the additional value. 50 | */ 51 | function findMedianOfArrayAndValueOddCase(array, arrayMedian, value) { 52 | var midIndex = (array.length - 1) / 2; 53 | var left = array[midIndex - 1]; 54 | var mid = array[midIndex]; 55 | var right = array[midIndex + 1]; 56 | if (value < left) { 57 | return (mid + left) / 2; 58 | } 59 | if (value > right) { 60 | return (mid + right) / 2; 61 | } 62 | return (mid + value) / 2; 63 | } 64 | 65 | /** 66 | * Gets the median of a sorted array and an additional value. 67 | * 68 | * @param {number[]} array The sorted array. 69 | * @param {number} value The additional value to include in median calculation. 70 | * @return {number} The median of the array including the additional value. 71 | */ 72 | function findMedianOfArrayAndValue(array, value) { 73 | var arrayMedian = medianOfArray(array); 74 | if (arrayMedian === value) { 75 | return arrayMedian; 76 | } 77 | if (array.length % 2 === 0) { 78 | return findMedianOfArrayAndValueEvenCase(array, arrayMedian, value); 79 | } 80 | return findMedianOfArrayAndValueOddCase(array, arrayMedian, value); 81 | } 82 | 83 | /** 84 | * Gets whether two values belong in sorted order in the middle of an array. 85 | * 86 | * @param {number[]} array The sorted array. 87 | * @param {number} small The smaller number. 88 | * @param {number} large The larger number. 89 | * @return {boolean} Whether the two values belong in the middle. 90 | */ 91 | function areValuesInMiddleOfEvenArray(array, small, large) { 92 | return small > array[Math.floor(array.length / 2) - 1] && 93 | large < array[Math.floor(array.length / 2)]; 94 | } 95 | 96 | /** 97 | * Gets the median of two sorted arrays. 98 | * 99 | * @param {number[]} A The first sorted array. 100 | * @param {number[]} B The second sorted array. 101 | * @returns {number} The median of A and B. 102 | */ 103 | function findMedian(A, B) { 104 | if (A.length === 0 && B.length === 0) { 105 | return undefined; 106 | } 107 | if (A.length === 1 && B.length === 1) { 108 | return (A[0] + B[0]) / 2; 109 | } 110 | if (A.length === 0) { 111 | return medianOfArray(B); 112 | } 113 | if (B.length === 0) { 114 | return medianOfArray(A); 115 | } 116 | if (A.length === 1) { 117 | return findMedianOfArrayAndValue(B, A[0]); 118 | } 119 | if (B.length === 1) { 120 | return findMedianOfArrayAndValue(A, B[0]); 121 | } 122 | if (A.length === 2 && B.length >= 2 && B.length % 2 === 0) { 123 | if (areValuesInMiddleOfEvenArray(B, A[0], A[1])) { 124 | return (A[0] + A[1]) / 2; 125 | } 126 | } 127 | if (B.length === 2 && A.length >= 2 && A.length % 2 === 0) { 128 | if (areValuesInMiddleOfEvenArray(A, B[0], B[1])) { 129 | return (B[0] + B[1]) / 2; 130 | } 131 | } 132 | 133 | var medianA = medianOfArray(A); 134 | var medianB = medianOfArray(B); 135 | if (medianA === medianB) { 136 | return medianA; 137 | } 138 | var maxDiscardable = Math.floor(Math.min(A.length / 2 - 1, B.length / 2 - 1)); 139 | if (maxDiscardable < 1) { 140 | maxDiscardable = 1; 141 | } 142 | if (medianA < medianB) { 143 | A.splice(0, maxDiscardable); 144 | B.splice(B.length - maxDiscardable); 145 | } else { 146 | A.splice(A.length - maxDiscardable); 147 | B.splice(0, maxDiscardable); 148 | } 149 | return findMedian(A, B); 150 | } 151 | 152 | module.exports = { 153 | findMedian: findMedian 154 | }; 155 | -------------------------------------------------------------------------------- /src/get-all-combinations-of-a-set/README.md: -------------------------------------------------------------------------------- 1 | **Question:** Implement a function that gets all possible combinations (or subsets) of the characters in a string with length of at least one. For example for the input string "abc", the output will be "a", "b", "c", "ab", "ac", "bc" and "abc". 2 | 3 | [Link to analysis and answer](http://www.growingwiththeweb.com/2013/06/algorithm-all-combinations-of-set.html) 4 | -------------------------------------------------------------------------------- /src/get-all-combinations-of-a-set/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/get-all-combinations-of-a-set 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | /** 8 | * Get all combinations of characters in a string. 9 | * @param {String} text The text to extract combinations from. 10 | * @returns {Array} The resulting combinations. 11 | */ 12 | function getAllCombinationsOfASet(text) { 13 | var results = []; 14 | for (var i = 0; i < text.length; i++) { 15 | // Record size as the list will change 16 | var resultsLength = results.length; 17 | for (var j = 0; j < resultsLength; j++) { 18 | results.push(text[i] + results[j]); 19 | } 20 | results.push(text[i]); 21 | } 22 | return results; 23 | } 24 | 25 | module.exports = getAllCombinationsOfASet; 26 | -------------------------------------------------------------------------------- /src/get-all-permutations-of-a-set/README.md: -------------------------------------------------------------------------------- 1 | **Question:** Implement a function that gets all possible permutations (or orderings) of the characters in a string. For example for the input string "abc", the output will be "abc", "acb", "bac", "bca", "cab" and "cba". 2 | 3 | [Link to analysis and answer](http://www.growingwiththeweb.com/2013/06/algorithm-all-permutations-of-set.html) 4 | -------------------------------------------------------------------------------- /src/get-all-permutations-of-a-set/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/get-all-permutations-of-a-set 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | /** 8 | * Get all permutations of characters in a string. 9 | * @param {String} text The text to extract permutations from. 10 | * @returns {Array} The resulting permutations. 11 | */ 12 | function getAllPermutationsOfASet(text) { 13 | var results = []; 14 | 15 | if (text.length === 1) { 16 | results.push(text); 17 | return results; 18 | } 19 | 20 | for (var i = 0; i < text.length; i++) { 21 | var first = text[i]; 22 | var remains = text.substring(0, i) + text.substring(i + 1); 23 | var innerPermutations = getAllPermutationsOfASet(remains); 24 | for (var j = 0; j < innerPermutations.length; j++) { 25 | results.push(first + innerPermutations[j]); 26 | } 27 | } 28 | 29 | return results; 30 | } 31 | 32 | module.exports = getAllPermutationsOfASet; 33 | -------------------------------------------------------------------------------- /src/is-palindrome/README.md: -------------------------------------------------------------------------------- 1 | **Question:** Determine if a string is a palindrome. A palindrome is a piece of text that is spelt the same when reversed. 2 | 3 | [Link to analysis and answer](http://www.growingwiththeweb.com/2014/02/determine-if-a-string-is-a-palindrome.html) 4 | -------------------------------------------------------------------------------- /src/is-palindrome/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/is-palindrome 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | /** 8 | * Determines whether a string is a palindrome. 9 | * @param {string} text The string to check. 10 | * @returns {boolean} Whether the string is a palindrome. 11 | */ 12 | function isTextPalindrome(text) { 13 | if (text === undefined) { 14 | return false; 15 | } 16 | var left = 0; 17 | var right = text.length - 1; 18 | while (left < right) { 19 | if (text[left++] !== text[right--]) { 20 | return false; 21 | } 22 | } 23 | return true; 24 | } 25 | 26 | /** 27 | * Determines whether a phrase is a palindrome. 28 | * @param {string} text The phrase to check. 29 | * @returns {boolean} Whether the phrase is a palindrome. 30 | */ 31 | function isPhrasePalindrome(text) { 32 | var chars = text.replace(/[^a-zA-Z]/g, '').toLowerCase(); 33 | return isTextPalindrome(chars); 34 | } 35 | 36 | module.exports = { 37 | isTextPalindrome: isTextPalindrome, 38 | isPhrasePalindrome: isPhrasePalindrome 39 | }; 40 | -------------------------------------------------------------------------------- /src/kth-last-element-in-linked-list/singly-linked-list.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/kth-last-element-in-linked-list/singly-linked-list 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | /** 8 | * Creates a singly linked list node. 9 | * 10 | * @constructor 11 | * @param {Object} data The data associated with this node. 12 | * @param {SinglyLinkedList} next The next node in the linked list. 13 | */ 14 | function SinglyLinkedList(data, next) { 15 | this.data = data; 16 | this.next = next; 17 | } 18 | 19 | /** 20 | * Gets the kth last element of a {@link SinglyLinkedList}. 21 | * 22 | * @param {SinglyLinkedList} head The head of the list. 23 | * @param {number} k The number of elements to count backward. 24 | * @returns The kth last element of the linked list, if it is not large enough, 25 | * return 0. 26 | */ 27 | function getKthLastElement(head, k) { 28 | if (!head || k < 1) { 29 | return undefined; 30 | } 31 | 32 | var current = head; 33 | var nBehindCurrent = head; 34 | 35 | for (var i = 0; i < k - 1; i++) { 36 | current = current.next; 37 | if (!current) { 38 | return undefined; 39 | } 40 | } 41 | 42 | while (typeof current.next !== 'undefined') { 43 | nBehindCurrent = nBehindCurrent.next; 44 | current = current.next; 45 | } 46 | 47 | return nBehindCurrent; 48 | } 49 | 50 | module.exports = { 51 | SinglyLinkedList: SinglyLinkedList, 52 | getKthLastElement: getKthLastElement 53 | }; 54 | -------------------------------------------------------------------------------- /src/max-aware-stack/README.md: -------------------------------------------------------------------------------- 1 | **Question:** Implement a stack where its maximum value is available in constant time. 2 | 3 | [Link to analysis and answer](http://www.growingwiththeweb.com/2017/05/max-aware-stack.html) 4 | -------------------------------------------------------------------------------- /src/max-aware-stack/max-aware-stack-optimised.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/max-aware-stack/max-aware-stack-optimized 3 | * @license MIT Copyright 2017 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | /** 8 | * Creates a stack that is aware of its maximum value in constant time. 9 | */ 10 | function MaxAwareStackOptimised() { 11 | this.valueStack = []; 12 | this.maxStack = []; 13 | } 14 | 15 | /** 16 | * Push a value to the stack. 17 | * @param {*} value The value to push. 18 | */ 19 | MaxAwareStackOptimised.prototype.push = function (value) { 20 | if (this.maxStack.length === 0 || this.max() <= value) { 21 | this.maxStack.push(value); 22 | } 23 | this.valueStack.push(value); 24 | } 25 | 26 | /** 27 | * Pops a value from the stack and returns it. 28 | * @return {*} The popped value. 29 | */ 30 | MaxAwareStackOptimised.prototype.pop = function () { 31 | if (this.valueStack.length === 0) { 32 | return undefined; 33 | } 34 | var result = this.valueStack.pop(); 35 | if (result === this.max()) { 36 | this.maxStack.pop(); 37 | } 38 | return result; 39 | } 40 | 41 | /** 42 | * Gets the maximum value in the stack. 43 | * @return {*} The maximum value. 44 | */ 45 | MaxAwareStackOptimised.prototype.max = function () { 46 | if (this.maxStack.length === 0) { 47 | return undefined; 48 | } 49 | return this.maxStack[this.maxStack.length - 1]; 50 | } 51 | 52 | module.exports = MaxAwareStackOptimised; 53 | -------------------------------------------------------------------------------- /src/max-aware-stack/max-aware-stack.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/max-aware-stack/max-aware-stack 3 | * @license MIT Copyright 2017 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | /** 8 | * Creates a stack that is aware of its maximum value in constant time. 9 | */ 10 | function MaxAwareStack() { 11 | // Store the value and the maximum at any given point in objects of form: 12 | // { value: number, max: number } 13 | this.stack = []; 14 | } 15 | 16 | /** 17 | * Push a value to the stack. 18 | * @param {*} value The value to push. 19 | */ 20 | MaxAwareStack.prototype.push = function (value) { 21 | var top = this._top(); 22 | var entry; 23 | if (!top) { 24 | entry = { 25 | value: value, 26 | max: value 27 | }; 28 | } else { 29 | entry = { 30 | value: value, 31 | max: value > top.max ? value : top.max 32 | }; 33 | } 34 | this.stack.push(entry); 35 | } 36 | 37 | /** 38 | * Pops a value from the stack and returns it. 39 | * @return {*} The popped value. 40 | */ 41 | MaxAwareStack.prototype.pop = function () { 42 | if (this.stack.length === 0) { 43 | return undefined; 44 | } 45 | return this.stack.pop().value; 46 | } 47 | 48 | /** 49 | * Gets the maximum value in the stack. 50 | * @return {*} The maximum value. 51 | */ 52 | MaxAwareStack.prototype.max = function () { 53 | if (this.stack.length === 0) { 54 | return undefined; 55 | } 56 | return this._top().max; 57 | } 58 | 59 | /** 60 | * A private convenience function for getting the top entry of the stack. 61 | * @return {Object} The top entry. 62 | */ 63 | MaxAwareStack.prototype._top = function () { 64 | return this.stack[this.stack.length - 1]; 65 | } 66 | 67 | module.exports = MaxAwareStack; 68 | -------------------------------------------------------------------------------- /src/random7-from-random5/README.md: -------------------------------------------------------------------------------- 1 | **Question:** Given the function `random5` that generates and returns a uniformly distributed random integer from 1 to 5, implement `random7` that returns a uniformly distributed random integer from 1 to 7. 2 | 3 | [Link to analysis and answer](http://www.growingwiththeweb.com/2014/03/given-random5-implement-random7.html) 4 | -------------------------------------------------------------------------------- /src/random7-from-random5/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/random7-from-random5 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | /** 8 | * A random number generator that gets a uniformly distributed value from 1 to 7 9 | * given a function that gets a uniformly distributed value from 1 to 5. 10 | * @param {function} random5 A random number generator that gets a uniformly 11 | * distributed random number from 1 to 5. 12 | * @returns {number} A number from 1 to 7. 13 | */ 14 | function random7(random5) { 15 | // Get 0, 5, 10, 15 or 20 then add 0-4 (4% chance for 0-24) 16 | var val = (random5() - 1) * 5 + (random5() - 1); 17 | // If 0-20, return the result modulo 7 + 1 (12% chance for 1-7), otherwise 18 | // call recursively (16% chance) 19 | return val >= 21 ? random7(random5) : val % 7 + 1; 20 | } 21 | 22 | module.exports = random7; 23 | -------------------------------------------------------------------------------- /src/reverse-a-linked-list/README.md: -------------------------------------------------------------------------------- 1 | **Question:** Reverse a linked list. 2 | 3 | [Link to analysis and answer](http://www.growingwiththeweb.com/2014/03/reverse-a-linked-list.html) 4 | -------------------------------------------------------------------------------- /src/reverse-a-linked-list/doubly-linked-list.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/reverse-a-linked-list/doubly-linked-list 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | /** 8 | * Creates a doubly linked list node. 9 | * @constructor 10 | * @param {Object} data The data associated with this node. 11 | * @param {SinglyLinkedList} next The next node in the linked list. 12 | */ 13 | function DoublyLinkedList(data, next) { 14 | this.data = data; 15 | this.next = next; 16 | if (this.next) { 17 | this.next.prev = this; 18 | } 19 | this.prev = undefined; 20 | } 21 | 22 | /** 23 | * Reverse a {@link DoublyLinkedList}. 24 | * @param {DoublyLinkedList} head The head of the list. 25 | * @returns The new head of the linked list. 26 | */ 27 | function reverseDoubly(head) { 28 | while (head != null) { 29 | var temp = head.next; 30 | head.next = head.prev; 31 | head.prev = temp; 32 | if (!temp) { 33 | break; 34 | } 35 | head = temp; 36 | } 37 | return head; 38 | } 39 | 40 | module.exports = { 41 | DoublyLinkedList: DoublyLinkedList, 42 | reverseDoubly: reverseDoubly 43 | }; 44 | -------------------------------------------------------------------------------- /src/reverse-a-linked-list/singly-linked-list.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/reverse-a-linked-list/singly-linked-list 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | /** 8 | * Creates a singly linked list node. 9 | * @constructor 10 | * @param {Object} data The data associated with this node. 11 | * @param {SinglyLinkedList} next The next node in the linked list. 12 | */ 13 | function SinglyLinkedList(data, next) { 14 | this.data = data; 15 | this.next = next; 16 | } 17 | 18 | /** 19 | * Reverse a {@link SinglyLinkedList}. 20 | * @param {SinglyLinkedList} head The head of the list. 21 | * @returns The new head of the linked list. 22 | */ 23 | function reverseSingly(head) { 24 | var prev; 25 | while (head.next) { 26 | var next = head.next; 27 | head.next = prev; 28 | prev = head; 29 | head = next; 30 | } 31 | head.next = prev; 32 | return head; 33 | } 34 | 35 | module.exports = { 36 | SinglyLinkedList: SinglyLinkedList, 37 | reverseSingly: reverseSingly 38 | }; 39 | -------------------------------------------------------------------------------- /src/reverse-a-string/README.md: -------------------------------------------------------------------------------- 1 | **Question:** Reverse a string in the most efficient way possible. For example an input of "abc123" will result in the output "321cba". 2 | 3 | [Link to analysis and answer](http://www.growingwiththeweb.com/2013/06/algorithm-reverse-string.html) 4 | -------------------------------------------------------------------------------- /src/reverse-a-string/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/reverse-a-string 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | /** 8 | * Reverses a string. 9 | * @param {string} text The string to reverse. 10 | * @returns {string} The reversed string. 11 | */ 12 | function reverseString(text) { 13 | var result = ''; 14 | for (var i = text.length - 1; i >= 0; i--) { 15 | result += text[i]; 16 | } 17 | return result; 18 | } 19 | 20 | module.exports = reverseString; 21 | -------------------------------------------------------------------------------- /src/two-stack-queue/README.md: -------------------------------------------------------------------------------- 1 | **Question:** Implement a function that returns the Fibonnaci number for a given integer input. 2 | 3 | [Link to analysis and answer](http://www.growingwiththeweb.com/2013/07/algorithm-implement-queue-using-2-stacks.html) 4 | -------------------------------------------------------------------------------- /src/two-stack-queue/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/two-stack-queue 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | /** 8 | * Creates a queue implemented with two stacks. 9 | * @constructor 10 | */ 11 | function TwoStackQueue() { 12 | this.inbox = []; 13 | this.outbox = []; 14 | } 15 | 16 | /** 17 | * Push a value to the queue. 18 | * @param {*} value The value to push. 19 | */ 20 | TwoStackQueue.prototype.push = function (value) { 21 | this.inbox.push(value); 22 | }; 23 | 24 | /** 25 | * Pops a value from the queue and returns it. 26 | * @return {*} The popped value. 27 | */ 28 | TwoStackQueue.prototype.pop = function () { 29 | if (!this.outbox.length) { 30 | if (!this.inbox.length) { 31 | return undefined; 32 | } 33 | while (this.inbox.length) { 34 | this.outbox.push(this.inbox.pop()); 35 | } 36 | } 37 | return this.outbox.pop(); 38 | }; 39 | 40 | module.exports = TwoStackQueue; 41 | -------------------------------------------------------------------------------- /src/two-sum/linear.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/reverse-a-string 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | function twoSumLinear(array, target) { 8 | let hash = {}; 9 | for (let i = 0; i < array.length; i++) { 10 | let requiredValue = target - array[i]; 11 | if (requiredValue in hash) { 12 | return [i, hash[requiredValue]]; 13 | } 14 | hash[array[i]] = i; 15 | }; 16 | return undefined; 17 | } 18 | 19 | module.exports = twoSum; 20 | -------------------------------------------------------------------------------- /src/two-sum/naive.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/reverse-a-string 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | function twoSumNaive(array, target) { 8 | for (let i = 0; i < array.length; i++) { 9 | for (let j = i + 1; j < array.length; j++) { 10 | if (array[i] + array[j] === target) { 11 | return [i, j]; 12 | } 13 | } 14 | }; 15 | return undefined; 16 | } 17 | 18 | module.exports = twoSum; 19 | -------------------------------------------------------------------------------- /src/two-sum/sorted.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module src/reverse-a-string 3 | * @license MIT Copyright 2015 Daniel Imms (http://www.growingwiththeweb.com) 4 | */ 5 | 'use strict'; 6 | 7 | function twoSumSorted(array, target) { 8 | var left = 0; 9 | var right = array.length - 1; 10 | while (left < right) { 11 | var sum = array[left] + array[right]; 12 | if (sum === target) { 13 | return [left, right]; 14 | } 15 | if (sum < target) { 16 | left++; 17 | } else { 18 | right--; 19 | } 20 | } 21 | return undefined; 22 | } 23 | 24 | module.exports = twoSum; 25 | -------------------------------------------------------------------------------- /test/check-if-a-binary-tree-is-balanced-spec.js: -------------------------------------------------------------------------------- 1 | var BinaryTreeNode = require('../src/check-if-a-binary-tree-is-balanced').BinaryTreeNode; 2 | var isBinaryTreeBalanced = require('../src/check-if-a-binary-tree-is-balanced').isBinaryTreeBalanced; 3 | 4 | describe('isBinaryTreeBalanced', function () { 5 | 'use strict'; 6 | 7 | describe('given an undefined tree', function () { 8 | it('should return undefined', function () { 9 | expect(isBinaryTreeBalanced(undefined)).toBe(undefined); 10 | }); 11 | }); 12 | 13 | describe('given a single element tree', function () { 14 | it('should return true', function () { 15 | var tree = new BinaryTreeNode(null); 16 | expect(isBinaryTreeBalanced(tree)).toBe(true); 17 | }); 18 | }); 19 | 20 | describe('given a two element tree', function () { 21 | it('should return true when left-heavy', function () { 22 | var tree = new BinaryTreeNode(null, new BinaryTreeNode(null), undefined); 23 | expect(isBinaryTreeBalanced(tree)).toBe(true); 24 | }); 25 | 26 | it('should return true when right heavy', function () { 27 | var tree = new BinaryTreeNode(null, undefined, new BinaryTreeNode(null)); 28 | expect(isBinaryTreeBalanced(tree)).toBe(true); 29 | }); 30 | }); 31 | 32 | describe('given a tree element tree', function () { 33 | it('should return false when left-heavy', function () { 34 | var tree = new BinaryTreeNode(null, 35 | new BinaryTreeNode(null, new BinaryTreeNode(null), undefined), 36 | undefined); 37 | expect(isBinaryTreeBalanced(tree)).toBe(false); 38 | }); 39 | 40 | it('should return true when balanced', function () { 41 | var tree = new BinaryTreeNode(null, 42 | new BinaryTreeNode(null), 43 | new BinaryTreeNode(null)); 44 | expect(isBinaryTreeBalanced(tree)).toBe(true); 45 | }); 46 | 47 | it('should return false when right heavy', function () { 48 | var tree = new BinaryTreeNode(null, 49 | undefined, 50 | new BinaryTreeNode(null, undefined, new BinaryTreeNode(null))); 51 | expect(isBinaryTreeBalanced(tree)).toBe(false); 52 | }); 53 | }); 54 | }); 55 | -------------------------------------------------------------------------------- /test/divide-without-divide-spec.js: -------------------------------------------------------------------------------- 1 | var divideWithoutDivide = require('../src/divide-without-divide'); 2 | 3 | describe('divideWithoutDivide', function () { 4 | 'use strict'; 5 | 6 | it('should throw when dividing by zero', function () { 7 | expect(divideWithoutDivide.bind(undefined, 1, 0)).toThrow(); 8 | }); 9 | 10 | it('should divide by 1', function () { 11 | expect(divideWithoutDivide(0, 1)).toBe(0); 12 | expect(divideWithoutDivide(1, 1)).toBe(1); 13 | expect(divideWithoutDivide(2, 1)).toBe(2); 14 | expect(divideWithoutDivide(3, 1)).toBe(3); 15 | expect(divideWithoutDivide(4, 1)).toBe(4); 16 | }); 17 | 18 | it('should divide positive numbers', function () { 19 | expect(divideWithoutDivide(20, 2)).toBe(10); 20 | expect(divideWithoutDivide(20, 3)).toBe(6); 21 | expect(divideWithoutDivide(30, 4)).toBe(7); 22 | expect(divideWithoutDivide(30, 5)).toBe(6); 23 | expect(divideWithoutDivide(40, 6)).toBe(6); 24 | expect(divideWithoutDivide(40, 7)).toBe(5); 25 | }); 26 | 27 | it('should divide negative numbers', function () { 28 | expect(divideWithoutDivide(-20, 2)).toBe(-10); 29 | expect(divideWithoutDivide(-20, 3)).toBe(-6); 30 | expect(divideWithoutDivide(-30, 4)).toBe(-7); 31 | expect(divideWithoutDivide(-30, 5)).toBe(-6); 32 | expect(divideWithoutDivide(-40, 6)).toBe(-6); 33 | expect(divideWithoutDivide(-40, 7)).toBe(-5); 34 | }); 35 | 36 | it('should divide by negative numbers', function () { 37 | expect(divideWithoutDivide(20, -2)).toBe(-10); 38 | expect(divideWithoutDivide(20, -3)).toBe(-6); 39 | expect(divideWithoutDivide(30, -4)).toBe(-7); 40 | expect(divideWithoutDivide(30, -5)).toBe(-6); 41 | expect(divideWithoutDivide(40, -6)).toBe(-6); 42 | expect(divideWithoutDivide(40, -7)).toBe(-5); 43 | }); 44 | 45 | it('should divide negative numerator and denominator', function () { 46 | expect(divideWithoutDivide(-20, -3)).toBe(6); 47 | expect(divideWithoutDivide(-30, -5)).toBe(6); 48 | expect(divideWithoutDivide(-40, -7)).toBe(5); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /test/fibonacci-sequence-spec.js: -------------------------------------------------------------------------------- 1 | var fibonacciRecursive = require('../src/fibonacci-sequence').fibonacciRecursive; 2 | var fibonacciOptimised = require('../src/fibonacci-sequence').fibonacciOptimised; 3 | var fibonacciIterative = require('../src/fibonacci-sequence').fibonacciIterative; 4 | 5 | function fibonacciSequenceTests(algorithm) { 6 | describe('with negative input', function () { 7 | it('should throw', function () { 8 | expect(algorithm.bind(undefined, -1)).toThrow(); 9 | }); 10 | }); 11 | 12 | describe('with input 0', function () { 13 | it('should return 0', function () { 14 | expect(algorithm(0)).toBe(0); 15 | }); 16 | }); 17 | 18 | describe('with input 1', function () { 19 | it('should return 1', function () { 20 | expect(algorithm(1)).toBe(1); 21 | }); 22 | }); 23 | 24 | describe('with input 2', function () { 25 | it('should return 1', function () { 26 | expect(algorithm(2)).toBe(1); 27 | }); 28 | }); 29 | 30 | describe('with input 3', function () { 31 | it('should return 2', function () { 32 | expect(algorithm(3)).toBe(2); 33 | }); 34 | }); 35 | 36 | describe('with input 4', function () { 37 | it('should return 3', function () { 38 | expect(algorithm(4)).toBe(3); 39 | }); 40 | }); 41 | 42 | describe('with input 5', function () { 43 | it('should return 5', function () { 44 | expect(algorithm(5)).toBe(5); 45 | }); 46 | }); 47 | 48 | describe('with input 6', function () { 49 | it('should return 8', function () { 50 | expect(algorithm(6)).toBe(8); 51 | }); 52 | }); 53 | 54 | describe('with input 7', function () { 55 | it('should return 13', function () { 56 | expect(algorithm(7)).toBe(13); 57 | }); 58 | }); 59 | 60 | describe('with input 8', function () { 61 | it('should return 21', function () { 62 | expect(algorithm(8)).toBe(21); 63 | }); 64 | }); 65 | 66 | describe('with input 9', function () { 67 | it('should return 34', function () { 68 | expect(algorithm(9)).toBe(34); 69 | }); 70 | }); 71 | 72 | describe('with input 10', function () { 73 | it('should return 55', function () { 74 | expect(algorithm(10)).toBe(55); 75 | }); 76 | }); 77 | } 78 | 79 | describe('fibonacciSequence', function () { 80 | 'use strict'; 81 | 82 | describe('fibonacciRecursive', function () { 83 | fibonacciSequenceTests(fibonacciRecursive); 84 | }); 85 | 86 | describe('fibonacciOptimised', function () { 87 | fibonacciSequenceTests(fibonacciOptimised); 88 | }); 89 | 90 | describe('fibonacciIterative', function () { 91 | fibonacciSequenceTests(fibonacciIterative); 92 | }); 93 | }); 94 | -------------------------------------------------------------------------------- /test/find-median-of-two-sorted-arrays-spec.js: -------------------------------------------------------------------------------- 1 | var findMedian = require('../src/find-median-of-two-sorted-arrays').findMedian; 2 | 3 | describe('findMedian', function () { 4 | 'use strict'; 5 | 6 | describe('given two empty arrays', function () { 7 | it('should return undefined', function () { 8 | expect(findMedian([], [])).toBe(undefined); 9 | }); 10 | }); 11 | 12 | describe('given one single element array', function () { 13 | it('should return undefined', function () { 14 | expect(findMedian([], [1])).toBe(1); 15 | expect(findMedian([1], [])).toBe(1); 16 | }); 17 | }); 18 | 19 | describe('given two single element arrays', function () { 20 | it('should return the median', function () { 21 | expect(findMedian([1], [3])).toBe(2); 22 | }); 23 | }); 24 | 25 | describe('given an empty first array', function () { 26 | it('should return the median of the second array', function () { 27 | expect(findMedian([], [1, 2, 3, 4, 5])).toBe(3); 28 | expect(findMedian([], [-2, 6, 10, 22, 23])).toBe(10); 29 | expect(findMedian([], [1, 2, 4, 4, 5, 6])).toBe(4); 30 | expect(findMedian([], [1, 2, 3, 4, 5, 6])).toBe(3.5); 31 | }); 32 | }); 33 | 34 | describe('given an empty second array', function () { 35 | it('should return the median of the first array', function () { 36 | expect(findMedian([1, 2, 3, 4, 5], [])).toBe(3); 37 | expect(findMedian([-2, 6, 10, 22, 23], [])).toBe(10); 38 | expect(findMedian([1, 2, 4, 4, 5, 6], [])).toBe(4); 39 | expect(findMedian([1, 2, 3, 4, 5, 6], [])).toBe(3.5); 40 | }); 41 | }); 42 | 43 | describe('given two same sized small arrays', function () { 44 | it('should return the median', function () { 45 | expect(findMedian([1, 3, 5, 6], [3, 5, 6, 8])).toBe(5); 46 | expect(findMedian([3, 4, 5, 6, 7], [4, 5, 6, 7, 8])).toBe(5.5); 47 | expect(findMedian([1, 2, 3, 4], [4, 5, 6, 7])).toBe(4); 48 | expect(findMedian([1, 2, 3, 4], [5, 6, 7, 8])).toBe(4.5); 49 | expect(findMedian([1, 2, 3, 4], [6, 7, 8, 9])).toBe(5); 50 | expect(findMedian([1, 2, 3, 4], [7, 8, 9, 10])).toBe(5.5); 51 | expect(findMedian([1, 1, 1, 1], [1, 1, 1, 1])).toBe(1); 52 | expect(findMedian([1, 2, 3, 4, 5], [2, 3, 4, 5, 6])).toBe(3.5); 53 | expect(findMedian([-1, 0, 1, 2, 5], [2, 3, 4, 5, 6])).toBe(2.5); 54 | }); 55 | }); 56 | 57 | describe('given a larger first array', function () { 58 | it('should return the median', function () { 59 | expect(findMedian([1, 2, 4, 6, 7], [3, 5, 8, 9])).toBe(5); 60 | expect(findMedian([1, 2, 3, 4, 5, 6, 8, 9, 10], [7])).toBe(5.5); 61 | expect(findMedian([1, 2, 3, 4, 5, 6, 8, 9], [7])).toBe(5); 62 | expect(findMedian([1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3])).toBe(3.5); 63 | expect(findMedian([1, 2, 3, 4, 5, 6, 7, 8], [1, 2, 3])).toBe(3); 64 | expect(findMedian([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [2, 3])).toBe(4.5); 65 | expect(findMedian([1, 2, 3, 4, 5, 6, 7, 8, 9], [2, 3])).toBe(4); 66 | }); 67 | 68 | describe('when the median is within a single element array', function () { 69 | it('should return the median', function () { 70 | expect(findMedian([1, 2, 3, 4, 6, 7, 8, 9], [5])).toBe(5); 71 | expect(findMedian([4, 7], [5])).toBe(5); 72 | expect(findMedian([1, 4, 7, 9], [5])).toBe(5); 73 | }); 74 | }); 75 | }); 76 | 77 | 78 | describe('given a larger second array', function () { 79 | it('should return the median', function () { 80 | expect(findMedian([3, 5, 8, 9], [1, 2, 4, 6, 7])).toBe(5); 81 | expect(findMedian([7], [1, 2, 3, 4, 5, 6, 8, 9, 10])).toBe(5.5); 82 | expect(findMedian([7], [1, 2, 3, 4, 5, 6, 8, 9])).toBe(5); 83 | expect(findMedian([1, 2, 3], [1, 2, 3, 4, 5, 6, 7, 8, 9])).toBe(3.5); 84 | expect(findMedian([1, 2, 3], [1, 2, 3, 4, 5, 6, 7, 8])).toBe(3); 85 | expect(findMedian([2, 3], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])).toBe(4.5); 86 | expect(findMedian([2, 3], [1, 2, 3, 4, 5, 6, 7, 8, 9])).toBe(4); 87 | }); 88 | 89 | describe('when the median is within a single element array', function () { 90 | it('should return the median', function () { 91 | expect(findMedian([5], [1, 2, 3, 4, 6, 7, 8, 9])).toBe(5); 92 | expect(findMedian([5], [4, 7])).toBe(5); 93 | expect(findMedian([5], [1, 4, 7, 9])).toBe(5); 94 | }); 95 | }); 96 | }); 97 | 98 | describe('given two large arrays', function () { 99 | it('should handle the case when one array is trimmed to two values which are the median and the other array contains more', function () { 100 | expect(findMedian([-50, -47, -36, -35, 0, 13, 14, 16], [-31, 1, 9, 23, 30, 39])).toBe(5); 101 | expect(findMedian([-47, -36, -35, 0, 13, 14], [-31, 1, 9, 23, 30, 39])).toBe(5); 102 | }); 103 | }); 104 | 105 | describe('findMedianOfArrayAndValue', function () { 106 | it('should handle value < array left value', function () { 107 | expect(findMedian([-1], [1, 4, 7])).toBe(2.5); 108 | expect(findMedian([0], [1, 4, 7])).toBe(2.5); 109 | expect(findMedian([1, 4, 7], [-1])).toBe(2.5); 110 | expect(findMedian([1, 4, 7], [0])).toBe(2.5); 111 | }); 112 | 113 | it('should handle value > array left value && value < array mid value', function () { 114 | expect(findMedian([2], [1, 4, 7])).toBe(3); 115 | expect(findMedian([3], [1, 4, 7])).toBe(3.5); 116 | expect(findMedian([1, 4, 7], [2])).toBe(3); 117 | expect(findMedian([1, 4, 7], [3])).toBe(3.5); 118 | }); 119 | 120 | it('should handle value == array mid value', function () { 121 | expect(findMedian([4], [1, 4, 7])).toBe(4); 122 | expect(findMedian([4], [1, 4, 7])).toBe(4); 123 | expect(findMedian([1, 4, 7], [4])).toBe(4); 124 | expect(findMedian([1, 4, 7], [4])).toBe(4); 125 | }); 126 | 127 | it('should handle value < array right value && value > array mid value', function () { 128 | expect(findMedian([5], [1, 4, 7])).toBe(4.5); 129 | expect(findMedian([6], [1, 4, 7])).toBe(5); 130 | expect(findMedian([1, 4, 7], [5])).toBe(4.5); 131 | expect(findMedian([1, 4, 7], [6])).toBe(5); 132 | }); 133 | 134 | it('should handle value > array right value', function () { 135 | expect(findMedian([8], [1, 4, 7])).toBe(5.5); 136 | expect(findMedian([9], [1, 4, 7])).toBe(5.5); 137 | expect(findMedian([1, 4, 7], [8])).toBe(5.5); 138 | expect(findMedian([1, 4, 7], [9])).toBe(5.5); 139 | }); 140 | }); 141 | }); 142 | -------------------------------------------------------------------------------- /test/get-all-combinations-of-a-set-spec.js: -------------------------------------------------------------------------------- 1 | var getAllCombinationsOfASet = require('../src/get-all-combinations-of-a-set'); 2 | 3 | describe('getAllCombinationsOfASet', function () { 4 | 'use strict'; 5 | 6 | describe('with input ""', function () { 7 | it('should return []', function () { 8 | expect(getAllCombinationsOfASet('').length).toBe(0); 9 | }); 10 | }); 11 | 12 | describe('with input "a"', function () { 13 | it('should return ["a"]', function () { 14 | var result = getAllCombinationsOfASet('a'); 15 | expect(result.length).toBe(1); 16 | expect(result[0]).toBe('a'); 17 | }); 18 | }); 19 | 20 | describe('with input "a"', function () { 21 | it('should return ["a"]', function () { 22 | var result = getAllCombinationsOfASet('a'); 23 | expect(result.length).toBe(1); 24 | expect(result[0]).toBe('a'); 25 | }); 26 | }); 27 | 28 | describe('with input "ab"', function () { 29 | it('should return ["a", "b", "ba"]', function () { 30 | var result = getAllCombinationsOfASet('ab'); 31 | expect(result.length).toBe(3); 32 | expect(result.indexOf('a') >= 0).toBe(true); 33 | expect(result.indexOf('b') >= 0).toBe(true); 34 | expect(result.indexOf('ba') >= 0).toBe(true); 35 | }); 36 | }); 37 | 38 | describe('with input "abc"', function () { 39 | it('should return ["a", "b", "c", "ba", "ca", "cb", "cba"]', function () { 40 | var result = getAllCombinationsOfASet('abc'); 41 | expect(result.length).toBe(7); 42 | expect(result.indexOf('a') >= 0).toBe(true); 43 | expect(result.indexOf('b') >= 0).toBe(true); 44 | expect(result.indexOf('c') >= 0).toBe(true); 45 | expect(result.indexOf('ba') >= 0).toBe(true); 46 | expect(result.indexOf('ca') >= 0).toBe(true); 47 | expect(result.indexOf('cb') >= 0).toBe(true); 48 | expect(result.indexOf('cba') >= 0).toBe(true); 49 | }); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /test/get-all-permutations-of-a-set-spec.js: -------------------------------------------------------------------------------- 1 | var getAllPermutationsOfASet = require('../src/get-all-permutations-of-a-set'); 2 | 3 | describe('getAllPermutationsOfASet', function () { 4 | 'use strict'; 5 | 6 | describe('with input ""', function () { 7 | it('should return []', function () { 8 | expect(getAllPermutationsOfASet('').length).toBe(0); 9 | }); 10 | }); 11 | 12 | describe('with input "a"', function () { 13 | it('should return ["a"]', function () { 14 | var result = getAllPermutationsOfASet('a'); 15 | expect(result.length).toBe(1); 16 | expect(result[0]).toBe('a'); 17 | }); 18 | }); 19 | 20 | describe('with input "a"', function () { 21 | it('should return ["a"]', function () { 22 | var result = getAllPermutationsOfASet('a'); 23 | expect(result.length).toBe(1); 24 | expect(result[0]).toBe('a'); 25 | }); 26 | }); 27 | 28 | describe('with input "ab"', function () { 29 | it('should return ["ab", "ba"]', function () { 30 | var result = getAllPermutationsOfASet('ab'); 31 | expect(result.length).toBe(2); 32 | expect(result.indexOf('ab') >= 0).toBe(true); 33 | expect(result.indexOf('ba') >= 0).toBe(true); 34 | }); 35 | }); 36 | 37 | describe('with input "abc"', function () { 38 | it('should return ["abc", "acb", "bac", "bca", "cab", "cba"]', function () { 39 | var result = getAllPermutationsOfASet('abc'); 40 | expect(result.length).toBe(6); 41 | expect(result.indexOf('abc') >= 0).toBe(true); 42 | expect(result.indexOf('acb') >= 0).toBe(true); 43 | expect(result.indexOf('bac') >= 0).toBe(true); 44 | expect(result.indexOf('bca') >= 0).toBe(true); 45 | expect(result.indexOf('cab') >= 0).toBe(true); 46 | expect(result.indexOf('cba') >= 0).toBe(true); 47 | }); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /test/is-palindrome-spec.js: -------------------------------------------------------------------------------- 1 | var isTextPalindrome = require('../src/is-palindrome').isTextPalindrome; 2 | var isPhrasePalindrome = require('../src/is-palindrome').isPhrasePalindrome; 3 | 4 | describe('isTextPalindrome', function () { 5 | 'use strict'; 6 | 7 | it('should throw whenreturn false when the input is undefined', function () { 8 | expect(isTextPalindrome()).toBe(false); 9 | }); 10 | 11 | it('should return true for palindromes', function () { 12 | expect(isTextPalindrome('')).toBe(true); 13 | expect(isTextPalindrome('a')).toBe(true); 14 | expect(isTextPalindrome('aa')).toBe(true); 15 | expect(isTextPalindrome('aba')).toBe(true); 16 | expect(isTextPalindrome('abba')).toBe(true); 17 | expect(isTextPalindrome('abcba')).toBe(true); 18 | }); 19 | 20 | it('should return false for non-palindromes', function () { 21 | expect(isTextPalindrome('ab')).toBe(false); 22 | expect(isTextPalindrome('ab')).toBe(false); 23 | expect(isTextPalindrome('abc')).toBe(false); 24 | expect(isTextPalindrome('abac')).toBe(false); 25 | expect(isTextPalindrome('abcca')).toBe(false); 26 | }); 27 | }); 28 | 29 | describe('isPhrasePalindrome', function () { 30 | 'use strict'; 31 | 32 | it('should return true for palindromes', function () { 33 | expect(isPhrasePalindrome('')).toBe(true); 34 | expect(isPhrasePalindrome('a')).toBe(true); 35 | expect(isPhrasePalindrome('aa')).toBe(true); 36 | expect(isPhrasePalindrome('aba')).toBe(true); 37 | expect(isPhrasePalindrome('abba')).toBe(true); 38 | expect(isPhrasePalindrome('abcba')).toBe(true); 39 | }); 40 | 41 | it('should return true for phrase palindromes', function () { 42 | expect(isPhrasePalindrome('race car')).toBe(true); 43 | expect(isPhrasePalindrome('taco cat')).toBe(true); 44 | expect(isPhrasePalindrome('Cain: a maniac.')).toBe(true); 45 | expect(isPhrasePalindrome('Was it a car or a cat I saw?')).toBe(true); 46 | expect(isPhrasePalindrome('A man, a plan, a canal, Panama')).toBe(true); 47 | }); 48 | 49 | it('should return false for non-palindromes', function () { 50 | expect(isPhrasePalindrome('ab')).toBe(false); 51 | expect(isPhrasePalindrome('ab')).toBe(false); 52 | expect(isPhrasePalindrome('abc')).toBe(false); 53 | expect(isPhrasePalindrome('abac')).toBe(false); 54 | expect(isPhrasePalindrome('abcca')).toBe(false); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /test/kth-last-element-in-linked-list-spec.js: -------------------------------------------------------------------------------- 1 | var SinglyLinkedList = require('../src/kth-last-element-in-linked-list/singly-linked-list').SinglyLinkedList; 2 | var getKthLastElement = require('../src/kth-last-element-in-linked-list/singly-linked-list').getKthLastElement; 3 | 4 | describe('getKthLastElement', function () { 5 | 'use strict'; 6 | 7 | it('should return desired results for undefined list', function () { 8 | expect(getKthLastElement(undefined, 1)).toBe(undefined); 9 | }); 10 | 11 | it('should return desired results for single element list', function () { 12 | var head = new SinglyLinkedList(1); 13 | expect(getKthLastElement(head, 1).data).toBe(1); 14 | expect(getKthLastElement(head, 2)).toBe(undefined); 15 | }); 16 | 17 | it('should return desired results for two element list', function () { 18 | var head = new SinglyLinkedList(1, 19 | new SinglyLinkedList(2)); 20 | expect(getKthLastElement(head, 1).data).toBe(2); 21 | expect(getKthLastElement(head, 2).data).toBe(1); 22 | expect(getKthLastElement(head, 3)).toBe(undefined); 23 | }); 24 | 25 | it('should return desired results for small list', function () { 26 | var head = new SinglyLinkedList(1, 27 | new SinglyLinkedList(2, 28 | new SinglyLinkedList(3))); 29 | expect(getKthLastElement(head, 1).data).toBe(3); 30 | expect(getKthLastElement(head, 2).data).toBe(2); 31 | expect(getKthLastElement(head, 3).data).toBe(1); 32 | expect(getKthLastElement(head, 4)).toBe(undefined); 33 | }); 34 | 35 | it('should return desired results for large list', function () { 36 | var head = new SinglyLinkedList(1); 37 | var current = head; 38 | for (var i = 2; i <= 100; i++) { 39 | current.next = new SinglyLinkedList(i); 40 | current = current.next; 41 | } 42 | current = head; 43 | for (var i = 1; i <= 100; i++) { 44 | expect(getKthLastElement(current, 101 - i)).toBe(current); 45 | current = current.next; 46 | } 47 | expect(getKthLastElement(head, 101)).toBe(undefined); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /test/max-aware-stack-optimised-spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var MaxAwareStackOptimised = require('../src/max-aware-stack/max-aware-stack-optimised'); 4 | 5 | describe('MaxAwareStackOptimised', function () { 6 | it('should return undefined when calling pop() on an empty stack', function () { 7 | var stack = new MaxAwareStackOptimised(); 8 | expect(stack.pop()).toBe(undefined); 9 | stack.push(1); 10 | stack.pop(); 11 | expect(stack.pop()).toBe(undefined); 12 | }); 13 | 14 | it('should push and pop 1 element', function () { 15 | var stack = new MaxAwareStackOptimised(); 16 | stack.push(1); 17 | expect(stack.pop()).toBe(1); 18 | }); 19 | 20 | it('should push and pop 2 elements', function () { 21 | var stack = new MaxAwareStackOptimised(); 22 | stack.push(1); 23 | stack.push(2); 24 | expect(stack.pop()).toBe(2); 25 | expect(stack.pop()).toBe(1); 26 | }); 27 | 28 | it('should push and pop 3 element', function () { 29 | var stack = new MaxAwareStackOptimised(); 30 | stack.push(1); 31 | stack.push(2); 32 | stack.push(3); 33 | expect(stack.pop()).toBe(3); 34 | expect(stack.pop()).toBe(2); 35 | expect(stack.pop()).toBe(1); 36 | }); 37 | 38 | it('should push and pop in shuffled order', function () { 39 | var stack = new MaxAwareStackOptimised(); 40 | stack.push(1); 41 | stack.push(2); 42 | expect(stack.pop()).toBe(2); 43 | stack.push(3); 44 | stack.push(4); 45 | expect(stack.pop()).toBe(4); 46 | stack.push(5); 47 | expect(stack.pop()).toBe(5); 48 | expect(stack.pop()).toBe(3); 49 | expect(stack.pop()).toBe(1); 50 | }); 51 | 52 | it('should return undefined as the maximum on an empty stack', function () { 53 | var stack = new MaxAwareStackOptimised(); 54 | expect(stack.max()).toBe(undefined); 55 | stack.push(1); 56 | stack.pop(); 57 | expect(stack.max()).toBe(undefined); 58 | }); 59 | 60 | it('should return the maximum when values are pushed', function () { 61 | var stack = new MaxAwareStackOptimised(); 62 | stack.push(1); 63 | expect(stack.max()).toBe(1); 64 | stack.push(3); 65 | expect(stack.max()).toBe(3); 66 | stack.push(2); 67 | expect(stack.max()).toBe(3); 68 | }); 69 | 70 | it('should record the maximum when values are popped', function () { 71 | var stack = new MaxAwareStackOptimised(); 72 | stack.push(1); 73 | stack.push(3); 74 | stack.push(2); 75 | expect(stack.max()).toBe(3); 76 | stack.pop(); 77 | expect(stack.max()).toBe(3); 78 | stack.pop(); 79 | expect(stack.max()).toBe(1); 80 | stack.pop(); 81 | expect(stack.max()).toBe(undefined); 82 | }); 83 | 84 | it('should work with duplicate values', function () { 85 | var stack = new MaxAwareStackOptimised(); 86 | stack.push(1); 87 | stack.push(1); 88 | stack.push(2); 89 | stack.push(2); 90 | expect(stack.max()).toBe(2); 91 | stack.pop(); 92 | expect(stack.max()).toBe(2); 93 | stack.pop(); 94 | expect(stack.max()).toBe(1); 95 | stack.pop(); 96 | expect(stack.max()).toBe(1); 97 | stack.pop(); 98 | expect(stack.max()).toBe(undefined); 99 | }); 100 | }); 101 | -------------------------------------------------------------------------------- /test/max-aware-stack-spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var MaxAwareStack = require('../src/max-aware-stack/max-aware-stack'); 4 | 5 | describe('MaxAwareStack', function () { 6 | it('should return undefined when calling pop() on an empty stack', function () { 7 | var stack = new MaxAwareStack(); 8 | expect(stack.pop()).toBe(undefined); 9 | stack.push(1); 10 | stack.pop(); 11 | expect(stack.pop()).toBe(undefined); 12 | }); 13 | 14 | it('should push and pop 1 element', function () { 15 | var stack = new MaxAwareStack(); 16 | stack.push(1); 17 | expect(stack.pop()).toBe(1); 18 | }); 19 | 20 | it('should push and pop 2 elements', function () { 21 | var stack = new MaxAwareStack(); 22 | stack.push(1); 23 | stack.push(2); 24 | expect(stack.pop()).toBe(2); 25 | expect(stack.pop()).toBe(1); 26 | }); 27 | 28 | it('should push and pop 3 element', function () { 29 | var stack = new MaxAwareStack(); 30 | stack.push(1); 31 | stack.push(2); 32 | stack.push(3); 33 | expect(stack.pop()).toBe(3); 34 | expect(stack.pop()).toBe(2); 35 | expect(stack.pop()).toBe(1); 36 | }); 37 | 38 | it('should push and pop in shuffled order', function () { 39 | var stack = new MaxAwareStack(); 40 | stack.push(1); 41 | stack.push(2); 42 | expect(stack.pop()).toBe(2); 43 | stack.push(3); 44 | stack.push(4); 45 | expect(stack.pop()).toBe(4); 46 | stack.push(5); 47 | expect(stack.pop()).toBe(5); 48 | expect(stack.pop()).toBe(3); 49 | expect(stack.pop()).toBe(1); 50 | }); 51 | 52 | it('should return undefined as the maximum on an empty stack', function () { 53 | var stack = new MaxAwareStack(); 54 | expect(stack.max()).toBe(undefined); 55 | stack.push(1); 56 | stack.pop(); 57 | expect(stack.max()).toBe(undefined); 58 | }); 59 | 60 | it('should return the maximum when values are pushed', function () { 61 | var stack = new MaxAwareStack(); 62 | stack.push(1); 63 | expect(stack.max()).toBe(1); 64 | stack.push(3); 65 | expect(stack.max()).toBe(3); 66 | stack.push(2); 67 | expect(stack.max()).toBe(3); 68 | }); 69 | 70 | it('should record the maximum when values are popped', function () { 71 | var stack = new MaxAwareStack(); 72 | stack.push(1); 73 | stack.push(3); 74 | stack.push(2); 75 | expect(stack.max()).toBe(3); 76 | stack.pop(); 77 | expect(stack.max()).toBe(3); 78 | stack.pop(); 79 | expect(stack.max()).toBe(1); 80 | stack.pop(); 81 | expect(stack.max()).toBe(undefined); 82 | }); 83 | }); 84 | -------------------------------------------------------------------------------- /test/random7-from-random5-spec.js: -------------------------------------------------------------------------------- 1 | var random7 = require('../src/random7-from-random5'); 2 | 3 | describe('random7', function () { 4 | 'use strict'; 5 | 6 | describe('given mocked random5 that returns integers', function () { 7 | it('should return uniformly distributed numbers', function () { 8 | function fakeRandom(sequence) { 9 | return function () { 10 | return sequence.shift(); 11 | } 12 | } 13 | 14 | // Go through first 1-21 sequences that can give 1-7 15 | expect(random7(fakeRandom([1, 1]))).toBe(1); 16 | expect(random7(fakeRandom([1, 2]))).toBe(2); 17 | expect(random7(fakeRandom([1, 3]))).toBe(3); 18 | expect(random7(fakeRandom([1, 4]))).toBe(4); 19 | expect(random7(fakeRandom([1, 5]))).toBe(5); 20 | expect(random7(fakeRandom([2, 1]))).toBe(6); 21 | expect(random7(fakeRandom([2, 2]))).toBe(7); 22 | expect(random7(fakeRandom([2, 3]))).toBe(1); 23 | expect(random7(fakeRandom([2, 4]))).toBe(2); 24 | expect(random7(fakeRandom([2, 5]))).toBe(3); 25 | expect(random7(fakeRandom([3, 1]))).toBe(4); 26 | expect(random7(fakeRandom([3, 2]))).toBe(5); 27 | expect(random7(fakeRandom([3, 3]))).toBe(6); 28 | expect(random7(fakeRandom([3, 4]))).toBe(7); 29 | expect(random7(fakeRandom([3, 5]))).toBe(1); 30 | expect(random7(fakeRandom([4, 1]))).toBe(2); 31 | expect(random7(fakeRandom([4, 2]))).toBe(3); 32 | expect(random7(fakeRandom([4, 3]))).toBe(4); 33 | expect(random7(fakeRandom([4, 4]))).toBe(5); 34 | expect(random7(fakeRandom([4, 5]))).toBe(6); 35 | expect(random7(fakeRandom([5, 1]))).toBe(7); 36 | // Ensure that random7 is recursively called 37 | expect(random7(fakeRandom([5, 2, 1, 1]))).toBe(1); 38 | expect(random7(fakeRandom([5, 3, 1, 2]))).toBe(2); 39 | expect(random7(fakeRandom([5, 4, 1, 3]))).toBe(3); 40 | expect(random7(fakeRandom([5, 5, 1, 4]))).toBe(4); 41 | expect(random7(fakeRandom([5, 3, 1, 5]))).toBe(5); 42 | expect(random7(fakeRandom([5, 4, 2, 1]))).toBe(6); 43 | expect(random7(fakeRandom([5, 5, 2, 2]))).toBe(7); 44 | }); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /test/reverse-a-linked-list-spec.js: -------------------------------------------------------------------------------- 1 | var SinglyLinkedList = require('../src/reverse-a-linked-list/singly-linked-list').SinglyLinkedList; 2 | var reverseSingly = require('../src/reverse-a-linked-list/singly-linked-list').reverseSingly; 3 | var DoublyLinkedList = require('../src/reverse-a-linked-list/doubly-linked-list').DoublyLinkedList; 4 | var reverseDoubly = require('../src/reverse-a-linked-list/doubly-linked-list').reverseDoubly; 5 | 6 | describe('SinglyLinkedList', function () { 7 | 'use strict'; 8 | 9 | describe('Reversing a single element linked list', function () { 10 | it('should not change the list', function () { 11 | var list = new SinglyLinkedList(1); 12 | expect(list.data).toBe(1); 13 | expect(list.next).toBe(undefined); 14 | reverseSingly(list); 15 | expect(list.data).toBe(1); 16 | expect(list.next).toBe(undefined); 17 | }); 18 | }); 19 | 20 | describe('Reversing a 2 element linked list', function () { 21 | it('should correctly reverse the list', function () { 22 | var list = new SinglyLinkedList(1, new SinglyLinkedList(2)); 23 | list = reverseSingly(list); 24 | expect(list.data).toBe(2); 25 | expect(list.next.data).toBe(1); 26 | expect(list.next.next).toBe(undefined); 27 | }); 28 | }); 29 | 30 | describe('Reversing a 3 element linked list', function () { 31 | it('should correctly reverse the list', function () { 32 | var list = new SinglyLinkedList(1, new SinglyLinkedList(2, new SinglyLinkedList(3))); 33 | list = reverseSingly(list); 34 | expect(list.data).toBe(3); 35 | expect(list.next.data).toBe(2); 36 | expect(list.next.next.data).toBe(1); 37 | expect(list.next.next.next).toBe(undefined); 38 | }); 39 | }); 40 | }); 41 | 42 | describe('DoublyLinkedList', function () { 43 | 'use strict'; 44 | 45 | describe('Reversing a single element linked list', function () { 46 | it('should not change the list', function () { 47 | var list = new DoublyLinkedList(1); 48 | expect(list.data).toBe(1); 49 | expect(list.next).toBe(undefined); 50 | expect(list.prev).toBe(undefined); 51 | reverseSingly(list); 52 | expect(list.data).toBe(1); 53 | expect(list.next).toBe(undefined); 54 | expect(list.prev).toBe(undefined); 55 | }); 56 | }); 57 | 58 | describe('Reversing a 2 element linked list', function () { 59 | it('should correctly reverse the list', function () { 60 | var list = new DoublyLinkedList(1, new DoublyLinkedList(2)); 61 | list = reverseDoubly(list); 62 | expect(list.data).toBe(2); 63 | expect(list.prev).toBe(undefined); 64 | expect(list.next.data).toBe(1); 65 | expect(list.next.prev.data).toBe(2); 66 | expect(list.next.next).toBe(undefined); 67 | }); 68 | }); 69 | 70 | describe('Reversing a 3 element linked list', function () { 71 | it('should correctly reverse the list', function () { 72 | var list = new DoublyLinkedList(1, new DoublyLinkedList(2, new DoublyLinkedList(3))); 73 | list = reverseDoubly(list); 74 | expect(list.data).toBe(3); 75 | expect(list.prev).toBe(undefined); 76 | expect(list.next.data).toBe(2); 77 | expect(list.next.prev.data).toBe(3); 78 | expect(list.next.next.data).toBe(1); 79 | expect(list.next.next.prev.data).toBe(2); 80 | expect(list.next.next.next).toBe(undefined); 81 | }); 82 | }); 83 | }); 84 | -------------------------------------------------------------------------------- /test/reverse-a-string-spec.js: -------------------------------------------------------------------------------- 1 | var reverseString = require('../src/reverse-a-string'); 2 | 3 | describe('reverseString', function () { 4 | 'use strict'; 5 | 6 | describe('with input ""', function () { 7 | it('should return ""', function () { 8 | expect(reverseString('')).toBe(''); 9 | }); 10 | }); 11 | 12 | describe('with input of a single character', function () { 13 | it('should return the character', function () { 14 | expect(reverseString('a')).toBe('a'); 15 | expect(reverseString('b')).toBe('b'); 16 | }); 17 | }); 18 | 19 | describe('with input of size >= 2', function () { 20 | it('should return the reversed string', function () { 21 | expect(reverseString('ab')).toBe('ba'); 22 | expect(reverseString('abc')).toBe('cba'); 23 | expect(reverseString('abcd')).toBe('dcba'); 24 | expect(reverseString('abcde')).toBe('edcba'); 25 | expect(reverseString('abcdef')).toBe('fedcba'); 26 | expect(reverseString('abcdefg')).toBe('gfedcba'); 27 | }); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /test/two-stack-queue-spec.js: -------------------------------------------------------------------------------- 1 | var TwoStackQueue = require('../src/two-stack-queue'); 2 | 3 | describe('TwoStackQueue', function () { 4 | 'use strict'; 5 | 6 | it('should return undefined when calling pop() on an empty queue', function () { 7 | var queue = new TwoStackQueue(); 8 | expect(queue.pop()).toBe(undefined); 9 | queue.push(1); 10 | queue.pop(); 11 | expect(queue.pop()).toBe(undefined); 12 | }); 13 | 14 | it('should push and pop 1 element', function () { 15 | var queue = new TwoStackQueue(); 16 | queue.push(1); 17 | expect(queue.pop()).toBe(1); 18 | }); 19 | 20 | it('should push and pop 2 elements', function () { 21 | var queue = new TwoStackQueue(); 22 | queue.push(1); 23 | queue.push(2); 24 | expect(queue.pop()).toBe(1); 25 | expect(queue.pop()).toBe(2); 26 | }); 27 | 28 | it('should push and pop 3 element', function () { 29 | var queue = new TwoStackQueue(); 30 | queue.push(1); 31 | queue.push(2); 32 | queue.push(3); 33 | expect(queue.pop()).toBe(1); 34 | expect(queue.pop()).toBe(2); 35 | expect(queue.pop()).toBe(3); 36 | }); 37 | 38 | it('should push and pop in shuffled order', function () { 39 | var queue = new TwoStackQueue(); 40 | queue.push(1); 41 | queue.push(2); 42 | expect(queue.pop()).toBe(1); 43 | queue.push(3); 44 | queue.push(4); 45 | expect(queue.pop()).toBe(2); 46 | queue.push(5); 47 | expect(queue.pop()).toBe(3); 48 | expect(queue.pop()).toBe(4); 49 | expect(queue.pop()).toBe(5); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /test/two-sum-linear-spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var twoSum = require('../src/two-sum/linear'); 4 | 5 | describe('twoSum linear', function () { 6 | it('should return undefined when called on an empty array', function () { 7 | expect(twoSum([], 1)).toBe(undefined); 8 | }); 9 | it('should return correct result when it exists in sorted lists', function () { 10 | expect(twoSum([1, 2, 4, 8, 16], 3).sort()).toEqual([0, 1]); 11 | expect(twoSum([1, 2, 4, 8, 16], 6).sort()).toEqual([1, 2]); 12 | expect(twoSum([1, 2, 4, 8, 16], 17).sort()).toEqual([0, 4]); 13 | expect(twoSum([1, 2, 4, 8, 16], 20).sort()).toEqual([2, 4]); 14 | expect(twoSum([1, 2, 4, 8, 16], 24).sort()).toEqual([3, 4]); 15 | }); 16 | it('should return correct result when it exists in a jumbled lists', function () { 17 | expect(twoSum([16, 1, 4, 2, 8], 3).sort()).toEqual([1, 3]); 18 | expect(twoSum([16, 1, 4, 2, 8], 6).sort()).toEqual([2, 3]); 19 | expect(twoSum([16, 1, 4, 2, 8], 17).sort()).toEqual([0, 1]); 20 | expect(twoSum([16, 1, 4, 2, 8], 20).sort()).toEqual([0, 2]); 21 | expect(twoSum([16, 1, 4, 2, 8], 24).sort()).toEqual([0, 4]); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/two-sum-naive-spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var twoSum = require('../src/two-sum/naive'); 4 | 5 | describe('twoSum naive', function () { 6 | it('should return undefined when called on an empty array', function () { 7 | expect(twoSum([], 1)).toBe(undefined); 8 | }); 9 | it('should return correct result when it exists in sorted lists', function () { 10 | expect(twoSum([1, 2, 4, 8, 16], 3)).toEqual([0, 1]); 11 | expect(twoSum([1, 2, 4, 8, 16], 6)).toEqual([1, 2]); 12 | expect(twoSum([1, 2, 4, 8, 16], 17)).toEqual([0, 4]); 13 | expect(twoSum([1, 2, 4, 8, 16], 20)).toEqual([2, 4]); 14 | expect(twoSum([1, 2, 4, 8, 16], 24)).toEqual([3, 4]); 15 | }); 16 | it('should return correct result when it exists in a jumbled lists', function () { 17 | expect(twoSum([16, 1, 4, 2, 8], 3)).toEqual([1, 3]); 18 | expect(twoSum([16, 1, 4, 2, 8], 6)).toEqual([2, 3]); 19 | expect(twoSum([16, 1, 4, 2, 8], 17)).toEqual([0, 1]); 20 | expect(twoSum([16, 1, 4, 2, 8], 20)).toEqual([0, 2]); 21 | expect(twoSum([16, 1, 4, 2, 8], 24)).toEqual([0, 4]); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/two-sum-sorted-spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var twoSum = require('../src/two-sum/sorted'); 4 | 5 | describe('twoSum sorted', function () { 6 | it('should return undefined when called on an empty array', function () { 7 | expect(twoSum([], 1)).toBe(undefined); 8 | }); 9 | it('should return correct result when it exists', function () { 10 | expect(twoSum([1, 2, 4, 8, 16], 3)).toEqual([0, 1]); 11 | expect(twoSum([1, 2, 4, 8, 16], 6)).toEqual([1, 2]); 12 | expect(twoSum([1, 2, 4, 8, 16], 17)).toEqual([0, 4]); 13 | expect(twoSum([1, 2, 4, 8, 16], 20)).toEqual([2, 4]); 14 | expect(twoSum([1, 2, 4, 8, 16], 24)).toEqual([3, 4]); 15 | }); 16 | }); 17 | --------------------------------------------------------------------------------