├── .husky ├── .gitignore └── pre-commit ├── .prettierignore ├── src ├── design │ ├── OrderSaleMaximizer │ │ └── index.spec.js │ ├── DiscordCmdCooldowns │ │ └── index.js │ ├── Observable │ │ └── index.js │ ├── BufferSequence │ │ └── index.js │ └── BehaviorSubject │ │ └── index.js ├── fromJob │ ├── README.md │ └── flattenObjectOfArrays │ │ └── index.spec.js ├── intro │ └── basicAlgos │ │ └── function-intro.png ├── data_structures │ ├── Graphs │ │ ├── graph-parts.jpg │ │ ├── airports-weighted-graph.jpg │ │ ├── Dijkstras-video-screencap.png │ │ ├── connected-vs-complete-graph.jpg │ │ ├── directed-vs-undirected-graph.jpg │ │ ├── depth-vs-breadth-search-first.gif │ │ ├── cyclic-vs-acyclic-directed-graph.jpg │ │ └── travelingSalesman │ │ │ ├── travelingSalesman.md │ │ │ └── travelingSalesman.js │ ├── Queue │ │ └── QueueUsingTwoStacks.png │ └── Trie │ │ ├── intro.md │ │ └── index.js ├── DOM │ ├── displayFolderStructure │ │ ├── folderStructure.png │ │ └── index.html │ └── iterativelyRenderTree │ │ ├── index.html │ │ └── index.js ├── recursion │ ├── intro-notes │ │ ├── call-stack-order-debug.png │ │ ├── factorial-code-animation.gif │ │ └── fibonacci-recursion-animation.gif │ ├── generateAnagrams │ │ ├── index.spec.js │ │ └── index.js │ ├── inOrderSubsets │ │ ├── index.spec.js │ │ └── index.js │ ├── reverseStr │ │ ├── index.spec.js │ │ └── index.js │ ├── binaryStringExpansion │ │ └── index.spec.js │ ├── sumToOneDigit │ │ ├── index.spec.js │ │ └── index.js │ ├── sumArr │ │ ├── index.spec.js │ │ └── index.js │ ├── recursiveSigma │ │ └── index.spec.js │ ├── factorial │ │ ├── index.spec.js │ │ └── index.js │ ├── removeConsecDupeWords │ │ └── index.spec.js │ ├── binarySearch │ │ └── index.spec.js │ ├── coronaVirusFloodFill │ │ └── index.spec.js │ ├── fibonacci │ │ └── index.spec.js │ ├── lowestCommonMult │ │ └── index.spec.js │ ├── greatestCommonFactor │ │ ├── index.spec.js │ │ └── index.js │ └── generateCoinChange │ │ └── index.js ├── bit_arithmetic │ ├── decimalToBinary │ │ └── index.js │ ├── binaryToDecimal │ │ └── index.js.js │ ├── decimalToHexidecimal │ │ └── index.js.js │ ├── encodeBytesTo32 │ │ └── index.js.js │ └── hexidecimalToDecimal │ │ └── index.js.js ├── sorts │ ├── intro.md │ ├── radixSort │ │ ├── index.js │ │ └── index.spec.js │ ├── bubbleSort │ │ └── index.spec.js │ ├── quickSort │ │ └── index.spec.js │ ├── insertionSort │ │ └── index.spec.js │ ├── selectionSort │ │ └── index.spec.js │ └── mergeSort │ │ └── index.spec.js ├── strings │ ├── rehash │ │ └── index.spec.js │ ├── trim │ │ ├── index.spec.js │ │ └── index.js │ ├── stringToWordArray │ │ ├── index.spec.js │ │ └── index.js │ ├── dupesBetweenSeparators │ │ └── index.spec.js │ ├── decodeStr │ │ └── index.spec.js │ ├── vowelsFirst │ │ ├── index.spec.js │ │ └── index.js │ ├── capitalization │ │ └── index.spec.js │ ├── getQuoteFromCaret │ │ ├── index.spec.js │ │ └── index.js │ ├── reverseWords │ │ └── index.spec.js │ ├── bracesValid │ │ └── index.spec.js │ ├── reverseString │ │ ├── index.spec.js │ │ └── index.js │ ├── reverseWordOrder │ │ └── index.spec.js │ ├── bookIndex │ │ └── index.spec.js │ ├── isPalindrome │ │ ├── index.spec.js │ │ └── index.js │ ├── caseInsensitiveStringCompare │ │ └── index.spec.js │ ├── removeDupeWords │ │ ├── index.spec.js │ │ └── index.js │ ├── stringDedupe │ │ └── index.spec.js │ ├── kaprekarsConstant │ │ ├── index.spec.js │ │ └── index.js │ ├── encodeStr │ │ └── index.spec.js │ ├── acronymize │ │ └── index.spec.js │ ├── questionMarks │ │ └── index.spec.js │ ├── addHonorific │ │ └── index.spec.js │ ├── isAnagram │ │ └── index.spec.js │ ├── longestPalindromicSubstring │ │ └── index.spec.js │ ├── palindromeFromSubstr │ │ └── index.js │ ├── parensValid │ │ └── index.spec.js │ ├── isRotation │ │ ├── index.spec.js │ │ └── index.js │ ├── rotateStr │ │ └── index.spec.js │ ├── backspaceStringCompare │ │ └── index.spec.js │ ├── lengthOfLongestSubstring │ │ └── index.spec.js │ ├── canBuildS1FromS2 │ │ └── index.spec.js │ ├── canStringBecomePalindrome │ │ └── index.spec.js │ ├── outputToJson │ │ ├── index.js │ │ └── output.txt │ ├── largestCommonSubstring │ │ └── index.spec.js │ ├── compareVersionNumbers │ │ └── index.spec.js │ └── rot13 │ │ └── index.js ├── misc │ ├── swapTwoInts │ │ └── index.js │ └── clockHandAngles │ │ └── index.js ├── arrays │ ├── firstNonConsecutive │ │ ├── index.js │ │ └── index.spec.js │ ├── sumArrColumns │ │ ├── index.spec.js │ │ └── index.js │ ├── balanceIndex │ │ └── index.spec.js │ ├── balancePoint │ │ └── index.spec.js │ ├── countEvenNegatives │ │ ├── index.spec.js │ │ └── index.js │ ├── minToFront │ │ └── index.spec.js │ ├── reverseArr │ │ └── index.spec.js │ ├── findTriplets │ │ └── index.spec.js │ ├── flatten2dArray │ │ └── index.spec.js │ ├── allNonConsecutive │ │ └── index.spec.js │ ├── tacoTruck │ │ └── index.js │ ├── binarySearch │ │ └── index.spec.js │ ├── dedupeSorted │ │ └── index.spec.js │ ├── diagonalDifference │ │ └── index.spec.js │ ├── concatSelf │ │ └── index.spec.js │ ├── indexOfMinVal │ │ └── index.spec.js │ ├── firstNonRepeated │ │ └── index.spec.js │ ├── socialDistancingEnforcer │ │ ├── index.spec.js │ │ └── index.js │ ├── containerWithMostWater │ │ └── index.spec.js │ ├── oddOccurrencesInArray │ │ └── index.spec.js │ ├── matrixSearch │ │ └── index.js │ ├── missingValue │ │ └── index.spec.js │ ├── mode │ │ └── index.spec.js │ ├── interleaveArrays │ │ └── index.spec.js │ ├── nthLast │ │ └── index.spec.js │ ├── checkTicTacToeWinner │ │ └── index.spec.js │ ├── kMostFrequent │ │ └── index.spec.js │ ├── removeAt │ │ └── index.spec.js │ └── twoSum │ │ └── index.spec.js ├── objects │ ├── invertObj │ │ ├── index.spec.js │ │ └── index.js │ ├── fewestCoinChange │ │ └── index.spec.js │ ├── zipArraysIntoMap │ │ └── index.spec.js │ ├── insert │ │ └── index.spec.js │ ├── findObjects │ │ └── index.spec.js │ ├── lens │ │ └── index.spec.js │ ├── coronaVirusAtRisk │ │ └── index.spec.js │ ├── makeFrequencyTable │ │ └── index.spec.js │ ├── santasNaughtyList │ │ └── index.spec.js │ ├── getMaxServings │ │ └── index.spec.js │ ├── updateInventory │ │ └── index.spec.js │ └── groupObjects │ │ └── index.spec.js ├── amazon │ ├── shortestDeliveries │ │ └── index.spec.js │ └── musicRuntime │ │ └── index.spec.js ├── recreated_methods │ ├── Array │ │ ├── concat │ │ │ └── index.spec.js │ │ ├── unshift │ │ │ └── index.spec.js │ │ ├── push │ │ │ └── index.spec.js │ │ ├── shift │ │ │ └── index.spec.js │ │ ├── indexOf │ │ │ └── index.spec.js │ │ ├── join │ │ │ └── index.spec.js │ │ └── pop │ │ │ └── index.spec.js │ └── Object │ │ └── entries │ │ └── index.test.js ├── sets │ ├── intro.md │ └── orderedIntersection │ │ └── index.spec.js ├── callbacks │ └── dropIt │ │ └── index.spec.js └── intervals │ └── mergeSortedIntervals │ └── index.spec.js ├── .prettierrc.json ├── spec ├── support │ └── jasmine.json └── temp.js ├── pair-programming.md ├── package.json ├── README.md ├── jasmine.md └── schedules └── web_fund.md /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /src/design/OrderSaleMaximizer/index.spec.js: -------------------------------------------------------------------------------- 1 | // TODO 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npm run pretty-quick 5 | -------------------------------------------------------------------------------- /src/fromJob/README.md: -------------------------------------------------------------------------------- 1 | # From Job Algos 2 | 3 | - Extracted logic from solving a problem on the job. 4 | -------------------------------------------------------------------------------- /src/intro/basicAlgos/function-intro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCodingDojo/algorithms/HEAD/src/intro/basicAlgos/function-intro.png -------------------------------------------------------------------------------- /src/data_structures/Graphs/graph-parts.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCodingDojo/algorithms/HEAD/src/data_structures/Graphs/graph-parts.jpg -------------------------------------------------------------------------------- /src/data_structures/Queue/QueueUsingTwoStacks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCodingDojo/algorithms/HEAD/src/data_structures/Queue/QueueUsingTwoStacks.png -------------------------------------------------------------------------------- /src/DOM/displayFolderStructure/folderStructure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCodingDojo/algorithms/HEAD/src/DOM/displayFolderStructure/folderStructure.png -------------------------------------------------------------------------------- /src/data_structures/Graphs/airports-weighted-graph.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCodingDojo/algorithms/HEAD/src/data_structures/Graphs/airports-weighted-graph.jpg -------------------------------------------------------------------------------- /src/recursion/intro-notes/call-stack-order-debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCodingDojo/algorithms/HEAD/src/recursion/intro-notes/call-stack-order-debug.png -------------------------------------------------------------------------------- /src/recursion/intro-notes/factorial-code-animation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCodingDojo/algorithms/HEAD/src/recursion/intro-notes/factorial-code-animation.gif -------------------------------------------------------------------------------- /src/data_structures/Graphs/Dijkstras-video-screencap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCodingDojo/algorithms/HEAD/src/data_structures/Graphs/Dijkstras-video-screencap.png -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "trailingComma": "es5", 4 | "singleQuote": false, 5 | "printWidth": 80, 6 | "tabWidth": 2, 7 | "useTabs": false 8 | } 9 | -------------------------------------------------------------------------------- /src/data_structures/Graphs/connected-vs-complete-graph.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCodingDojo/algorithms/HEAD/src/data_structures/Graphs/connected-vs-complete-graph.jpg -------------------------------------------------------------------------------- /src/data_structures/Graphs/directed-vs-undirected-graph.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCodingDojo/algorithms/HEAD/src/data_structures/Graphs/directed-vs-undirected-graph.jpg -------------------------------------------------------------------------------- /src/recursion/intro-notes/fibonacci-recursion-animation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCodingDojo/algorithms/HEAD/src/recursion/intro-notes/fibonacci-recursion-animation.gif -------------------------------------------------------------------------------- /src/data_structures/Graphs/depth-vs-breadth-search-first.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCodingDojo/algorithms/HEAD/src/data_structures/Graphs/depth-vs-breadth-search-first.gif -------------------------------------------------------------------------------- /src/data_structures/Graphs/cyclic-vs-acyclic-directed-graph.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCodingDojo/algorithms/HEAD/src/data_structures/Graphs/cyclic-vs-acyclic-directed-graph.jpg -------------------------------------------------------------------------------- /spec/support/jasmine.json: -------------------------------------------------------------------------------- 1 | { 2 | "spec_dir": "/", 3 | "spec_files": ["**/*.spec.js"], 4 | "helpers": ["helpers/**/*.js"], 5 | "stopSpecOnExpectationFailure": false, 6 | "random": false 7 | } 8 | -------------------------------------------------------------------------------- /pair-programming.md: -------------------------------------------------------------------------------- 1 | # Pair Programming 2 | 3 | - Students are **_expected_** to assume [these roles](https://docs.google.com/document/d/1kK74NhJwHzM3xnZ6FffZKVLBsQTCBf6WSxh4U-9u9i4/edit#) within a few minutes of entering their breakout rooms. 4 | -------------------------------------------------------------------------------- /src/bit_arithmetic/decimalToBinary/index.js: -------------------------------------------------------------------------------- 1 | function decimalToBinary(decimal) { 2 | let str = ""; 3 | while (decimal > 0) { 4 | const char = decimal % 2; 5 | decimal = Math.floor(decimal / 2); 6 | str = char + str; 7 | } 8 | return "0b" + str; 9 | } 10 | 11 | console.log(decimalToBinary(14)); 12 | -------------------------------------------------------------------------------- /spec/temp.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | // 6 | 7 | testCases.forEach(({ args, expected }, i) => { 8 | describe(`when given testCases[${i}]`, () => { 9 | it("", () => { 10 | expect(testFn(...args)).toEqual(expected); 11 | }); 12 | }); 13 | }); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/bit_arithmetic/binaryToDecimal/index.js.js: -------------------------------------------------------------------------------- 1 | /* 2 | Binary to Decimal 3 | 4 | For practice, convert the following from binary to decimal. Example: 0b100111 becomes 39 . 0b10100101 0b111 0b1111000 0b110110 0b000 0b11 -0b1010 0b100110 0b1010101010 0b111001 0b100101 5 | */ 6 | 7 | function binaryToDecimal(binary) { 8 | let count = 0, 9 | power = 0; 10 | for (let i = binary.length - 1; i >= 2; i--) { 11 | count += binary[i] * Math.pow(2, power++); 12 | } 13 | return count; 14 | } 15 | -------------------------------------------------------------------------------- /src/bit_arithmetic/decimalToHexidecimal/index.js.js: -------------------------------------------------------------------------------- 1 | /* 2 | Decimal to Hexadecimal 3 | 4 | 5 | */ 6 | 7 | function decimalToHexadecimal(decimal) { 8 | const map = { 9 | 10: "A", 10 | 11: "B", 11 | 12: "C", 12 | 13: "D", 13 | 14: "E", 14 | 15: "F", 15 | }; 16 | 17 | let str = ""; 18 | while (decimal > 0) { 19 | const remainder = decimal % 16; 20 | decimal = Math.floor(decimal / 16); 21 | str = (remainder < 10 ? remainder : map[remainder]) + str; 22 | } 23 | return "0x" + str; 24 | } 25 | -------------------------------------------------------------------------------- /src/bit_arithmetic/encodeBytesTo32/index.js.js: -------------------------------------------------------------------------------- 1 | /* 2 | Encode Bytes to 32 3 | 4 | Input: four values between 0-255, 5 | Output: encode them into a 32-bit integer 6 | First should map to most significant 8 bits. Given [0xF0, 0xC3, 0x96, 0x59] , return 4039349849 ( 0xF0C39659 ). 7 | */ 8 | 9 | const hexadecimalToDecimal = require("../2_Tue/hexidecimalToDecimal"); 10 | 11 | function encodeBytesTo32(arr) { 12 | const combined = arr.map((digits) => digits.slice(2)).join(""); 13 | 14 | return hexadecimalToDecimal("0x" + combined); 15 | } 16 | -------------------------------------------------------------------------------- /src/sorts/intro.md: -------------------------------------------------------------------------------- 1 | # Sorts 2 | 3 | - [Sorts Visualize Step by Step](https://www.hackerearth.com/practice/algorithms/sorting/merge-sort/visualize/) 4 | - [Sorts Visualized](https://visualgo.net/en/sorting) 5 | 6 | ## Terminology 7 | 8 | ### [Stable](https://www.geeksforgeeks.org/stability-in-sorting-algorithms/) 9 | 10 | - It is stable if when there are duplicates, the duplicates are left in original order relative to one another 11 | - Making a sort stable incurs overhead (takes more time) 12 | - Click the above link for an example of when stability is needed 13 | -------------------------------------------------------------------------------- /src/DOM/displayFolderStructure/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 |
11 |
12 | folder reference 13 |
14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/strings/rehash/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const str1 = "b70a164c32a20c10"; 6 | const expected1 = "a184b70c42"; 7 | 8 | const testCases = [{ arg: str1, expected: expected1 }]; 9 | 10 | testCases.forEach(({ arg, expected }, i) => { 11 | describe(`when given "${arg}:`, () => { 12 | it("should return the correctly rehashed string.", () => { 13 | expect(testFn(arg)).toEqual(expected); 14 | }); 15 | }); 16 | }); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/misc/swapTwoInts/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Interview question that I received. 3 | 4 | Given two vars, x and y that store integers, swap their values WITHOUT 5 | creating any new variables or using any data types. 6 | 7 | Don't worry about creating a function either. 8 | */ 9 | 10 | var x = 5; 11 | var y = 3; 12 | 13 | console.log(x, y); 14 | 15 | // Your code here. 16 | 17 | console.log(x, y); 18 | 19 | /*****************************************************************************/ 20 | var a = 5; 21 | var b = 3; 22 | 23 | a = a - b; // 5 - 3 = 2 24 | b = b + a; // 3 + 2 = 5 25 | a = b - a; // 5 - 2 = 3 26 | -------------------------------------------------------------------------------- /src/strings/trim/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const str1 = " hello world "; 6 | const expected1 = "hello world"; 7 | 8 | const testCases = [{ arg: str1, expected: expected1 }]; 9 | 10 | testCases.forEach(({ arg, expected }, i) => { 11 | describe(`when given testCases[${i}]`, () => { 12 | it("should return a string that is the given string with all leading and trailing spaces removed.", () => { 13 | expect(testFn(arg)).toEqual(expected); 14 | }); 15 | }); 16 | }); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/strings/stringToWordArray/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const str1 = "Life is not a drill!"; 6 | const expected1 = ["Life", "is", "not", "a", "drill!"]; 7 | 8 | const testCases = [{ arg: str1, expected: expected1 }]; 9 | 10 | testCases.forEach(({ arg, expected }, i) => { 11 | describe(`when given testCases[${i}]`, () => { 12 | it("should convert a string of space separated words into an array of words.", () => { 13 | expect(testFn(arg)).toEqual(expected); 14 | }); 15 | }); 16 | }); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/strings/dupesBetweenSeparators/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const str1 = "to be,; --or\tnot : ;;; to-:: be"; 6 | const expected1 = ["to", "be"]; 7 | 8 | const testCases = [{ args: [str1], expected: expected1 }]; 9 | 10 | testCases.forEach(({ args, expected }, i) => { 11 | describe(`when given testCases[${i}]`, () => { 12 | it("should return an array of the duplicate words between the specified separators.", () => { 13 | expect(testFn(...args)).toEqual(expected); 14 | }); 15 | }); 16 | }); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/design/DiscordCmdCooldowns/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | In discord bot development, commands are created that can be executed by a 3 | message with a special prefix, such as: 4 | 5 | dojo.find john 6 | 7 | where 'dojo.' is a prefix that is checked for and the cmd name is 'find' 8 | and the argument(s) are 'john'. This will trigger a function in the code 9 | with the arguments. 10 | 11 | However, some commands need to be given a cooldown so they are not executed 12 | too frequently. Use OOP to design a way to give commands a cooldown and 13 | keep track of who is on cooldown and for which commands using a command 14 | name, command cooldown, and a unique username as your relevant properties. 15 | */ 16 | -------------------------------------------------------------------------------- /src/recursion/generateAnagrams/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const str1 = "lim"; 6 | const expected1 = ["ilm", "iml", "lim", "lmi", "mil", "mli"]; 7 | // Order of the output array does not matter 8 | 9 | const testCases = [{ arg: str1, expected: expected1 }]; 10 | 11 | testCases.forEach(({ arg: arg, expected }, i) => { 12 | describe(`when given ${arg}`, () => { 13 | it("should return an array of all the anagrams of the given string.", () => { 14 | expect(testFn(arg)).toEqual(jasmine.arrayContaining(expected)); 15 | }); 16 | }); 17 | }); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /src/recursion/inOrderSubsets/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const string1 = "abc"; 6 | // In any order: 7 | const expected1 = ["", "c", "b", "bc", "a", "ac", "ab", "abc"]; 8 | 9 | const testCases = [{ arg: string1, expected: expected1 }]; 10 | 11 | testCases.forEach(({ arg, expected }, i) => { 12 | describe(`when given "${arg}"`, () => { 13 | it("should generate an array with every possible in-order character subset of the given string.", () => { 14 | expect(testFn(arg)).toEqual(jasmine.arrayContaining(expected)); 15 | }); 16 | }); 17 | }); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /src/recursion/reverseStr/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const str1 = "abc"; 6 | const expected1 = "cba"; 7 | 8 | const str2 = ""; 9 | const expected2 = ""; 10 | 11 | const testCases = [ 12 | { arg: str1, expected: expected1 }, 13 | { arg: str2, expected: expected2 }, 14 | ]; 15 | 16 | testCases.forEach(({ arg, expected }, i) => { 17 | describe(`when given "${arg}"`, () => { 18 | it("should return a string that is the reverse of the given string.", () => { 19 | expect(testFn(arg)).toEqual(expected); 20 | }); 21 | }); 22 | }); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /src/bit_arithmetic/hexidecimalToDecimal/index.js.js: -------------------------------------------------------------------------------- 1 | /* 2 | Hexadecimal to Decimal 3 | 4 | 5 | */ 6 | 7 | function hexadecimalToDecimal(hexadecimal) { 8 | const map = { 9 | A: 10, 10 | B: 11, 11 | C: 12, 12 | D: 13, 13 | E: 14, 14 | F: 15, 15 | }; 16 | 17 | let count = 0, 18 | power = 0; 19 | for (let i = hexadecimal.length - 1; i >= 2; i--) { 20 | const char = hexadecimal[i]; 21 | // If not a number, access map for value 22 | // otherwise, use the char, because it is a number 23 | // then do the multiplication before concatenating 24 | count += (isNaN(+char) ? map[char] : char) * Math.pow(16, power++); 25 | } 26 | return count; 27 | } 28 | 29 | module.exports = hexadecimalToDecimal; 30 | -------------------------------------------------------------------------------- /src/arrays/firstNonConsecutive/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Given an array of integers, return the first non-consecutive integer 3 | - a non-consecutive integer is one that is NOT exactly 1 larger 4 | than the previous number 5 | */ 6 | 7 | const nums1 = []; 8 | const expected1 = null; 9 | 10 | const nums2 = [1, 2, 3, 4, 6, 7, 8]; 11 | const expected2 = 6; 12 | 13 | const nums3 = [1, 4, 5, 6]; 14 | const expected3 = 4; 15 | 16 | function firstNonConsecutive(nums) { 17 | for (let i = 1; i < nums.length; i++) { 18 | const prevNum = nums[i - 1]; 19 | const currNum = nums[i]; 20 | 21 | if (prevNum + 1 !== currNum) { 22 | return currNum; 23 | } 24 | } 25 | return null; 26 | } 27 | 28 | module.exports = { firstNonConsecutive }; 29 | -------------------------------------------------------------------------------- /src/objects/invertObj/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const obj1 = { name: "Zaphod", charm: "high", morals: "dicey" }; 6 | const expected1 = { Zaphod: "name", high: "charm", dicey: "morals" }; 7 | 8 | const testCases = [{ args: [obj1], expected: expected1 }]; 9 | 10 | testCases.forEach(({ args, expected }, i) => { 11 | describe(`when given testCases[${i}]`, () => { 12 | it("should return an object that has the keys and values from the given object swapped so that the values are the keys.", () => { 13 | expect(testFn(...args)).toEqual(expected); 14 | }); 15 | }); 16 | }); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/recursion/binaryStringExpansion/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const str1 = "1?0?"; 6 | const expected1 = ["1000", "1001", "1100", "1101"]; 7 | // output list order does not matter 8 | 9 | const testCases = [{ args: [str1], expected: expected1 }]; 10 | 11 | testCases.forEach(({ args, expected }, i) => { 12 | describe(`when given testCases[${i}]`, () => { 13 | it("should return an array of string representing all variations of the given string's question marks replaced with either 0 or 1.", () => { 14 | expect(testFn(...args)).toEqual(jasmine.arrayContaining(expected)); 15 | }); 16 | }); 17 | }); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /src/arrays/sumArrColumns/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const arrA1 = [1, 2, 3]; 6 | const arrB1 = [4, 5, 6]; 7 | const expected1 = [5, 7, 9]; 8 | 9 | const testCases = [ 10 | { 11 | args: [arrA1, arrB1], 12 | expected: expected1, 13 | description: "a 3x3 matrix", 14 | }, 15 | ]; 16 | 17 | testCases.forEach(({ args, expected, description }) => { 18 | describe("when given " + description, () => { 19 | it("should return a new array that is the sum of the columns of the two given arrays.", () => { 20 | expect(testFn(...args)).toEqual(expected); 21 | }); 22 | }); 23 | }); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/amazon/shortestDeliveries/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const coordinates1 = [ 6 | [-2, 5], 7 | [3, 4], 8 | [1, 0], 9 | ]; 10 | const numDeliveries1 = 2; 11 | /* 12 | Explanation: [1, 0] is the shortest distance from [0, 0] 13 | and [3, 4] is the 2nd shortest. 14 | */ 15 | const expected1 = [ 16 | [1, 0], 17 | [3, 4], 18 | ]; 19 | 20 | [[[coordinates1, numDeliveries1], expected1]].forEach( 21 | ([args, expected], i) => { 22 | describe(`when given testCases[${i}]`, () => { 23 | it("", () => { 24 | expect(testFn(...args)).toEqual(expected); 25 | }); 26 | }); 27 | } 28 | ); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /src/strings/decodeStr/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const str1 = "a3b2c1d3"; 6 | const expected1 = "aaabbcddd"; 7 | 8 | const str2 = "a3b2c12d10"; 9 | const expected2 = "aaabbccccccccccccdddddddddd"; 10 | 11 | const testCases = [ 12 | { arg: str1, expected: expected1 }, 13 | { arg: str2, expected: expected2 }, 14 | ]; 15 | 16 | testCases.forEach(({ arg, expected }, i) => { 17 | describe(`when given "${arg}"`, () => { 18 | it("should return a decoded version of the given string such that each char is repeated based on the integer that follows.", () => { 19 | expect(testFn(arg)).toEqual(expected); 20 | }); 21 | }); 22 | }); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /src/strings/vowelsFirst/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const str1 = "hello world"; 6 | const expected1 = "eoohll wrld"; 7 | 8 | const str2 = "More people have been to Hawaii than I have."; 9 | const expected2 = "oeeoeaeeeoaaiiaIaeMr ppl hv bn t Hw thn hv."; 10 | 11 | const testCases = [ 12 | { arg: str1, expected: expected1 }, 13 | { arg: str2, expected: expected2 }, 14 | ]; 15 | 16 | testCases.forEach(({ arg, expected }, i) => { 17 | describe(`when given testCases[${i}]`, () => { 18 | it("should move all the vowels of a string to the front.", () => { 19 | expect(testFn(arg)).toEqual(expected); 20 | }); 21 | }); 22 | }); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /src/recursion/sumToOneDigit/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const num1 = 5; 6 | const expected1 = 5; 7 | 8 | const num2 = 10; 9 | const expected2 = 1; 10 | 11 | const num3 = 25; 12 | const expected3 = 7; 13 | 14 | const testCases = [ 15 | { arg: num1, expected: expected1 }, 16 | { arg: num2, expected: expected2 }, 17 | { arg: num3, expected: expected3 }, 18 | ]; 19 | 20 | testCases.forEach(({ arg, expected }, i) => { 21 | describe(`when given ${arg}`, () => { 22 | it("should sum the given int's digits until it becomes one digit and return that result.", () => { 23 | expect(testFn(arg)).toEqual(expected); 24 | }); 25 | }); 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/recursion/sumArr/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const nums1 = [1, 2, 3]; 6 | const expected1 = 6; 7 | 8 | const nums2 = [1]; 9 | const expected2 = 1; 10 | 11 | const nums3 = []; 12 | const expected3 = 0; 13 | 14 | const testCases = [ 15 | { arg: nums1, expected: expected1 }, 16 | { arg: nums2, expected: expected2 }, 17 | { arg: nums3, expected: expected3 }, 18 | ]; 19 | 20 | testCases.forEach(({ arg, expected }, i) => { 21 | describe(`when given an array of ${arg.length} items`, () => { 22 | it("should return the sum of the given array using recursion.", () => { 23 | expect(testFn(arg)).toEqual(expected); 24 | }); 25 | }); 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/strings/capitalization/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const strings1 = ["hello", "world"]; 6 | const expectedStrings1 = ["Hello", "World"]; 7 | 8 | const testCases = [ 9 | { 10 | arr: strings1, 11 | expected: expectedStrings1, 12 | }, 13 | ]; 14 | 15 | testCases.forEach(({ arr, expected }, i) => { 16 | describe(`when given testCases[${i}]`, () => { 17 | const actual = testFn(arr); 18 | 19 | it("should have capitalized the first letter of each word.", () => { 20 | expect(actual).toEqual(expected); 21 | }); 22 | 23 | it("should have mutated the given array", () => { 24 | expect(arr).toBe(actual); 25 | }); 26 | }); 27 | }); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /src/recursion/recursiveSigma/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const num1 = 5; 6 | const expected1 = 15; 7 | // Explanation: (1+2+3+4+5) 8 | 9 | const num2 = 2.5; 10 | const expected2 = 3; 11 | // Explanation: (1+2) 12 | 13 | const num3 = -1; 14 | const expected3 = 0; 15 | 16 | const testCases = [ 17 | { arg: num1, expected: expected1 }, 18 | { arg: num2, expected: expected2 }, 19 | { arg: num3, expected: expected3 }, 20 | ]; 21 | 22 | testCases.forEach(({ arg, expected }, i) => { 23 | describe(`when given ${arg}`, () => { 24 | it("should return the sum of 1 through the given int inclusive.", () => { 25 | expect(testFn(arg)).toEqual(expected); 26 | }); 27 | }); 28 | }); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /src/strings/getQuoteFromCaret/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const str1 = `wow "jabascript cool" lol "foo"`; 6 | const idx1 = 10; 7 | const expected1 = "jabascript cool"; 8 | 9 | const str2 = `hello "world", good morning.`; 10 | const idx2 = 2; 11 | const expected2 = ""; 12 | 13 | const testCases = [ 14 | { args: [str1, idx1], expected: expected1 }, 15 | { args: [str2, idx2], expected: expected2 }, 16 | ]; 17 | 18 | testCases.forEach(({ args, expected }, i) => { 19 | describe(`when given testCases[${i}]`, () => { 20 | it("return the string enclosed in double quotes that the caret idx is within.", () => { 21 | expect(testFn(...args)).toEqual(expected); 22 | }); 23 | }); 24 | }); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /src/strings/reverseWords/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const str1 = "hello"; 6 | const expected1 = "olleh"; 7 | 8 | const str2 = "hello world"; 9 | const expected2 = "olleh dlrow"; 10 | 11 | const str3 = "abc def ghi"; 12 | const expected3 = "cba fed ihg"; 13 | 14 | const testCases = [ 15 | { arg: str1, expected: expected1 }, 16 | { arg: str2, expected: expected2 }, 17 | { arg: str3, expected: expected3 }, 18 | ]; 19 | 20 | testCases.forEach(({ arg, expected }, i) => { 21 | describe(`when given "${arg}"`, () => { 22 | it("should reverse each word's characters in the given string of space separated words.", () => { 23 | expect(testFn(arg)).toEqual(expected); 24 | }); 25 | }); 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/recreated_methods/Array/concat/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const arrA1 = ["a", "b"]; 6 | const arrB1 = [1, 2, 3]; 7 | const expected1 = ["a", "b", 1, 2, 3]; 8 | 9 | const arrA2 = [1, 2, 3]; 10 | const arrB2 = ["a", "b"]; 11 | const expected2 = [1, 2, 3, "a", "b"]; 12 | 13 | const testCases = [ 14 | { args: [arrA1, arrB1], expected: expected1 }, 15 | { args: [arrA2, arrB2], expected: expected2 }, 16 | ]; 17 | 18 | testCases.forEach(({ args, expected }, i) => { 19 | describe(`when given testCases[${i}]`, () => { 20 | it("should return a new array that has all the first given array's items and then the second given array's items.", () => 21 | expect(testFn(...args)).toEqual(expected)); 22 | }); 23 | }); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "algorithms", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "npx jasmine", 8 | "prepare": "husky install", 9 | "pretty-quick": "pretty-quick --staged", 10 | "format": "prettier --write ." 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/TheCodingDojo/algorithms.git" 15 | }, 16 | "author": { 17 | "name": "Neil Mosunic", 18 | "email": "neilm813@gmail.com", 19 | "url": "https://github.com/neilm813" 20 | }, 21 | "license": "ISC", 22 | "bugs": { 23 | "url": "https://github.com/TheCodingDojo/algorithms/issues" 24 | }, 25 | "homepage": "https://github.com/TheCodingDojo/algorithms#readme", 26 | "devDependencies": { 27 | "husky": "^6.0.0", 28 | "jasmine": "^3.5.0", 29 | "prettier": "^2.3.1", 30 | "pretty-quick": "^3.1.1" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/arrays/balanceIndex/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const nums1 = [-2, 5, 7, 0, 3]; 6 | const expected1 = 2; 7 | 8 | const nums2 = [9, 9]; 9 | const expected2 = -1; 10 | 11 | const testCases = [ 12 | { 13 | args: [nums1], 14 | expected: expected1, 15 | description: "middle balanced array", 16 | }, 17 | { args: [nums2], expected: expected2, description: "unbalanced array" }, 18 | ]; 19 | 20 | testCases.forEach(({ args, expected, description }) => { 21 | describe("when given " + description, () => { 22 | it("should return the index where the sum to the left and the right of the index are equal, or -1.", () => { 23 | expect(testFn(...args)).toEqual(expected); 24 | }); 25 | }); 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/recursion/factorial/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const num1 = 3; 6 | const expected1 = 6; 7 | // Explanation: 1*2*3 = 6 8 | 9 | const num2 = 6.8; 10 | const expected2 = 720; 11 | // Explanation: 1*2*3*4*5*6 = 720 12 | 13 | const num3 = 0; 14 | const expected3 = 1; 15 | 16 | const testCases = [ 17 | { args: [num1], expected: expected1 }, 18 | { args: [num2], expected: expected2 }, 19 | { args: [num3], expected: expected3 }, 20 | ]; 21 | 22 | testCases.forEach(({ args, expected }, i) => { 23 | describe(`when given testCases[${i}]`, () => { 24 | it("should return the product of 1 through the given int inclusive.", () => { 25 | expect(testFn(...args)).toEqual(expected); 26 | }); 27 | }); 28 | }); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /src/strings/bracesValid/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const str1 = "W(a{t}s[o(n{ c}o)m]e )h[e{r}e]!"; 6 | const expected1 = true; 7 | 8 | const str2 = "D(i{a}l[ t]o)n{e"; 9 | const expected2 = false; 10 | 11 | const str3 = "A(1)s[O (n]0{t) 0}k"; 12 | const expected3 = false; 13 | 14 | const testCases = [ 15 | { args: [str1], expected: expected1 }, 16 | { args: [str2], expected: expected2 }, 17 | { args: [str3], expected: expected3 }, 18 | ]; 19 | 20 | testCases.forEach(({ args, expected }, i) => { 21 | describe(`when given testCases[${i}]`, () => { 22 | it("should return whether or not the braces in the given string are valid.", () => { 23 | expect(testFn(...args)).toEqual(expected); 24 | }); 25 | }); 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/DOM/iterativelyRenderTree/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /src/strings/reverseString/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const str1 = "creature"; 6 | const expected1 = "erutaerc"; 7 | 8 | const str2 = "dog"; 9 | const expected2 = "god"; 10 | 11 | const str3 = "hello"; 12 | const expected3 = "olleh"; 13 | 14 | const str4 = ""; 15 | const expected4 = ""; 16 | 17 | const testCases = [ 18 | { arg: str1, expected: expected1 }, 19 | { arg: str2, expected: expected2 }, 20 | { arg: str3, expected: expected3 }, 21 | { arg: str4, expected: expected4 }, 22 | ]; 23 | 24 | testCases.forEach(({ arg, expected }, i) => { 25 | describe(`when given "${arg}"`, () => { 26 | it("should return a string that is the reverse of the given string.", () => { 27 | expect(testFn(arg)).toEqual(expected); 28 | }); 29 | }); 30 | }); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /src/strings/reverseWordOrder/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const str1 = "This is a test"; 6 | const expected1 = "test a is This"; 7 | 8 | const str2 = "hello"; 9 | const expected2 = "hello"; 10 | 11 | const str3 = " This is a test "; 12 | const expected3 = "test a is This"; 13 | 14 | const testCases = [ 15 | { arg: str1, expected: expected1 }, 16 | { arg: str2, expected: expected2 }, 17 | { arg: str3, expected: expected3 }, 18 | ]; 19 | 20 | testCases.forEach(({ arg, expected }, i) => { 21 | describe(`when given "${arg}"`, () => { 22 | it("should return a string with the order of the space separated words reversed, but the words themselves should not be reversed.", () => { 23 | expect(testFn(arg)).toEqual(expected); 24 | }); 25 | }); 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/strings/bookIndex/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const nums1 = [1, 13, 14, 15, 37, 38, 70]; 6 | const expected1 = "1, 13-15, 37-38, 70"; 7 | 8 | const nums2 = [5, 6, 7, 8, 9]; 9 | const expected2 = "5-9"; 10 | 11 | const nums3 = [1, 2, 3, 7, 9, 15, 16, 17]; 12 | const expected3 = "1-3, 7, 9, 15-17"; 13 | 14 | const testCases = [ 15 | { args: [nums1], expected: expected1 }, 16 | { args: [nums2], expected: expected2 }, 17 | { args: [nums3], expected: expected3 }, 18 | ]; 19 | 20 | testCases.forEach(({ args, expected }, i) => { 21 | describe(`when given testCases[${i}]`, () => { 22 | it("should return a string formatted as comma separated pages and page ranges when needed.", () => { 23 | expect(testFn(...args)).toEqual(expected); 24 | }); 25 | }); 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/strings/isPalindrome/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const str1 = "a x a"; 6 | const expected1 = true; 7 | 8 | const str2 = "racecar"; 9 | const expected2 = true; 10 | 11 | const str3 = "Dud"; 12 | const expected3 = false; 13 | 14 | const str4 = "oho!"; 15 | const expected4 = false; 16 | 17 | const testCases = [ 18 | { args: [str1], expected: expected1 }, 19 | { args: [str2], expected: expected2 }, 20 | { args: [str3], expected: expected3 }, 21 | { args: [str4], expected: expected4 }, 22 | ]; 23 | 24 | testCases.forEach(({ args, expected }, i) => { 25 | describe(`when given testCases[${i}]`, () => { 26 | it("should return whether or not the given string is a palindrome.", () => { 27 | expect(testFn(...args)).toEqual(expected); 28 | }); 29 | }); 30 | }); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /src/strings/caseInsensitiveStringCompare/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const strA1 = "ABC"; 6 | const strB1 = "abc"; 7 | const expected1 = true; 8 | 9 | const strA2 = "ABC"; 10 | const strB2 = "abd"; 11 | const expected2 = false; 12 | 13 | const strA3 = "ABC"; 14 | const strB3 = "bc"; 15 | const expected3 = false; 16 | 17 | const testCases = [ 18 | { args: [strA1, strB1], expected: expected1 }, 19 | { args: [strA2, strB2], expected: expected2 }, 20 | { args: [strA3, strB3], expected: expected3 }, 21 | ]; 22 | 23 | testCases.forEach(({ args, expected }, i) => { 24 | describe(`when given testCases[${i}]`, () => { 25 | it("should return whether the strings are equal while ignoring case.", () => { 26 | expect(testFn(...args)).toEqual(expected); 27 | }); 28 | }); 29 | }); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /src/strings/removeDupeWords/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const s1 = ""; 6 | const expected1 = ""; 7 | 8 | const s2 = "hi"; 9 | const expected2 = "hi"; 10 | 11 | const s3 = "hi hi hi"; 12 | const expected3 = "hi"; 13 | 14 | const s4 = "hello flat hello flat world"; 15 | const expected4 = "hello flat world"; 16 | 17 | const testCases = [ 18 | { arg: s1, expected: expected1 }, 19 | { arg: s2, expected: expected2 }, 20 | { arg: s3, expected: expected3 }, 21 | { arg: s4, expected: expected4 }, 22 | ]; 23 | 24 | testCases.forEach(({ arg, expected }, i) => { 25 | describe(`when given "${arg}"`, () => { 26 | it("should remove duplicate words from the given string and return the deduped string.", () => { 27 | expect(testFn(arg)).toEqual(expected); 28 | }); 29 | }); 30 | }); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /src/strings/stringDedupe/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const str1 = "abcABC"; 6 | const expected1 = "abcABC"; 7 | 8 | const str2 = "helloo"; 9 | const expected2 = "helo"; 10 | 11 | const str3 = ""; 12 | const expected3 = ""; 13 | 14 | const str4 = "aa"; 15 | const expected4 = "a"; 16 | 17 | const testCases = [ 18 | { args: [str1], expected: expected1 }, 19 | { args: [str2], expected: expected2 }, 20 | { args: [str3], expected: expected3 }, 21 | { args: [str4], expected: expected4 }, 22 | ]; 23 | 24 | testCases.forEach(({ args, expected }, i) => { 25 | describe(`when given testCases[${i}]`, () => { 26 | it("should return a string that is the given string with duplicate characters removed.", () => { 27 | expect(testFn(...args)).toEqual(expected); 28 | }); 29 | }); 30 | }); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /src/recursion/removeConsecDupeWords/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const s1 = ""; 6 | const expected1 = ""; 7 | 8 | const s2 = "one two two three"; 9 | const expected2 = "one two three"; 10 | 11 | const s3 = "one one two"; 12 | const expected3 = "one two"; 13 | 14 | const s4 = "one one one two two two"; 15 | const expected4 = "one two"; 16 | 17 | const testCases = [ 18 | { arg: s1, expected: expected1 }, 19 | { arg: s2, expected: expected2 }, 20 | { arg: s3, expected: expected3 }, 21 | { arg: s4, expected: expected4 }, 22 | ]; 23 | 24 | testCases.forEach(({ arg, expected }, i) => { 25 | describe(`when given "${arg}"`, () => { 26 | it("should recursively remove consecutive dupe words from a string.", () => { 27 | expect(testFn(arg)).toEqual(expected); 28 | }); 29 | }); 30 | }); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /src/strings/kaprekarsConstant/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const number1 = 3524; 6 | /* 7 | Explanation: 8 | 1. 5432 - 2345 = 3087 9 | 2. 8730 - 0378 = 8352 10 | 3. 8532 - 2358 = 6174 11 | */ 12 | const expected1 = 3; 13 | 14 | const number2 = 2111; 15 | const expected2 = 5; 16 | 17 | const number3 = 9831; 18 | const expected3 = 7; 19 | 20 | const testCases = [ 21 | { arg: number1, expected: expected1 }, 22 | { arg: number2, expected: expected2 }, 23 | { arg: number3, expected: expected3 }, 24 | ]; 25 | 26 | testCases.forEach(({ arg, expected }, i) => { 27 | describe(`when given ${arg}`, () => { 28 | it("The number of summing operations required to reach kaprekars constant (6174).", () => { 29 | expect(testFn(arg)).toEqual(expected); 30 | }); 31 | }); 32 | }); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /src/arrays/balancePoint/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const nums1 = [1, 2, 3, 4, 10]; 6 | const expected1 = true; 7 | // Explanation: between indices 3 & 4 8 | 9 | const nums2 = [1, 2, 4, 2, 1]; 10 | const expected2 = false; 11 | 12 | const testCases = [ 13 | { 14 | args: [nums1], 15 | expected: expected1, 16 | description: "array where last number is the sum of the rest", 17 | }, 18 | { args: [nums2], expected: expected2, description: "unbalanced array" }, 19 | ]; 20 | 21 | testCases.forEach(({ args, expected, description }) => { 22 | describe("when given " + description, () => { 23 | it("should return whether there exists a point between indexes where the sum to the left and the right are equal.", () => { 24 | expect(testFn(...args)).toEqual(expected); 25 | }); 26 | }); 27 | }); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /src/recursion/binarySearch/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const nums1 = [1, 3, 5, 6]; 6 | const searchNum1 = 4; 7 | const expected1 = false; 8 | 9 | const nums2 = [4, 5, 6, 8, 12]; 10 | const searchNum2 = 5; 11 | const expected2 = true; 12 | 13 | const nums3 = [3, 4, 6, 8, 12]; 14 | const searchNum3 = 3; 15 | const expected3 = true; 16 | 17 | const testCases = [ 18 | { args: [nums1, searchNum1], expected: expected1 }, 19 | { args: [nums2, searchNum2], expected: expected2 }, 20 | { args: [nums3, searchNum3], expected: expected3 }, 21 | ]; 22 | 23 | testCases.forEach(({ args, expected }, i) => { 24 | describe(`when given testCases[${i}]`, () => { 25 | it("should return whether or not the given array contains the given int.", () => { 26 | expect(testFn(...args)).toEqual(expected); 27 | }); 28 | }); 29 | }); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /src/strings/encodeStr/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const str1 = "aaaabbcddd"; 6 | const expected1 = "a4b2c1d3"; 7 | 8 | const str2 = ""; 9 | const expected2 = ""; 10 | 11 | const str3 = "a"; 12 | const expected3 = "a"; 13 | 14 | const str4 = "bbcc"; 15 | const expected4 = "bbcc"; 16 | 17 | const testCases = [ 18 | { args: [str1], expected: expected1 }, 19 | { args: [str2], expected: expected2 }, 20 | { args: [str3], expected: expected3 }, 21 | { args: [str4], expected: expected4 }, 22 | ]; 23 | 24 | testCases.forEach(({ args, expected }, i) => { 25 | describe(`when given testCases[${i}]`, () => { 26 | it("should return the given string encoded so that consecutively repeated chars are replaced with an int of its frequency.", () => { 27 | expect(testFn(...args)).toEqual(expected); 28 | }); 29 | }); 30 | }); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /src/recursion/coronaVirusFloodFill/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const socialSpaceGrid = [ 6 | ["Jon2", "Jane2", null, null], 7 | [null, "Jon1", "Jane1", null], 8 | ["Jane4", "patient zero", null, "Jon3"], 9 | ["Jon4", null, "Jane3", null], 10 | ]; 11 | const patientZeroPoint = { x: 1, y: 2 }; 12 | const expected = ["Jane4", "Jon4", "Jon1", "Jane1", "Jane2", "Jon2"]; 13 | // order of output list does not matter 14 | 15 | const testCases = [ 16 | { args: [socialSpaceGrid, patientZeroPoint], expected: expected }, 17 | ]; 18 | 19 | testCases.forEach(({ args, expected }, i) => { 20 | describe(`when given testCases[${i}]`, () => { 21 | it("should return an array of the names new corona virus cases based on flood fill from a starting point.", () => { 22 | expect(testFn(...args)).toEqual(expected); 23 | }); 24 | }); 25 | }); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /src/objects/fewestCoinChange/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const cents1 = 25; 6 | const expected1 = { quarter: 1 }; 7 | 8 | const cents2 = 50; 9 | const expected2 = { quarter: 2 }; 10 | 11 | const cents3 = 9; 12 | const expected3 = { nickel: 1, penny: 4 }; 13 | 14 | const cents4 = 99; 15 | const expected4 = { quarter: 3, dime: 2, penny: 4 }; 16 | 17 | const testCases = [ 18 | { cents: cents1, expected: expected1 }, 19 | { cents: cents2, expected: expected2 }, 20 | { cents: cents3, expected: expected3 }, 21 | { cents: cents4, expected: expected4 }, 22 | ]; 23 | 24 | testCases.forEach(({ cents, expected }, i) => { 25 | describe(`when given case ${cents} cents`, () => { 26 | it("should return an object detailing the fewest coins needed to get to the given cents.", () => 27 | expect(testFn(cents)).toEqual(expected)); 28 | }); 29 | }); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /src/strings/acronymize/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const str1 = "abstraction polymorphism inheritance encapsulation"; 6 | const expected1 = "APIE"; 7 | 8 | const str2 = "object oriented programming"; 9 | const expected2 = "OOP"; 10 | 11 | const str3 = "software development life cycle"; 12 | const expected3 = "SDLC"; 13 | 14 | const str4 = " global information tracker "; 15 | const expected4 = "GIT"; 16 | 17 | const testCases = [ 18 | { arg: str1, expected: expected1 }, 19 | { arg: str2, expected: expected2 }, 20 | { arg: str3, expected: expected3 }, 21 | { arg: str4, expected: expected4 }, 22 | ]; 23 | 24 | testCases.forEach(({ arg, expected }, i) => { 25 | describe(`when given testCases[${i}]`, () => { 26 | it("should return the acronym version of the given string.", () => { 27 | expect(testFn(arg)).toEqual(expected); 28 | }); 29 | }); 30 | }); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /src/strings/questionMarks/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const str1 = "aa6?9"; 6 | const expected1 = false; 7 | 8 | const str2 = "acc?7??sss?3rr1??????5"; 9 | const expected2 = true; 10 | 11 | const str3 = "?3?d?dad?7??????3"; 12 | const expected3 = true; 13 | 14 | const str4 = "7??????3"; 15 | // Explanation: too many question marks. 16 | const expected4 = false; 17 | 18 | const testCases = [ 19 | { arg: str1, expected: expected1 }, 20 | { arg: str2, expected: expected2 }, 21 | { arg: str3, expected: expected3 }, 22 | { arg: str4, expected: expected4 }, 23 | ]; 24 | 25 | testCases.forEach(({ arg, expected }, i) => { 26 | describe(`when given "${arg}"`, () => { 27 | it("should return whether or not the given string contains exactly 3 questions marks between every two ints that sum to 10.", () => { 28 | expect(testFn(arg)).toEqual(expected); 29 | }); 30 | }); 31 | }); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /src/objects/zipArraysIntoMap/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const keys1 = ["abc", 3, "yo"]; 6 | const vals1 = [42, "wassup", true]; 7 | const expected1 = { 8 | abc: 42, 9 | 3: "wassup", 10 | yo: true, 11 | }; 12 | 13 | const keys2 = []; 14 | const vals2 = []; 15 | const expected2 = {}; 16 | 17 | const testCases = [ 18 | { 19 | args: [keys1, vals1], 20 | expected: expected1, 21 | description: "3 key value pairs", 22 | }, 23 | { 24 | args: [keys2, vals2], 25 | expected: expected2, 26 | description: "an empty array for both keys and values", 27 | }, 28 | ]; 29 | 30 | testCases.forEach(({ args, expected }, i) => { 31 | describe(`when given testCases[${i}]`, () => { 32 | it("should return an object that has the keys and values from the two given arrays.", () => 33 | expect(testFn(...args)).toEqual(expected)); 34 | }); 35 | }); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /src/sorts/radixSort/index.js: -------------------------------------------------------------------------------- 1 | // setup 2 | function getPosition(num, place) { 3 | return Math.floor(Math.abs(num) / Math.pow(10, place)) % 10; 4 | } 5 | 6 | // get num with most digits 7 | function getMax(arr) { 8 | let max = 0; 9 | for (let num of arr) { 10 | if (max < num.toString().length) { 11 | max = num.toString().length; 12 | } 13 | } 14 | return max; 15 | } 16 | 17 | // setup 18 | function radixSort(arr) { 19 | const max = getMax(arr); // length of the max digit in the array 20 | 21 | for (let i = 0; i < max; i++) { 22 | let buckets = Array.from({ length: 10 }, () => []); 23 | } 24 | return arr; 25 | } 26 | 27 | function radixSort(arr) { 28 | const max = getMax(arr); // length of the max digit in the array 29 | 30 | for (let i = 0; i < max; i++) { 31 | let buckets = Array.from({ length: 10 }, () => []); 32 | for (let j = 0; j < arr.length; j++) { 33 | buckets[getPosition(arr[j], i)].push(arr[j]); // pushing into buckets 34 | } 35 | arr = [].concat(...buckets); 36 | } 37 | return arr; 38 | } 39 | 40 | module.exports = { 41 | radixSort, 42 | }; 43 | -------------------------------------------------------------------------------- /src/strings/addHonorific/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const honorific1 = "Mr."; 6 | const names1 = []; 7 | const expected1 = []; 8 | 9 | const honorific2 = "Sir"; 10 | const names2 = ["Sanchez, Rick", "Smith, Jerry"]; 11 | const expected2 = ["Sir Rick Sanchez", "Sir Jerry Smith"]; 12 | 13 | const honorific3 = "Mrs."; 14 | const names3 = ["HorseDoctor, Beth"]; 15 | const expected3 = ["Mrs. Beth HorseDoctor"]; 16 | 17 | const testCases = [ 18 | { args: [honorific1, names1], expected: expected1 }, 19 | { args: [honorific2, names2], expected: expected2 }, 20 | { args: [honorific3, names3], expected: expected3 }, 21 | ]; 22 | 23 | testCases.forEach(({ args, expected }, i) => { 24 | describe(`when given testCases[${i}]`, () => { 25 | it("should return an array of the given names in the format of: Honorific FirstName LastName.", () => { 26 | expect(testFn(...args)).toEqual(expected); 27 | }); 28 | }); 29 | }); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /src/strings/isAnagram/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const strA1 = "yes"; 6 | const strB1 = "eys"; 7 | const expected1 = true; 8 | 9 | const strA2 = "yes"; 10 | const strB2 = "eYs"; 11 | const expected2 = true; 12 | 13 | const strA3 = "no"; 14 | const strB3 = "noo"; 15 | const expected3 = false; 16 | 17 | const strA4 = "silent"; 18 | const strB4 = "listen"; 19 | const expected4 = true; 20 | 21 | const testCases = [ 22 | { args: [strA1, strB1], expected: expected1 }, 23 | { args: [strA2, strB2], expected: expected2 }, 24 | { args: [strA3, strB3], expected: expected3 }, 25 | { args: [strA4, strB4], expected: expected4 }, 26 | ]; 27 | 28 | testCases.forEach(({ args, expected }, i) => { 29 | describe(`when given testCases[${i}]`, () => { 30 | it("should return whether or not the 1st given string is an anagram of the 2nd.", () => { 31 | expect(testFn(...args)).toEqual(expected); 32 | }); 33 | }); 34 | }); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /src/misc/clockHandAngles/index.js: -------------------------------------------------------------------------------- 1 | // For input of 3600 secs (equivalent to 1:00:00), print "Hour hand: 30 degs. Minute hand: 0 degs. Second hand: 0 degs." 2 | clockHandAngles(3600); 3 | 4 | // For an input parameter seconds of 119730 (which is equivalent to 9:15:30 plus 24 hours!), you should log "Hour hand: 277.745 degs. Minute hand: 93 degs. Second hand: 180 degs." Note: in the second example, the angle for the minute hand is not simply 90 degrees; it has advanced a bit further, because of the additional 30 seconds in that minute so far. 5 | 6 | // "Hour hand: 277.745 degs. Minute hand: 93 degs. Second hand: 180 degs." 7 | clockHandAngles(119730); 8 | 9 | function clockHandAngles(sec) { 10 | var h = 0.0; 11 | var m = 0.0; 12 | while (sec >= 3600) { 13 | if (h >= 24) { 14 | h = 0; 15 | } 16 | h++; 17 | sec -= 3600; 18 | } 19 | while (sec >= 60) { 20 | if (m >= 60) { 21 | m = 0; 22 | } 23 | m++; 24 | sec -= 60; 25 | } 26 | 27 | sd = sec * 6; 28 | md = m * 6 + sec / 10; 29 | hd = h * 30 + md / 12; 30 | 31 | return `Hour hand: ${hd} degrees, minute hand: ${md} degrees, second hand: ${sd} degrees.`; 32 | } 33 | -------------------------------------------------------------------------------- /src/arrays/countEvenNegatives/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const nums1 = [1, 5, -1, 2, -4, 9, -10, 0, -3, -2]; 6 | const expected1 = 3; 7 | 8 | const nums2 = []; 9 | const expected2 = 0; 10 | 11 | const nums3 = [-4, -2, -6]; 12 | const expected3 = 3; 13 | 14 | const testCases = [ 15 | { 16 | args: [nums1], 17 | expected: expected1, 18 | description: "an unordered mixture", 19 | }, 20 | { 21 | args: [nums2], 22 | expected: expected2, 23 | description: "an empty array", 24 | }, 25 | { 26 | args: [nums3], 27 | expected: expected3, 28 | description: "all negative evens", 29 | }, 30 | ]; 31 | 32 | testCases.forEach(({ args, expected, description }) => { 33 | describe("when given " + description, () => { 34 | it("should return a count of how many numbers are both negative and even.", () => { 35 | expect(testFn(...args)).toEqual(expected); 36 | }); 37 | }); 38 | }); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /src/recursion/fibonacci/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const num1 = 0; 6 | const expected1 = 0; 7 | 8 | const num2 = 1; 9 | const expected2 = 1; 10 | 11 | const num3 = 2; 12 | const expected3 = 1; 13 | 14 | const num4 = 3; 15 | const expected4 = 2; 16 | 17 | const num5 = 4; 18 | const expected5 = 3; 19 | 20 | const num6 = 8; 21 | const expected6 = 21; 22 | 23 | const testCases = [ 24 | { arg: num1, expected: expected1 }, 25 | { arg: num2, expected: expected2 }, 26 | { arg: num3, expected: expected3 }, 27 | { arg: num4, expected: expected4 }, 28 | { arg: num5, expected: expected5 }, 29 | { arg: num6, expected: expected6 }, 30 | ]; 31 | 32 | testCases.forEach(({ arg, expected }, i) => { 33 | describe(`when given ${arg}`, () => { 34 | it("should return the number from the fibonacci sequence at the given ints position (nth fibonacci num).", () => { 35 | expect(testFn(arg)).toEqual(expected); 36 | }); 37 | }); 38 | }); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /src/strings/removeDupeWords/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Given in an interview. 3 | 4 | Given a string of words 5 | return a string with the duplicate words removed 6 | 7 | no built in methods 8 | */ 9 | 10 | const s1 = ""; 11 | const expected1 = ""; 12 | 13 | const s2 = "hi"; 14 | const expected2 = "hi"; 15 | 16 | const s3 = "hi hi hi"; 17 | const expected3 = "hi"; 18 | 19 | const s4 = "hello flat hello flat world"; 20 | const expected4 = "hello flat world"; 21 | 22 | function removeDupeWords(str) {} 23 | 24 | /*****************************************************************************/ 25 | 26 | function removeDupeWords(str) { 27 | let deduped = ""; 28 | const seen = {}; 29 | let word = ""; 30 | 31 | for (let i = 0; i < str.length; i++) { 32 | if (str[i] !== " ") { 33 | word += str[i]; 34 | } 35 | 36 | if ((str[i] === " " || i === str.length - 1) && word.length > 0) { 37 | if (!seen.hasOwnProperty(word)) { 38 | deduped.length !== 0 && (deduped += " "); 39 | deduped += word; 40 | seen[word] = true; 41 | } 42 | word = ""; 43 | } 44 | } 45 | return deduped; 46 | } 47 | 48 | module.exports = { removeDupeWords }; 49 | -------------------------------------------------------------------------------- /src/arrays/minToFront/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const nums1 = [1, 5, 2, 9]; 6 | const expected1 = [1, 5, 2, 9]; 7 | 8 | const nums2 = [5, 1, 0, 2, 3, 0]; 9 | const expected2 = [0, 5, 1, 2, 3, 0]; 10 | 11 | const testCases = [ 12 | { 13 | args: [nums1], 14 | expected: expected1, 15 | description: "the minimum at the front", 16 | }, 17 | { 18 | args: [nums2], 19 | expected: expected2, 20 | description: "the minimum near the front and at the end", 21 | }, 22 | ]; 23 | 24 | testCases.forEach(({ args, expected, description }) => { 25 | describe("when given " + description, () => { 26 | const ret = testFn(...args); 27 | 28 | it("should move the min value in the given array to the front and return the given array.", () => { 29 | expect(ret).toEqual(expected); 30 | }); 31 | 32 | it("should return the given array, not a new array.", () => { 33 | expect(ret).toBe(args[0]); 34 | }); 35 | }); 36 | }); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /src/data_structures/Graphs/travelingSalesman/travelingSalesman.md: -------------------------------------------------------------------------------- 1 | # Traveling Salesman 2 | 3 | ## Overview 4 | 5 | Given a list of cities and the distances between each pair of cities, what is 6 | the shortest possible route that visits each city exactly once and returns to 7 | the origin city? 8 | 9 | ### In Technical Terms 10 | 11 | Given a complete graph with weighted edges (as an adjacency matrix) what is the 12 | Hamiltonian cycle (path that visits every node once) of minimum cost? 13 | 14 | ### Time Complexity 15 | 16 | - Brute Force - O(n!) - Factorial, checks every possible path. 17 | - Dynamic Programming: O(n^2 \* 2^n) 18 | 19 | | n | n! | n^2 \* 2^n | 20 | | --- | --------------- | ---------- | 21 | | 1 | 1 | 2 | 22 | | 2 | 2 | 16 | 23 | | 3 | 6 | 72 | 24 | | 4 | 24 | 256 | 25 | | 5 | 120 | 800 | 26 | | 6 | 720 | 2304 | 27 | | ... | ... | ... | 28 | | 15 | 1307674368000 | 7372800 | 29 | | 16 | 20922789888000 | 16777216 | 30 | | 17 | 355687428096000 | 37879808 | 31 | 32 | ### Dynamic Programming Approach 33 | -------------------------------------------------------------------------------- /src/recursion/sumArr/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Recursively sum an arr of ints 3 | */ 4 | 5 | const nums1 = [1, 2, 3]; 6 | const expected1 = 6; 7 | 8 | const nums2 = [1]; 9 | const expected2 = 1; 10 | 11 | const nums3 = []; 12 | const expected3 = 0; 13 | 14 | /** 15 | * Add params if needed for recursion 16 | * Recursively sums the given array. 17 | * - Time: O(?). 18 | * - Space: O(?). 19 | * @param {Array} nums 20 | * @returns {number} The sum of the given nums. 21 | */ 22 | function sumArr(nums) {} 23 | 24 | /*****************************************************************************/ 25 | 26 | /** 27 | * Recursively sums the given array. 28 | * - Time: O(n) linear. 29 | * - Space: O(n) linear due to the call stack. 30 | * @param {Array} nums 31 | * @returns {number} The sum of the given nums. 32 | */ 33 | function sumArr(nums = [], i = 0) { 34 | if (i === nums.length) { 35 | return 0; 36 | } 37 | return nums[i] + sumArr(nums, i + 1); 38 | } 39 | 40 | function sumArr2(nums = [], sum = 0, i = 0) { 41 | if (i === nums.length) { 42 | return sum; 43 | } 44 | return sumArr2(nums, sum + nums[i], i + 1); 45 | } 46 | 47 | module.exports = { sumArr, sumArr2 }; 48 | -------------------------------------------------------------------------------- /src/arrays/firstNonConsecutive/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const nums1 = []; 6 | const expected1 = null; 7 | 8 | const nums2 = [1, 2, 3, 4, 6, 7, 8]; 9 | const expected2 = 6; 10 | 11 | const nums3 = [1, 4, 5, 6]; 12 | const expected3 = 4; 13 | 14 | const testCases = [ 15 | { 16 | args: [nums1], 17 | expected: expected1, 18 | description: "an empty array", 19 | }, 20 | { 21 | args: [nums2], 22 | expected: expected2, 23 | description: "a non consecutive number near the middle", 24 | }, 25 | { 26 | args: [nums3], 27 | expected: expected3, 28 | description: "a non consecutive number near the start", 29 | }, 30 | ]; 31 | 32 | testCases.forEach(({ args, expected, description }) => { 33 | describe("when given " + description, () => { 34 | it("should return the first number that is not exactly 1 larger than the previous.", () => { 35 | expect(testFn(...args)).toEqual(expected); 36 | }); 37 | }); 38 | }); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /src/arrays/reverseArr/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const arr1 = [1, 2, 3]; 6 | const expected1 = [3, 2, 1]; 7 | 8 | const arr2 = ["a", "b"]; 9 | const expected2 = ["b", "a"]; 10 | 11 | const arr3 = ["a"]; 12 | const expected3 = ["a"]; 13 | 14 | const arr4 = []; 15 | const expected4 = []; 16 | 17 | const testCases = [ 18 | { inputArr: arr1, expected: expected1 }, 19 | { inputArr: arr2, expected: expected2 }, 20 | { inputArr: arr3, expected: expected3 }, 21 | { inputArr: arr4, expected: expected4 }, 22 | ]; 23 | 24 | testCases.forEach(({ inputArr, expected, description }) => { 25 | describe("when given " + description, () => { 26 | const outputArr = testFn(inputArr); 27 | 28 | it("should reverse the given array in place and return the given array.", () => { 29 | expect(outputArr).toEqual(expected); 30 | }); 31 | 32 | it("should return the same array, not a new array.", () => { 33 | expect(inputArr).toBe(outputArr); 34 | }); 35 | }); 36 | }); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /src/sorts/radixSort/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const numsOrdered = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 6 | const numsRandomOrder = [9, 2, 5, 6, 4, 3, 7, 10, 1, 8]; 7 | const numsReversed = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]; 8 | const expected = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 9 | 10 | const testCases = [ 11 | { 12 | arg: numsOrdered, 13 | expected: expected, 14 | description: "an already sorted array", 15 | }, 16 | { 17 | arg: numsRandomOrder, 18 | expected: expected, 19 | description: "a randomly ordered array", 20 | }, 21 | { 22 | arg: numsReversed, 23 | expected: expected, 24 | description: "a reverse-ordered array", 25 | }, 26 | ]; 27 | 28 | testCases.forEach(({ arg, expected, description }, i) => { 29 | describe(`when given ${description}`, () => { 30 | const actual = testFn(arg); 31 | 32 | it("should return a sorted array.", () => { 33 | expect(actual).toEqual(expected); 34 | }); 35 | }); 36 | }); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /src/arrays/findTriplets/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const nums1 = [0, -1, 2, -3, 1]; 6 | const expected1 = true; 7 | 8 | const nums2 = [3, 1, 2, 6, 4]; 9 | const expected2 = false; 10 | 11 | const nums3 = [5, -1, 3, 2, -4, 1, 6]; 12 | const expected3 = true; 13 | 14 | const testCases = [ 15 | { 16 | args: [nums1], 17 | expected: expected1, 18 | description: "a mix of positives, negatives, and zero", 19 | }, 20 | { 21 | args: [nums2], 22 | expected: expected2, 23 | description: "all positive numbers", 24 | }, 25 | { 26 | args: [nums3], 27 | expected: expected3, 28 | description: "a mix of positive and negative numbers", 29 | }, 30 | ]; 31 | 32 | testCases.forEach(({ args, expected, description }) => { 33 | describe("when given " + description, () => { 34 | it("should return whether or not there are 3 ints that add up to 0.", () => { 35 | expect(testFn(...args)).toEqual(expected); 36 | }); 37 | }); 38 | }); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /src/strings/longestPalindromicSubstring/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const str1 = "what up, daddy-o?"; 6 | const expected1 = "dad"; 7 | 8 | const str2 = "uh, not much"; 9 | const expected2 = "u"; 10 | 11 | const str3 = "Yikes! my favorite racecar erupted!"; 12 | const expected3 = "e racecar e"; 13 | 14 | const str4 = "a1001x20002y5677765z"; 15 | const expected4 = "5677765"; 16 | 17 | const str5 = "a1001x20002y567765z"; 18 | const expected5 = "567765"; 19 | 20 | const testCases = [ 21 | { args: [str1], expected: expected1 }, 22 | { args: [str2], expected: expected2 }, 23 | { args: [str3], expected: expected3 }, 24 | { args: [str4], expected: expected4 }, 25 | { args: [str5], expected: expected5 }, 26 | ]; 27 | 28 | testCases.forEach(({ args, expected }, i) => { 29 | describe(`when given testCases[${i}]`, () => { 30 | it("should return the longest palindrome contained within the given string.", () => { 31 | expect(testFn(...args)).toEqual(expected); 32 | }); 33 | }); 34 | }); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /src/strings/palindromeFromSubstr/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This helper function avoids having to visit the chars multiple times to both 3 | * check if it is a palindrome and to then slice to get the palindrome. 4 | * - Time: O(n) linear. n = right - left which could be the full string. 5 | * - Space: O(n) linear. 6 | * @param {string} str 7 | * @param {number} left The left idx to start at inclusive. 8 | * @param {number} right The left idx to end at exclusive. 9 | * @returns {string} The palindrome or an empty string. 10 | */ 11 | function getPalindrome(str, left = 0, right = str.length) { 12 | let leftStr = ""; 13 | let rightStr = ""; 14 | const len = right - left; 15 | const half = Math.floor(len / 2); 16 | let leftIdx = left - 1; 17 | 18 | for (let i = 0; i < half; i++) { 19 | leftIdx += 1; 20 | const rightIdx = right - 1 - i; 21 | 22 | if (str[leftIdx] !== str[rightIdx]) { 23 | return ""; 24 | } 25 | 26 | leftStr += str[leftIdx]; 27 | rightStr = str[rightIdx] + rightStr; 28 | } 29 | 30 | // For odd palindromes we need to save middle letter since loop skips it. 31 | if (len % 2 !== 0) { 32 | leftStr += str[leftIdx + 1]; 33 | } 34 | 35 | return leftStr + rightStr; 36 | } 37 | -------------------------------------------------------------------------------- /src/arrays/flatten2dArray/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const twoDimArr1 = [ 6 | [1, 2, 3], 7 | [4, 5, 6], 8 | [7, 8, 9], 9 | ]; 10 | const expected1 = [1, 2, 3, 4, 5, 6, 7, 8, 9]; 11 | 12 | const twoDimArr2 = [[1], [2], [3]]; 13 | const expected2 = [1, 2, 3]; 14 | 15 | const twoDimArr3 = [[], [], [10, 20]]; 16 | const expected3 = [10, 20]; 17 | 18 | const testCases = [ 19 | { args: [twoDimArr1], expected: expected1, description: "a 3x3 matrix" }, 20 | { args: [twoDimArr2], expected: expected2, description: "a 1x3 matrix" }, 21 | { 22 | args: [twoDimArr3], 23 | expected: expected3, 24 | description: "a mixed length matrix with some empty nested arrays", 25 | }, 26 | ]; 27 | 28 | testCases.forEach(({ args, expected, description }) => { 29 | describe("when given " + description, () => { 30 | it("should flatten the given 2d array into a 1d array and preserver the order of the items.", () => { 31 | expect(testFn(...args)).toEqual(expected); 32 | }); 33 | }); 34 | }); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /src/recursion/lowestCommonMult/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const num1A = 1; 6 | const num1B = 1; 7 | const expected1 = 1; 8 | 9 | const num2A = 5; 10 | const num2B = 10; 11 | const expected2 = 10; 12 | 13 | const num3A = 10; 14 | const num3B = 5; 15 | const expected3 = 10; 16 | 17 | const num4A = 6; 18 | const num4B = 8; 19 | const expected4 = 24; 20 | 21 | const num5A = 15; 22 | const num5B = 25; 23 | const expected5 = 75; 24 | 25 | const testCases = [ 26 | { args: [num1A, num1B], expected: expected1 }, 27 | { args: [num2A, num2B], expected: expected2 }, 28 | { args: [num3A, num3B], expected: expected3 }, 29 | { args: [num4A, num4B], expected: expected4 }, 30 | { args: [num5A, num5B], expected: expected5 }, 31 | ]; 32 | 33 | testCases.forEach(({ args: [a, b], expected }, i) => { 34 | describe(`when given (${(a, b)})`, () => { 35 | it("should return the lowest common multiple of the two given ints.", () => { 36 | expect(testFn(a, b)).toEqual(expected); 37 | }); 38 | }); 39 | }); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /src/strings/parensValid/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const str1 = "Y(3(p)p(3)r)s"; 6 | const expected1 = true; 7 | 8 | const str2 = "N(0(p)3"; 9 | const expected2 = false; 10 | // Explanation: not every parenthesis is closed. 11 | 12 | const str3 = "N(0)t ) 0(k"; 13 | const expected3 = false; 14 | // Explanation: because the underlined ")" is premature: there is nothing open for it to close. 15 | 16 | const str4 = "a(b))(c"; 17 | const expected4 = false; 18 | // Explanation: same number of opens and closes but the 2nd closing closes nothing 19 | 20 | const testCases = [ 21 | { args: [str1], expected: expected1 }, 22 | { args: [str2], expected: expected2 }, 23 | { args: [str3], expected: expected3 }, 24 | { args: [str4], expected: expected4 }, 25 | ]; 26 | 27 | testCases.forEach(({ args, expected }, i) => { 28 | describe(`when given testCases[${i}]`, () => { 29 | it("should return whether or not the parenthesis in the given string are valid.", () => { 30 | expect(testFn(...args)).toEqual(expected); 31 | }); 32 | }); 33 | }); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /src/strings/isRotation/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const strA1 = "ABCD"; 6 | const strB1 = "CDAB"; 7 | // Explanation: if you start from A in the 2nd string, the letters are in the same order, just rotated 8 | const expected1 = true; 9 | 10 | const strA2 = "ABCD"; 11 | const strB2 = "CDBA"; 12 | // Explanation: all same letters in 2nd string, but out of order 13 | const expected2 = false; 14 | 15 | const strA3 = "ABCD"; 16 | const strB3 = "BCDAB"; 17 | // Explanation: same letters in correct order but there is an extra letter. 18 | const expected3 = false; 19 | 20 | const testCases = [ 21 | { args: [strA1, strB1], expected: expected1 }, 22 | { args: [strA2, strB2], expected: expected2 }, 23 | { args: [strA3, strB3], expected: expected3 }, 24 | ]; 25 | 26 | testCases.forEach(({ args, expected }, i) => { 27 | describe(`when given testCases[${i}]`, () => { 28 | it("should return whether or not the 1st given string is a rotation of the 2nd given string.", () => { 29 | expect(testFn(...args)).toEqual(expected); 30 | }); 31 | }); 32 | }); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /src/design/Observable/index.js: -------------------------------------------------------------------------------- 1 | class Observable { 2 | constructor(functionThatTakesObserver) { 3 | this._functionThatTakesObserver = functionThatTakesObserver; 4 | } 5 | 6 | subscribe(observer) { 7 | return this._functionThatTakesObserver(observer); 8 | } 9 | } 10 | 11 | const testObservable = new Observable((observer) => { 12 | observer.next("data 1"); 13 | observer.next("data 2"); 14 | 15 | setInterval(() => { 16 | if (Math.random() < 0.5) { 17 | observer.next("async data refreshed"); 18 | } else { 19 | observer.error("error getting data"); 20 | } 21 | observer.complete(); 22 | }, 5000); 23 | }); 24 | 25 | const observer1 = { 26 | next(data) { 27 | console.log("\nobserver1️⃣ ", data); 28 | }, 29 | error(e) { 30 | console.log("\nobserver1️⃣ ", e); 31 | }, 32 | complete() { 33 | console.log(`observer1️⃣ complete\n${"-".repeat(20)}`); 34 | }, 35 | }; 36 | 37 | const observer2 = { 38 | next(data) { 39 | console.log("\nobserver2️⃣ ", data); 40 | }, 41 | error(e) { 42 | console.log("\nobserver2️⃣ ", e); 43 | }, 44 | complete() { 45 | console.log(`observer2️⃣ complete\n${"~".repeat(20)}`); 46 | }, 47 | }; 48 | 49 | testObservable.subscribe(observer1); 50 | testObservable.subscribe(observer2); 51 | -------------------------------------------------------------------------------- /src/strings/rotateStr/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const str = "Hello World"; 6 | 7 | const rotateAmnt1 = 0; 8 | const expected1 = "Hello World"; 9 | 10 | const rotateAmnt2 = 1; 11 | const expected2 = "dHello Worl"; 12 | 13 | const rotateAmnt3 = 2; 14 | const expected3 = "ldHello Wor"; 15 | 16 | const rotateAmnt4 = 4; 17 | const expected4 = "orldHello W"; 18 | 19 | const rotateAmnt5 = 13; 20 | const expected5 = "ldHello Wor"; 21 | 22 | const testCases = [ 23 | { args: [str, rotateAmnt1], expected: expected1 }, 24 | { args: [str, rotateAmnt2], expected: expected2 }, 25 | { args: [str, rotateAmnt3], expected: expected3 }, 26 | { args: [str, rotateAmnt4], expected: expected4 }, 27 | { args: [str, rotateAmnt5], expected: expected5 }, 28 | ]; 29 | 30 | testCases.forEach(({ args, expected }, i) => { 31 | describe(`when given testCases[${i}]`, () => { 32 | it("should return a string that is the given string with chars rotated to the right by the given int amount.", () => { 33 | expect(testFn(...args)).toEqual(expected); 34 | }); 35 | }); 36 | }); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /src/strings/vowelsFirst/index.js: -------------------------------------------------------------------------------- 1 | // given a string, return a new string that has all the vowels of the given string first 2 | 3 | /** 4 | * Moves all the vowels of a string to the front. 5 | * - Time: O(?). 6 | * - Space: O(?). 7 | * @param {string} str 8 | * @returns {string} 9 | */ 10 | function vowelsFirst(str) {} 11 | 12 | /*****************************************************************************/ 13 | 14 | /** 15 | * Moves all the vowels of a string to the front. 16 | * - Time: O(n) linear. 17 | * - Space: O(n) linear, as n (length of str) grows we store that much more 18 | * memory in the vars. 19 | * @param {string} str 20 | * @returns {string} 21 | */ 22 | function vowelsFirst(str) { 23 | let vowelsStr = ""; 24 | let consonantsStr = ""; 25 | 26 | for (let i = 0; i < str.length; i++) { 27 | const char = str[i]; 28 | const lowerCaseChar = char.toLocaleLowerCase(); 29 | 30 | if ( 31 | lowerCaseChar === "a" || 32 | lowerCaseChar === "e" || 33 | lowerCaseChar === "i" || 34 | lowerCaseChar === "o" || 35 | lowerCaseChar === "u" 36 | ) { 37 | vowelsStr += char; 38 | } else { 39 | consonantsStr += char; 40 | } 41 | } 42 | return vowelsStr + consonantsStr; 43 | } 44 | 45 | module.exports = { vowelsFirst }; 46 | -------------------------------------------------------------------------------- /src/arrays/allNonConsecutive/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const nums1 = [1, 2, 3, 4, 6, 7, 8, 10]; 6 | const expected1 = [ 7 | { i: 4, n: 6 }, 8 | { i: 7, n: 10 }, 9 | ]; 10 | 11 | const nums2 = []; 12 | const expected2 = []; 13 | 14 | const nums3 = [1, 3, 7, 9]; 15 | const expected3 = [ 16 | { i: 1, n: 3 }, 17 | { i: 2, n: 7 }, 18 | { i: 3, n: 9 }, 19 | ]; 20 | 21 | const testCases = [ 22 | { 23 | args: [nums1], 24 | expected: expected1, 25 | description: "non-consecutive one through ten", 26 | }, 27 | { 28 | args: [nums2], 29 | expected: expected2, 30 | description: "an empty array", 31 | }, 32 | { 33 | args: [nums3], 34 | expected: expected3, 35 | description: "all odds", 36 | }, 37 | ]; 38 | 39 | testCases.forEach(({ args, expected, description }) => { 40 | describe("when given " + description, () => { 41 | it("should return all the non consecutive ints in the given sorted array of ints.", () => 42 | expect(testFn(...args)).toEqual(expected)); 43 | }); 44 | }); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /src/arrays/tacoTruck/index.js: -------------------------------------------------------------------------------- 1 | // https://login.codingdojo.com/m/667/15334/111786 2 | 3 | function distanceBetweenTwoPoints(pointA, pointB) { 4 | const firstDistance = Math.abs(pointA[0] - pointB[0]); 5 | const secondDistance = Math.abs(pointA[1] - pointB[1]); 6 | return firstDistance + secondDistance; 7 | } 8 | 9 | /** 10 | * 11 | */ 12 | function findOptimalTruckLocation(customerLocations = []) { 13 | let shortestAverageDistance = 0; 14 | let locationWithShortestAverageDistance = null; 15 | 16 | // For each point 17 | for (let i = 0; i < customerLocations.length; i++) { 18 | let totalDistance = 0; 19 | 20 | // Find it's distance to every other point 21 | for (let j = 0; j < arr.length; j++) { 22 | if (i === j) { 23 | continue; 24 | } 25 | 26 | totalDistance += distanceBetweenTwoPoints( 27 | customerLocations[i], 28 | customerLocations[j] 29 | ); 30 | } 31 | 32 | // To get an average distance 33 | let averageDistance = totalDistance / (customerLocations.length - 1); 34 | 35 | if (averageDistance < shortestAverageDistance) { 36 | shortestAverageDistance = averageDistance; 37 | locationWithShortestAverageDistance = customerLocations[i]; 38 | } 39 | 40 | console.log(averageDistance); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/recursion/inOrderSubsets/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | String: In-Order Subsets 3 | 4 | Create strSubsets(str). Return an array with every possible in-order 5 | character subset of str. The resultant array itself need not be in any 6 | specific order – it is the subset of letters in each string that must be in 7 | the same order as they were in the original string. 8 | 9 | Input: "abc" , 10 | Output: return an array that includes ["", "c", "b", "bc", "a", "ac", "ab", "abc"] (in any order). 11 | */ 12 | 13 | const string1 = "abc"; 14 | // In any order: 15 | const expected1 = ["", "c", "b", "bc", "a", "ac", "ab", "abc"]; 16 | 17 | /** 18 | * Generates an array with every possible in-order character subset of the 19 | * given string. 20 | * Add additional params for recursion as needed. 21 | * @param {string} str 22 | */ 23 | function inOrderSubsets(str) {} 24 | 25 | /*****************************************************************************/ 26 | 27 | function inOrderSubsets(str, solutions = [], partial = "") { 28 | solutions.push(partial); 29 | 30 | for (let i = 0; i < str.length; i++) { 31 | const sliced = str.slice(i + 1); 32 | inOrderSubsets(sliced, solutions, partial + str[i]); 33 | } 34 | 35 | return solutions; 36 | } 37 | 38 | module.exports = { 39 | inOrderSubsets, 40 | }; 41 | -------------------------------------------------------------------------------- /src/arrays/binarySearch/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const nums1 = [1, 3, 5, 6]; 6 | const searchNum1 = 4; 7 | const expected1 = false; 8 | 9 | const nums2 = [4, 5, 6, 8, 12]; 10 | const searchNum2 = 5; 11 | const expected2 = true; 12 | 13 | const nums3 = [3, 4, 6, 8, 12]; 14 | const searchNum3 = 3; 15 | const expected3 = true; 16 | 17 | const testCases = [ 18 | { 19 | args: [nums1, searchNum1], 20 | expected: expected1, 21 | description: "small array with no match", 22 | }, 23 | { 24 | args: [nums2, searchNum2], 25 | expected: expected2, 26 | description: "small array second index match.", 27 | }, 28 | { 29 | args: [nums3, searchNum3], 30 | expected: expected3, 31 | description: "small array first index match", 32 | }, 33 | ]; 34 | 35 | testCases.forEach(({ args, expected, description }) => { 36 | describe("when given " + description, () => { 37 | it("should return whether the search number exists in the array.", () => { 38 | expect(testFn(...args)).toEqual(expected); 39 | }); 40 | }); 41 | }); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /src/arrays/dedupeSorted/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const nums1 = [1, 1, 1, 1]; 6 | const expected1 = [1]; 7 | 8 | const nums2 = [1, 1, 2, 2, 3, 3]; 9 | const expected2 = [1, 2, 3]; 10 | 11 | const nums3 = [1, 1, 2, 3, 3, 4]; 12 | const expected3 = [1, 2, 3, 4]; 13 | 14 | const nums4 = [1, 1]; 15 | const expected4 = [1]; 16 | 17 | const testCases = [ 18 | { args: [nums1], expected: expected1, description: "four ones" }, 19 | { 20 | args: [nums2], 21 | expected: expected2, 22 | description: "1-3 with two of each", 23 | }, 24 | { 25 | args: [nums3], 26 | expected: expected3, 27 | description: "1-4 with some dupes", 28 | }, 29 | { 30 | args: [nums4], 31 | expected: expected4, 32 | description: "two of the same number", 33 | }, 34 | ]; 35 | 36 | testCases.forEach(({ args, expected, description }) => { 37 | describe("when given " + description, () => { 38 | it("should return an array with duplicate values removed.", () => { 39 | expect(testFn(...args)).toEqual(expected); 40 | }); 41 | }); 42 | }); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /src/design/BufferSequence/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | From Microsoft interview March 2021 3 | 4 | Make a Buffer that receives an int and prints the value, but only if the given 5 | value is in sequence with the previous given int. If it isn’t, then wait until 6 | the buffer receives the missing values before printing the rest of the 7 | sequence. 8 | 9 | Create a class 10 | */ 11 | 12 | class BufferSequence { 13 | constructor() { 14 | this.lastPrintedNum = null; 15 | this.storage = {}; 16 | } 17 | 18 | print(num) { 19 | this.lastPrintedNum = num; 20 | console.log(num); 21 | } 22 | 23 | handler(num) { 24 | this.storage[num] = num; 25 | 26 | if (this.lastPrintedNum === null) { 27 | this.print(num); 28 | return; 29 | } 30 | 31 | if (num === this.lastPrintedNum + 1) { 32 | while (this.storage.hasOwnProperty(this.lastPrintedNum + 1)) { 33 | this.print(this.lastPrintedNum + 1); 34 | } 35 | } 36 | } 37 | } 38 | 39 | const buffer = new BufferSequence(); 40 | 41 | /* Uncomment one line at a time to test. */ 42 | buffer.handler(5); // prints 5 43 | // buffer.handler(6); // prints 6 44 | // buffer.handler(10); // no print 45 | // buffer.handler(9); // no print 46 | // buffer.handler(7); // prints 7 47 | // buffer.handler(8); // prints 8, 9, 10 on new lines. 48 | -------------------------------------------------------------------------------- /src/strings/backspaceStringCompare/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const S1 = "ab#c"; 6 | const T1 = "ad#c"; 7 | const expected1 = true; 8 | // Explanation: Both S and T become "ac" 9 | 10 | const S2 = "ab##"; 11 | const T2 = "c#d#"; 12 | const expected2 = true; 13 | // Explanation: Both S and T become "" 14 | 15 | const S3 = "a##c"; 16 | const T3 = "#a#c"; 17 | const expected3 = true; 18 | // Explanation: Both S and T become "c" 19 | 20 | const S4 = "a#c"; 21 | const T4 = "b"; 22 | const expected4 = false; 23 | // Explanation: S becomes "c" while T becomes "b". 24 | 25 | const testCases = [ 26 | { args: [S1, T1], expected: expected1 }, 27 | { args: [S2, T2], expected: expected2 }, 28 | { args: [S3, T3], expected: expected3 }, 29 | { args: [S4, T4], expected: expected4 }, 30 | ]; 31 | 32 | testCases.forEach(({ args, expected }, i) => { 33 | describe(`when given testCases[${i}]`, () => { 34 | it("should return whether or not the strings are equal after processing the backspaces.", () => { 35 | expect(testFn(...args)).toEqual(expected); 36 | }); 37 | }); 38 | }); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /src/strings/lengthOfLongestSubstring/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const str1 = "abcabcbb"; 6 | const expected1 = 3; 7 | // Explanation: The answer is "abc", with the length of 3. 8 | 9 | const str2 = "bbbbb"; 10 | const expected2 = 1; 11 | // Explanation: The answer is "b", with the length of 1. 12 | 13 | const str3 = "pwwkew"; 14 | const expected3 = 3; 15 | /* Explanation: The answer is "wke", with the length of 3. 16 | Note that the answer must be a substring, "pwke" is a subsequence and not a substring. */ 17 | 18 | const str4 = "dvadf"; 19 | const expected4 = 4; 20 | // Explanation: "vadf" 21 | 22 | const testCases = [ 23 | { arg: str1, expected: expected1 }, 24 | { arg: str2, expected: expected2 }, 25 | { arg: str3, expected: expected3 }, 26 | { arg: str4, expected: expected4 }, 27 | ]; 28 | 29 | testCases.forEach(({ arg, expected }, i) => { 30 | describe(`when given "${arg}"`, () => { 31 | it("should return the length of the longest substring (without dupes) from the given string.", () => { 32 | expect(testFn(arg)).toEqual(expected); 33 | }); 34 | }); 35 | }); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /src/design/BehaviorSubject/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | BehaviorSubject is a design pattern for keeping track of a value that changes 3 | over time where multiple different parts of your app need to know when the 4 | value changes because they need to perform some task when that happens. 5 | 6 | As an analogy, think of multiple researches that are all studying the same 7 | behavior subject (say an animal) to try to understand it's behavior, but each 8 | researcher is studying the behavior for different reasons. That means each 9 | researcher needs to be alerted when the behavior changes so they can study 10 | respond to that behavior event by studying it in their specific way. 11 | */ 12 | 13 | class BehaviorSubject { 14 | constructor(startVal) { 15 | this.value = startVal; 16 | this.subscribers = []; 17 | } 18 | 19 | subscribe(callback) { 20 | this.subscribers.push(callback); 21 | this.emit(); 22 | } 23 | 24 | emit() { 25 | for (let i = 0; i < this.subscribers.length; i++) { 26 | this.subscribers[i](this.value); 27 | } 28 | } 29 | 30 | getValue() { 31 | return this.value; 32 | } 33 | 34 | /** 35 | * Updates the value and notifies all subscribers. 36 | * @param {any} value The new value. 37 | */ 38 | next(value) { 39 | this.value = value; 40 | this.emit(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/recursion/greatestCommonFactor/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const a1 = 5; 6 | const b1 = 5; 7 | const expected1 = 5; 8 | 9 | const a2 = 6; 10 | const b2 = 20; 11 | const expected2 = 2; 12 | 13 | const a3 = 54; 14 | const b3 = 12; 15 | const expected3 = 6; 16 | 17 | const a4 = 12; 18 | const b4 = 54; 19 | const expected4 = 6; 20 | 21 | const a5 = 65; 22 | const b5 = 25; 23 | const expected5 = 5; 24 | 25 | const a6 = 123456; 26 | const b6 = 987654; 27 | const expected6 = 6; 28 | 29 | const testCases = [ 30 | { args: [a1, b1], expected: expected1 }, 31 | { args: [a2, b2], expected: expected2 }, 32 | { args: [a3, b3], expected: expected3 }, 33 | { args: [a4, b4], expected: expected4 }, 34 | { args: [a5, b5], expected: expected5 }, 35 | // { args: [a6, b6], expected: expected6 }, 36 | ]; 37 | 38 | testCases.forEach(({ args: [a, b], expected }, i) => { 39 | describe(`when given (${a}, ${b})`, () => { 40 | it("should return the greatest common factor of the two given numbers.", () => { 41 | expect(testFn(a, b)).toEqual(expected); 42 | }); 43 | }); 44 | }); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /src/strings/canBuildS1FromS2/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const strA1 = "Hello World"; 6 | const strB1 = "lloeh wordl"; 7 | const expected1 = true; 8 | 9 | const strA2 = "Hey"; 10 | const strB2 = "hello"; 11 | const expected2 = false; 12 | // Explanation: second string is missing a "y" 13 | 14 | const strA3 = "hello"; 15 | const strB3 = "helo"; 16 | const expected3 = false; 17 | // Explanation: second string doesn't have enough "l" letters 18 | 19 | const strA4 = "hello"; 20 | const strB4 = "lllheo"; 21 | const expected4 = true; 22 | 23 | const testCases = [ 24 | { args: [strA1, strB1], expected: expected1 }, 25 | { args: [strA2, strB2], expected: expected2 }, 26 | { args: [strA3, strB3], expected: expected3 }, 27 | { args: [strA4, strB4], expected: expected4 }, 28 | ]; 29 | 30 | testCases.forEach(({ args, expected }, i) => { 31 | describe(`when given testCases[${i}]`, () => { 32 | it("should return whether or not the first given string can be built using the characters from the second given string.", () => { 33 | expect(testFn(...args)).toEqual(expected); 34 | }); 35 | }); 36 | }); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /src/sorts/bubbleSort/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const numsOrdered = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 6 | const numsRandomOrder = [9, 2, 5, 6, 4, 3, 7, 10, 1, 8]; 7 | const numsReversed = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]; 8 | const expected = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 9 | 10 | const testCases = [ 11 | { 12 | arg: numsOrdered, 13 | expected: expected, 14 | description: "an already sorted array", 15 | }, 16 | { 17 | arg: numsRandomOrder, 18 | expected: expected, 19 | description: "a randomly ordered array", 20 | }, 21 | { 22 | arg: numsReversed, 23 | expected: expected, 24 | description: "a reverse-ordered array", 25 | }, 26 | ]; 27 | 28 | testCases.forEach(({ arg, expected, description }, i) => { 29 | describe(`when given ${description}`, () => { 30 | const actual = testFn(arg); 31 | 32 | it("should return a sorted array.", () => { 33 | expect(actual).toEqual(expected); 34 | }); 35 | 36 | it("should have returned the same array after mutating it.", () => { 37 | expect(actual).toBe(arg); 38 | }); 39 | }); 40 | }); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /src/sorts/quickSort/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const numsOrdered = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 6 | const numsRandomOrder = [9, 2, 5, 6, 4, 3, 7, 10, 1, 8]; 7 | const numsReversed = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]; 8 | const expected = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 9 | 10 | const testCases = [ 11 | { 12 | arg: numsOrdered, 13 | expected: expected, 14 | description: "an already sorted array", 15 | }, 16 | { 17 | arg: numsRandomOrder, 18 | expected: expected, 19 | description: "a randomly ordered array", 20 | }, 21 | { 22 | arg: numsReversed, 23 | expected: expected, 24 | description: "a reverse-ordered array", 25 | }, 26 | ]; 27 | 28 | testCases.forEach(({ arg, expected, description }, i) => { 29 | describe(`when given ${description}`, () => { 30 | const actual = testFn(arg); 31 | 32 | it("should return a sorted array.", () => { 33 | expect(actual).toEqual(expected); 34 | }); 35 | 36 | it("should have returned the same array after mutating it.", () => { 37 | expect(actual).toBe(arg); 38 | }); 39 | }); 40 | }); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /src/strings/canStringBecomePalindrome/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const str1 = ""; 6 | const expected1 = false; 7 | 8 | const str2 = "a"; 9 | const expected2 = true; 10 | 11 | const str3 = "ddaa"; 12 | const expected3 = true; 13 | // Explanation: "daad" or "adda" 14 | 15 | const str4 = "dda"; 16 | const expected4 = true; 17 | // Explanation: "dad" 18 | 19 | const str5 = "aaadd"; 20 | const expected5 = true; 21 | // Explanation: "daaad" 22 | 23 | const str6 = "abc"; 24 | const expected6 = false; 25 | 26 | const testCases = [ 27 | { args: [str1], expected: expected1 }, 28 | { args: [str2], expected: expected2 }, 29 | { args: [str3], expected: expected3 }, 30 | { args: [str4], expected: expected4 }, 31 | { args: [str5], expected: expected5 }, 32 | { args: [str6], expected: expected6 }, 33 | ]; 34 | 35 | testCases.forEach(({ args, expected }, i) => { 36 | describe(`when given testCases[${i}]`, () => { 37 | it("should return whether or not the given string could be rearranged into a palindrome.", () => { 38 | expect(testFn(...args)).toEqual(expected); 39 | }); 40 | }); 41 | }); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /src/sorts/insertionSort/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const numsOrdered = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 6 | const numsRandomOrder = [9, 2, 5, 6, 4, 3, 7, 10, 1, 8]; 7 | const numsReversed = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]; 8 | const expected = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 9 | 10 | const testCases = [ 11 | { 12 | arg: numsOrdered, 13 | expected: expected, 14 | description: "an already sorted array", 15 | }, 16 | { 17 | arg: numsRandomOrder, 18 | expected: expected, 19 | description: "a randomly ordered array", 20 | }, 21 | { 22 | arg: numsReversed, 23 | expected: expected, 24 | description: "a reverse-ordered array", 25 | }, 26 | ]; 27 | 28 | testCases.forEach(({ arg, expected, description }, i) => { 29 | describe(`when given ${description}`, () => { 30 | const actual = testFn(arg); 31 | 32 | it("should return a sorted array.", () => { 33 | expect(actual).toEqual(expected); 34 | }); 35 | 36 | it("should have returned the same array after mutating it.", () => { 37 | expect(actual).toBe(arg); 38 | }); 39 | }); 40 | }); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /src/sorts/selectionSort/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const numsOrdered = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 6 | const numsRandomOrder = [9, 2, 5, 6, 4, 3, 7, 10, 1, 8]; 7 | const numsReversed = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]; 8 | const expected = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 9 | 10 | const testCases = [ 11 | { 12 | arg: numsOrdered, 13 | expected: expected, 14 | description: "an already sorted array", 15 | }, 16 | { 17 | arg: numsRandomOrder, 18 | expected: expected, 19 | description: "a randomly ordered array", 20 | }, 21 | { 22 | arg: numsReversed, 23 | expected: expected, 24 | description: "a reverse-ordered array", 25 | }, 26 | ]; 27 | 28 | testCases.forEach(({ arg, expected, description }, i) => { 29 | describe(`when given ${description}`, () => { 30 | const actual = testFn(arg); 31 | 32 | it("should return a sorted array.", () => { 33 | expect(actual).toEqual(expected); 34 | }); 35 | 36 | it("should have returned the same array after mutating it.", () => { 37 | expect(actual).toBe(arg); 38 | }); 39 | }); 40 | }); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /src/objects/insert/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const table1 = "users"; 6 | const insertData1 = { first_name: "John", last_name: "Doe" }; 7 | const expected1 = 8 | "INSERT INTO users (first_name, last_name) VALUES ('John', 'Doe');"; 9 | 10 | // Bonus: 11 | const insertData2 = { 12 | first_name: "John", 13 | last_name: "Doe", 14 | age: 30, 15 | is_admin: false, 16 | }; 17 | const expected2 = 18 | "INSERT INTO users (first_name, last_name, age, is_admin) VALUES ('John', 'Doe', 30, false);"; 19 | // Explanation: no quotes areount the int or the bool, technically in SQL the bool would become a 0 or 1, but don't worry about that here. 20 | 21 | const testCases = [ 22 | { args: [table1, insertData1], expected: expected1 }, 23 | { args: [table1, insertData2], expected: expected2, type: "bonus" }, 24 | ]; 25 | 26 | testCases.forEach(({ args, expected }, i) => { 27 | describe(`when given testCases[${i}]`, () => { 28 | it("should return a SQL insert command as a string where the given objects key value pairs are the columns and values.", () => { 29 | expect(testFn(...args)).toEqual(expected); 30 | }); 31 | }); 32 | }); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /src/arrays/diagonalDifference/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const squareMatrix1 = [ 6 | [1, 2, 3], 7 | [4, 5, 6], 8 | [9, 8, 9], 9 | ]; 10 | const expected1 = 2; 11 | /* 12 | left to right diagonal: 1 + 5 + 9 = 15 13 | right to left diagonal: 3 + 5 + 9 = 17 14 | absolute difference = 2 15 | */ 16 | 17 | const squareMatrix2 = [ 18 | [1, 2, 3, 4, 5], 19 | [1, 2, 3, 4, 5], 20 | [1, 2, 3, 4, 5], 21 | [1, 2, 3, 4, 5], 22 | [1, 2, 3, 4, 5], 23 | ]; 24 | const expected2 = 0; 25 | 26 | const testCases = [ 27 | { 28 | args: [squareMatrix1], 29 | expected: expected1, 30 | description: "a 3x3 matrix", 31 | }, 32 | { 33 | args: [squareMatrix2], 34 | expected: expected2, 35 | description: "a 5x5 matrix with equal diagonals", 36 | }, 37 | ]; 38 | 39 | testCases.forEach(({ args, expected, description }) => { 40 | describe("when given " + description, () => { 41 | it("should return the absolute difference between the sums of the diagonals of a given square matrix.", () => { 42 | expect(testFn(...args)).toEqual(expected); 43 | }); 44 | }); 45 | }); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /src/strings/outputToJson/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Alumni interview question in 2021. 3 | 4 | Given the output text from an executable file, convert it into JSON. 5 | 6 | The result should be a JSON array of two objects. 7 | */ 8 | 9 | const fs = require("fs"); 10 | 11 | // Open VSCode to the folder this file is in for it to find the output.txt 12 | function outputToJson(filePath = "./output.txt") { 13 | try { 14 | const jsonStr = fs 15 | .readFileSync(filePath, "utf-8") 16 | .split("\n") 17 | .reduce((str, row, i, arr) => { 18 | if (i === arr.length - 1) { 19 | return str + "}]"; 20 | } 21 | 22 | // end of object 23 | if (row == "\r") { 24 | return str + "},{"; 25 | } 26 | 27 | // Comma before new KVP unless it's the first KVP. 28 | str[str.length - 1] !== "{" && (str += ","); 29 | 30 | let [key, val] = row.split(":"); 31 | const trimmedVal = val.trim(); 32 | val = 33 | trimmedVal !== "true" && trimmedVal !== "false" && isNaN(+trimmedVal) 34 | ? `"${trimmedVal}"` 35 | : trimmedVal; 36 | 37 | return str + `"${key.trim()}": ${val}`; 38 | }, "[{"); 39 | return JSON.parse(jsonStr); 40 | } catch (error) { 41 | console.log(error); 42 | return []; 43 | } 44 | } 45 | 46 | module.exports = { outputToJson }; 47 | -------------------------------------------------------------------------------- /src/sorts/mergeSort/index.spec.js: -------------------------------------------------------------------------------- 1 | const { mergeSort } = require("."); 2 | 3 | describe(mergeSort.name, () => { 4 | const numsOrdered = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 5 | const numsRandomOrder = [9, 2, 5, 6, 4, 3, 7, 10, 1, 8]; 6 | const numsReversed = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]; 7 | const expected = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 8 | 9 | const testCases = [ 10 | { 11 | arg: numsOrdered, 12 | expected: expected, 13 | description: "an already sorted array", 14 | }, 15 | { 16 | arg: numsRandomOrder, 17 | expected: expected, 18 | description: "a randomly ordered array", 19 | }, 20 | { 21 | arg: numsReversed, 22 | expected: expected, 23 | description: "a reverse-ordered array", 24 | }, 25 | ]; 26 | 27 | testCases.forEach(({ arg, expected, description }, i) => { 28 | describe(`when given ${description}`, () => { 29 | const arrCopy = [...arg]; 30 | const actual = mergeSort(arg); 31 | 32 | it("should return a sorted array.", () => { 33 | expect(actual).toEqual(expected); 34 | }); 35 | 36 | it("should have returned a new array.", () => { 37 | expect(actual).not.toBe(arg); 38 | }); 39 | 40 | it("should not have mutated the given array.", () => { 41 | expect(arrCopy).toEqual(arg); 42 | }); 43 | }); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /src/recreated_methods/Array/unshift/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const arr1 = [1, 2, 3]; 6 | const newItem1 = 0; 7 | const expected1 = 4; 8 | // after function is called, arr1 should be: 9 | const expectedArr1 = [0, 1, 2, 3]; 10 | 11 | const arr2 = []; 12 | const newItem2 = "a"; 13 | const expected2 = 1; 14 | // after function is called, arr2 should be: 15 | const expectedArr2 = ["a"]; 16 | 17 | const testCases = [ 18 | { 19 | args: [arr1, newItem1], 20 | expectedRet: expected1, 21 | expectedArr: expectedArr1, 22 | }, 23 | { 24 | args: [arr2, newItem2], 25 | expectedRet: expected2, 26 | expectedArr: expectedArr2, 27 | }, 28 | ]; 29 | 30 | testCases.forEach( 31 | ({ args: [inputArr, newItem], expectedRet, expectedArr }, i) => { 32 | describe(`when given testCases[${i}]`, () => { 33 | it(`should return the new length after adding the new item.`, () => { 34 | expect(testFn(inputArr, newItem)).toBe(expectedRet); 35 | }); 36 | 37 | it("should added the new item to the given array.", () => { 38 | expect(inputArr).toEqual(expectedArr); 39 | }); 40 | }); 41 | } 42 | ); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /src/strings/largestCommonSubstring/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const str1A = "aaa"; 6 | const str1B = "aa"; 7 | const expected1 = "aa"; 8 | 9 | const str2A = "aaba"; 10 | const str2B = "aa"; 11 | const expected2 = "aa"; 12 | 13 | const str3A = "aeff"; 14 | const str3B = "abcdef"; 15 | // Expected chars can be in any order. 16 | const expected3 = "aef"; 17 | 18 | const str4A = "z this hurts my head x"; 19 | const str4B = "my head, this hurts"; 20 | // Expected chars can be in any order. 21 | const expected4 = "this hurts my head"; 22 | 23 | const testCases = [ 24 | { args: [str1A, str1B], expected: expected1 }, 25 | { args: [str2A, str2B], expected: expected2 }, 26 | { args: [str3A, str3B], expected: expected3 }, 27 | { args: [str4A, str4B], expected: expected4 }, 28 | ]; 29 | 30 | testCases.forEach(({ args, expected }, i) => { 31 | describe(`when given testCases[${i}]`, () => { 32 | it("finds the longest longest string that can be built from characters that both of the given strings share.", () => { 33 | expect(testFn(...args).split("")).toEqual( 34 | jasmine.arrayContaining(expected.split("")) 35 | ); 36 | }); 37 | }); 38 | }); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## CURRENT STUDENT WARNING 4 | 5 | - If you get in the habit of looking up answers before putting in a real effort to solve them yourself, you are setting yourself up for failure in interviews. 6 | 7 | ## Internal Links 8 | 9 | - [Algo Schedules](/schedules) 10 | - [Lecture Outlines](https://github.com/TheCodingDojo/lecture-outlines) 11 | 12 | ## Student Resources 13 | 14 | - [RIOTWalk Interview Method](./RIOTWalk-interview-method.md) 15 | - [Interviewing Notes](https://docs.google.com/document/d/1jG6C70MRBqH_yP-GKfT2TVZ9tZeHPoRpPCbqkzXuAqE/edit#) 16 | - [Big O Notation Cheat Sheet](https://cooervo.github.io/Algorithms-DataStructures-BigONotation/big-O-notation.html) 17 | - [neetcode - interview algos with solution videos](https://neetcode.io/) 18 | - [Tech Interview Handbook](https://techinterviewhandbook.org/introduction/) 19 | - [Extra Student Resources - Shared Drive Folder](https://drive.google.com/drive/folders/11zE6KbvIdgr6_KtYGtMRNMja6Q41IAuo?usp=sharing) 20 | 21 | ## Clone Instructions & Source Control 22 | 23 | - `git clone https://github.com/TheCodingDojo/algorithms.git` 24 | - `cd algorithms` 25 | - `npm i` to install dependencies. 26 | - `git pull` whenever you want to check for new changes. 27 | - To avoid merge conflicts if you want to take your own notes or add your own solutions, create a new file for whatever algo you are working on. 28 | - [jasmine notes](jasmine.md) 29 | -------------------------------------------------------------------------------- /src/strings/trim/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Given a string that may have extra spaces at the start and the end, 3 | return a new string that has the extra spaces at the start and the end trimmed (removed) 4 | do not remove any other spaces. 5 | */ 6 | 7 | const str1 = " hello world "; 8 | const expected1 = "hello world"; 9 | 10 | /** 11 | * Trims any leading or trailing white space from the given str. 12 | * - Time: O(?). 13 | * - Space: O(?). 14 | * @param {string} str 15 | * @returns {string} The given string with any leading or trailing white space 16 | * stripped. 17 | */ 18 | function trim(str) {} 19 | 20 | /*****************************************************************************/ 21 | 22 | /** 23 | * - Time: O(n) linear, both while loops plus the .slice loop all add up to 24 | * str.length. 25 | * - Space: O(n) linear, .slice creates a new string, at most it will be as 26 | * long as input str. 27 | * @param {string} str 28 | * @returns {string} 29 | */ 30 | function trim(str = "") { 31 | let startIdx = 0; 32 | let endIdx = str.length - 1; 33 | 34 | // loose comparison to false works for spaces 35 | // and other space-like characters (tabs, etc.) 36 | while (str[startIdx] == false) { 37 | startIdx++; 38 | } 39 | 40 | while (str[endIdx] == false) { 41 | endIdx--; 42 | } 43 | 44 | return str.slice(startIdx, endIdx + 1); 45 | } 46 | 47 | module.exports = { trim }; 48 | -------------------------------------------------------------------------------- /src/arrays/concatSelf/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const arr1 = ["a", "b", "c"]; 6 | const expected1 = ["a", "b", "c", "a", "b", "c"]; 7 | 8 | const arr2 = ["a"]; 9 | const expected2 = ["a", "a"]; 10 | 11 | const arr3 = []; 12 | const expected3 = []; 13 | 14 | const testCases = [ 15 | { args: [arr1], expected: expected1, description: "three items" }, 16 | { args: [arr2], expected: expected2, description: "one item" }, 17 | { args: [arr3], expected: expected3, description: "empty array" }, 18 | ]; 19 | 20 | testCases.forEach(({ args, expected, description }) => { 21 | describe("when given " + description, () => { 22 | const inputArr = args[0]; 23 | const inputArrCopy = [...inputArr]; 24 | const outputArr = testFn(...args); 25 | 26 | it("should return a new array that contains all the given arrays items, and then all the same items repeated at the end.", () => { 27 | expect(outputArr).toEqual(expected); 28 | }); 29 | 30 | it("should have returned a new array, not the given array.", () => { 31 | expect(outputArr).not.toBe(inputArr); 32 | }); 33 | 34 | it("should not have mutated the given array.", () => { 35 | expect(inputArr).toEqual(inputArrCopy); 36 | }); 37 | }); 38 | }); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /src/recreated_methods/Array/push/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const arr1 = ["a", "b", "c"]; 6 | const newItem1 = "d"; 7 | const expected1 = 4; 8 | // what arr1 should be after running push function 9 | const expectedArr1 = ["a", "b", "c", "d"]; 10 | 11 | const arr2 = []; 12 | const newItem2 = "a"; 13 | const expected2 = 1; 14 | const expectedArr2 = ["a"]; 15 | 16 | const testCases = [ 17 | { 18 | args: [arr1, newItem1], 19 | expectedRet: expected1, 20 | expectedArr: expectedArr1, 21 | description: "a non empty array", 22 | }, 23 | { 24 | args: [arr2, newItem2], 25 | expectedRet: expected2, 26 | expectedArr: expectedArr2, 27 | description: "an empty array", 28 | }, 29 | ]; 30 | 31 | testCases.forEach( 32 | ({ args: [arr, newItem], expectedRet, expectedArr }, i) => { 33 | describe(`when given testCases[${i}]`, () => { 34 | it("should return the new length after pushing the new item to the back of the array.", () => { 35 | expect(testFn(arr, newItem)).toBe(expectedRet); 36 | }); 37 | 38 | it("should have added the new item to the back of the array.", () => { 39 | expect(arr).toEqual(expectedArr); 40 | }); 41 | }); 42 | } 43 | ); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /src/arrays/indexOfMinVal/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const nums1 = [5, 2, 3]; 6 | const expected1 = 1; 7 | 8 | const nums2 = [5, 2, 2, 3]; 9 | const expected2 = 1; 10 | 11 | const nums3 = []; 12 | const expected3 = -1; 13 | 14 | const nums4 = [5, 15, 11, 20]; 15 | const expected4 = 0; 16 | 17 | const nums5 = [15, 11, 20, 5]; 18 | const expected5 = 3; 19 | 20 | const testCases = [ 21 | { 22 | args: [nums1], 23 | expected: expected1, 24 | description: "a small array with the min centered", 25 | }, 26 | { 27 | args: [nums2], 28 | expected: expected2, 29 | description: "a small array with the minimum duplicated", 30 | }, 31 | { args: [nums3], expected: expected3, description: "an empty array" }, 32 | { 33 | args: [nums4], 34 | expected: expected4, 35 | description: "the min at the front", 36 | }, 37 | { args: [nums5], expected: expected5, description: "the min at the end" }, 38 | ]; 39 | 40 | testCases.forEach(({ args, expected, description }) => { 41 | describe("when given " + description, () => { 42 | it("should return the index of the minimum value from the given array.", () => { 43 | expect(testFn(...args)).toEqual(expected); 44 | }); 45 | }); 46 | }); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /src/objects/findObjects/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const items1 = [ 6 | { firstName: "Bob", lastName: "Bobbert", age: 31 }, 7 | { firstName: "John", lastName: "Smith", age: 25 }, 8 | { firstName: "Bob", lastName: "Smith", age: 27 }, 9 | { firstName: "Bob", lastName: "White", age: 31 }, 10 | ]; 11 | 12 | const searchCriteria1 = { 13 | firstName: "Bob", 14 | age: 31, 15 | }; 16 | const expected1 = [ 17 | { firstName: "Bob", lastName: "Bobbert", age: 31 }, 18 | { firstName: "Bob", lastName: "White", age: 31 }, 19 | ]; 20 | 21 | const searchCriteria2 = { 22 | lastName: "Smith", 23 | }; 24 | const expected2 = [ 25 | { firstName: "John", lastName: "Smith", age: 25 }, 26 | { firstName: "Bob", lastName: "Smith", age: 27 }, 27 | ]; 28 | 29 | const testCases = [ 30 | { args: [searchCriteria1, items1], expected: expected1 }, 31 | { args: [searchCriteria2, items1], expected: expected2 }, 32 | ]; 33 | 34 | testCases.forEach(({ args, expected }, i) => { 35 | describe(`when given testCases[${i}]`, () => { 36 | it("should return an array of the objects from the given array that match the key value pairs of the given object.", () => { 37 | expect(testFn(...args)).toEqual(expected); 38 | }); 39 | }); 40 | }); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /src/arrays/firstNonRepeated/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const nums1 = [3, 5, 4, 3, 4, 6, 5]; 6 | const expected1 = 6; 7 | 8 | const nums2 = [3, 5, 5]; 9 | const expected2 = 3; 10 | 11 | const nums3 = [3, 3, 5]; 12 | const expected3 = 5; 13 | 14 | const nums4 = [5]; 15 | const expected4 = 5; 16 | 17 | const nums5 = []; 18 | const expected5 = null; 19 | 20 | const testCases = [ 21 | { 22 | args: [nums1], 23 | expected: expected1, 24 | description: "first unique near the end", 25 | }, 26 | { 27 | args: [nums2], 28 | expected: expected2, 29 | description: "first unique at the start", 30 | }, 31 | { 32 | args: [nums3], 33 | expected: expected3, 34 | description: "first unique at the end", 35 | }, 36 | { args: [nums4], expected: expected4, description: "one number only" }, 37 | { args: [nums5], expected: expected5, description: "an empty array" }, 38 | ]; 39 | 40 | testCases.forEach(({ args, expected, description }) => { 41 | describe("when given " + description, () => { 42 | it("should return the integer that appears earliest that has no duplicate anywhere else in the array.", () => { 43 | expect(testFn(...args)).toEqual(expected); 44 | }); 45 | }); 46 | }); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /src/recreated_methods/Object/entries/index.test.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const obj1 = { 6 | name: "Pizza", 7 | calories: 9001, 8 | }; 9 | 10 | const expected1 = [ 11 | ["name", "Pizza"], 12 | ["calories", 9001], 13 | ]; 14 | 15 | const proto = { 16 | inheritance: "inherited key", 17 | keyOnProto: "val from proto", 18 | }; 19 | 20 | // This object contains inherited key value pairs from the above proto obj. 21 | const obj2 = Object.assign(Object.create(proto), { 22 | firstName: "Foo", 23 | lastName: "Bar", 24 | age: 13, 25 | }); 26 | 27 | const expected2 = [ 28 | ["firstName", "Foo"], 29 | ["lastName", "Bar"], 30 | ["age", 13], 31 | ]; 32 | 33 | const testCases = [ 34 | { 35 | args: [obj1], 36 | expected: expected1, 37 | description: "an object with no inherited keys", 38 | }, 39 | { 40 | args: [obj2], 41 | expected: expected2, 42 | description: "an object with inherited keys", 43 | }, 44 | ]; 45 | 46 | testCases.forEach(({ args, expected }, i) => { 47 | describe(`when given testCases[${i}]`, () => { 48 | it("should return a 2d array of the given object's key value pairs.", () => { 49 | expect(testFn(...args)).toEqual(expected); 50 | }); 51 | }); 52 | }); 53 | }); 54 | }); 55 | -------------------------------------------------------------------------------- /src/strings/kaprekarsConstant/index.js: -------------------------------------------------------------------------------- 1 | const number1 = 3524; 2 | /* 3 | Explanation: 4 | 1. 5432 - 2345 = 3087 5 | 2. 8730 - 0378 = 8352 6 | 3. 8532 - 2358 = 6174 7 | */ 8 | const expected1 = 3; 9 | 10 | const number2 = 2111; 11 | const expected2 = 5; 12 | 13 | const number3 = 9831; 14 | const expected3 = 7; 15 | 16 | /** 17 | * Determines how many digit-summing steps are required to reach kaprekars 18 | * constant from the given number. 19 | * 1. Arrange digits in descending order. 20 | * 2. Sum the sorted digits. 21 | * 3. Repeat until reaching 6174. 22 | * @param {number} num 23 | * @returns {number} The number of summing operations required to reach 24 | * kaprekars constant. 25 | */ 26 | function kaprekarsConstant(num) {} 27 | 28 | /*****************************************************************************/ 29 | 30 | function kaprekarsConstant(num) { 31 | let count = 0; 32 | if (num === 6174) { 33 | return count; 34 | } 35 | 36 | let numStr = num.toString(); 37 | 38 | while (numStr != 6174) { 39 | if (numStr.length < 4) numStr += "0"; 40 | 41 | const strDigits = numStr.split(""); 42 | 43 | const asc = strDigits 44 | .slice() 45 | .sort((a, b) => a - b) 46 | .join(""); 47 | 48 | const desc = strDigits 49 | .slice() 50 | .sort((a, b) => b - a) 51 | .join(""); 52 | 53 | numStr = (desc - asc).toString(); 54 | count++; 55 | } 56 | return count; 57 | } 58 | 59 | module.exports = { 60 | kaprekarsConstant, 61 | }; 62 | -------------------------------------------------------------------------------- /src/recursion/reverseStr/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Recursively reverse a string 3 | helpful methods: 4 | 5 | str.slice(beginIndex[, endIndex]) 6 | returns a new string from beginIndex to endIndex exclusive 7 | */ 8 | 9 | const str1 = "abc"; 10 | const expected1 = "cba"; 11 | 12 | const str2 = ""; 13 | const expected2 = ""; 14 | 15 | /** 16 | * Recursively reverses a string. 17 | * - Time: O(?). 18 | * - Space: O(?). 19 | * @param {string} str 20 | * @returns {string} The given str reversed. 21 | */ 22 | function reverseStr(str) {} 23 | 24 | /*****************************************************************************/ 25 | 26 | /** 27 | * input: abc 28 | * output: cba 29 | * return: fn + a 30 | * return: fn + b 31 | * return fn + c 32 | * return '' 33 | * '' + c + b + a 34 | * 35 | * - Time: O(n) linear, n = str.length 36 | * - Space: O(2n) -> O(n) linear. Every char of the string is copied into a new 37 | * string and one function call added to the stack for each char. 38 | */ 39 | function reverseStr(str = "") { 40 | if (str === "") { 41 | return ""; 42 | } 43 | const strWithoutFirstChar = str.slice(1); 44 | const firstChar = str[0]; 45 | return reverseStr(strWithoutFirstChar) + firstChar; 46 | } 47 | 48 | function reverseStr2(str = "", i = str.length - 1) { 49 | if (str === "") { 50 | return ""; 51 | } 52 | 53 | if (i === 0) { 54 | return str[i]; 55 | } 56 | 57 | return str[i] + reverseStr2(str, i - 1); 58 | } 59 | 60 | module.exports = { reverseStr, reverseStr2 }; 61 | -------------------------------------------------------------------------------- /src/recreated_methods/Array/shift/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const arr1 = [1, 2, 3]; 6 | const expected1 = 1; 7 | // after running function arr1 should now be: 8 | const expectedArr1 = [2, 3]; 9 | 10 | const arr2 = ["a", "b", "c", "d"]; 11 | const expected2 = "a"; 12 | // after running function arr2 should now be: 13 | const expectedArr2 = ["b", "c", "d"]; 14 | 15 | const arr3 = []; 16 | const expected3 = undefined; 17 | const expectedArr3 = []; 18 | 19 | const testCases = [ 20 | { 21 | arg: arr1, 22 | expectedRet: expected1, 23 | expectedArr: expectedArr1, 24 | }, 25 | { 26 | arg: arr2, 27 | expectedRet: expected2, 28 | expectedArr: expectedArr2, 29 | }, 30 | { 31 | arg: arr3, 32 | expectedRet: expected3, 33 | expectedArr: expectedArr3, 34 | }, 35 | ]; 36 | 37 | testCases.forEach(({ arg, expectedRet, expectedArr }, i) => { 38 | describe(`when given testCases[${i}] containing ${arg.length} items`, () => { 39 | it(`should return the first item from the given array.`, () => { 40 | expect(testFn(arg)).toBe(expectedRet); 41 | }); 42 | 43 | it("should remove the first item and shift the remaining items down.", () => { 44 | expect(arg).toEqual(expectedArr); 45 | }); 46 | }); 47 | }); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /src/recreated_methods/Array/indexOf/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const arr1 = ["a", "b", "c"]; 6 | const searchItem1 = "c"; 7 | const expected1 = 2; 8 | 9 | const arr2 = ["a", "b", "c"]; 10 | const searchItem2 = 5; 11 | const expected2 = -1; 12 | 13 | const arr3 = ["c", "a", "b", "c"]; 14 | const searchItem3 = "c"; 15 | const expected3 = 0; 16 | 17 | const arr4 = []; 18 | const searchItem4 = 5; 19 | const expected4 = -1; 20 | 21 | const testCases = [ 22 | { 23 | args: [arr1, searchItem1], 24 | expected: expected1, 25 | description: "the search item at the end", 26 | }, 27 | { 28 | args: [arr2, searchItem2], 29 | expected: expected2, 30 | description: "a search item that doesn't exist", 31 | }, 32 | { 33 | args: [arr3, searchItem3], 34 | expected: expected3, 35 | description: "a search item that appears twice", 36 | }, 37 | { 38 | args: [arr4, searchItem4], 39 | expected: expected4, 40 | description: "an empty array", 41 | }, 42 | ]; 43 | 44 | testCases.forEach(({ args, expected }, i) => { 45 | describe(`when given testCases[${i}]`, () => { 46 | it("should return the index of the given element in the given array.", () => 47 | expect(testFn(...args)).toEqual(expected)); 48 | }); 49 | }); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /src/arrays/socialDistancingEnforcer/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const queue1 = [0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1]; 6 | const expected1 = false; 7 | 8 | const queue2 = [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1]; 9 | const expected2 = true; 10 | 11 | const queue3 = [1, 0, 0, 0, 0, 0, 0, 0, 1]; 12 | const expected3 = true; 13 | 14 | const queue4 = []; 15 | const expected4 = true; 16 | 17 | const testCases = [ 18 | { 19 | args: [queue1], 20 | expected: expected1, 21 | description: 22 | "the first two people socially distancing but the next is not.", 23 | }, 24 | { 25 | args: [queue2], 26 | expected: expected2, 27 | description: "all people socially distancing", 28 | }, 29 | { 30 | args: [queue3], 31 | expected: expected3, 32 | description: 33 | "a person at the start and the end with enough distance between", 34 | }, 35 | { args: [queue4], expected: expected4, description: "an empty array" }, 36 | ]; 37 | 38 | testCases.forEach(({ args, expected, description }) => { 39 | describe("when given " + description, () => { 40 | it("should return a boolean representing if every person is separated by at least 6 empty spaces.", () => { 41 | expect(testFn(...args)).toEqual(expected); 42 | }); 43 | }); 44 | }); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /src/arrays/containerWithMostWater/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const heights1 = [1, 8, 6, 2, 5, 4, 8, 3, 7]; 6 | const expected1 = 49; 7 | // Explanation: heights1[1] and heights1[8] as container edges. 8 | // Length = 8 - 1. Height = 7 9 | 10 | const heights2 = [1, 1]; 11 | const expected2 = 1; 12 | 13 | const heights3 = [4, 3, 2, 1, 4]; 14 | const expected3 = 16; 15 | 16 | const heights4 = [1, 2, 1]; 17 | const expected4 = 2; 18 | 19 | const testCases = [ 20 | { 21 | args: [heights1], 22 | expected: expected1, 23 | description: "a wide container solution ignoring first", 24 | }, 25 | { 26 | args: [heights2], 27 | expected: expected2, 28 | description: "two same heights", 29 | }, 30 | { 31 | args: [heights3], 32 | expected: expected3, 33 | description: "a whole container solution", 34 | }, 35 | { 36 | args: [heights4], 37 | expected: expected4, 38 | description: "a whole container solution with short sides", 39 | }, 40 | ]; 41 | 42 | testCases.forEach(({ args, expected, description }) => { 43 | describe("when given " + description, () => { 44 | it("should return the area of the container that can hold the most water.", () => { 45 | expect(testFn(...args)).toEqual(expected); 46 | }); 47 | }); 48 | }); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /jasmine.md: -------------------------------------------------------------------------------- 1 | # [Jasmine](https://www.npmjs.com/package/jasmine) 2 | 3 | - Jasmine is a unit testing framework. We will be using it to pass test cases to our algorithms to see if your algorithms return the expected result. 4 | 5 | ## Setup 6 | 7 | - you must have [Node.js](https://nodejs.org/en/download/) installed 8 | 9 | ### Clone a repo that already has jasmine initialized 10 | 11 | 1. `git clone URL/TO/REPO.git` (url can be found on the repos GitHub page by clicking the top right code button) 12 | - this will create a new folder at the location your terminal is open to, the folder will be named after the repository 13 | 2. `cd repo_name` 14 | 3. `npm i` to install the dependencies (jasmine) listed in the `package.json` that came the cloned project. 15 | 16 | ### Initialize a new project and install jasmine 17 | 18 | 1. If you haven't already, run: `npm init` in your algos project folder 19 | 2. `npm i jasmine` 20 | - this should have created a `package.json` file that has `jasmine` and version number listed in it. 21 | 3. copy over the spec folder, or to create your own 22 | 23 | ## Run Jasmine 24 | 25 | - add the following to `package.json` 26 | 27 | - ```json 28 | "scripts": { 29 | "test": "node_modules/.bin/jasmine" 30 | }, 31 | ``` 32 | 33 | - this allows you to run `npm test` in the terminal open to your project folder 34 | - alternatively, to test a single `Spec` file: `npm test path/to/fileNameSpec.js` 35 | - you can type `npm test` with a space after `test`, then drag and drop the file after the space to auto fill the path 36 | -------------------------------------------------------------------------------- /src/recursion/generateAnagrams/index.js: -------------------------------------------------------------------------------- 1 | // http://algorithms.dojo.news/static/Algorithms/index.html#LinkTarget_2129 2 | /* 3 | String Anagrams 4 | 5 | Given a string, 6 | return array where each element is a string representing a different anagram (a different sequence of the letters in that string). 7 | 8 | Ok to use built in methods 9 | */ 10 | 11 | const str1 = "lim"; 12 | const expected1 = ["ilm", "iml", "lim", "lmi", "mil", "mli"]; 13 | // Order of the output array does not matter 14 | 15 | /** 16 | * Add params if needed for recursion. 17 | * Generates all anagrams of the given str. 18 | * - Time: O(?). 19 | * - Space: O(?). 20 | * @param {string} str 21 | * @returns {Array} All anagrams of the given str. 22 | */ 23 | function generateAnagrams(str) {} 24 | 25 | /*****************************************************************************/ 26 | 27 | /** 28 | * Generates all anagrams (permutations) for the given string 29 | * @see https://www.geeksforgeeks.org/time-complexity-permutations-string/ 30 | * - Time: O(n^2 * n!) 31 | * - Space: O(n!) factorial due to the call stack. 32 | */ 33 | function generateAnagrams(str, solutions = [], partial = "") { 34 | if (!str) { 35 | solutions.push(partial); 36 | } 37 | 38 | for (let i = 0; i < str.length; i++) { 39 | const leftSlice = str.slice(0, i); 40 | const rightSlice = str.slice(i + 1); // skips current letter 41 | generateAnagrams(leftSlice + rightSlice, solutions, partial + str[i]); 42 | } 43 | return solutions; 44 | } 45 | 46 | module.exports = { generateAnagrams }; 47 | -------------------------------------------------------------------------------- /src/arrays/oddOccurrencesInArray/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const nums1 = [1]; 6 | const expected1 = 1; 7 | 8 | const nums2 = [5, 4, 5]; 9 | const expected2 = 4; 10 | 11 | const nums3 = [5, 4, 3, 4, 3, 4, 5]; 12 | const expected3 = 4; // there is a pair of 4s but one 4 has no pair. 13 | 14 | const nums4 = [5, 2, 6, 2, 3, 1, 6, 3, 2, 5, 2]; 15 | const expected4 = 1; 16 | 17 | const testCases = [ 18 | { 19 | args: [nums1], 20 | expected: expected1, 21 | description: "an array with a length of one", 22 | }, 23 | { 24 | args: [nums2], 25 | expected: expected2, 26 | description: "three numbers with one duplicated", 27 | }, 28 | { 29 | args: [nums3], 30 | expected: expected3, 31 | description: 32 | "multiple duplicates with the odd frequency greater than 1", 33 | }, 34 | { 35 | args: [nums4], 36 | expected: expected4, 37 | description: 38 | "even frequencies that exceed 2 and a single non-duplicated number", 39 | }, 40 | ]; 41 | 42 | testCases.forEach(({ args, expected, description }) => { 43 | describe("when given " + description, () => { 44 | it("should return the only number that occurs and odd number of times from a non empty array.", () => { 45 | expect(testFn(...args)).toEqual(expected); 46 | }); 47 | }); 48 | }); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /src/arrays/matrixSearch/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Matrix Search 3 | 4 | Mike digs image recognition and wants to create a JavaScript Imaging Library, just like PIL for Python. He is given 2 different two-dimensional arrays, containing integers between 0 and 65535. Each two-dimensional array represents a gray-scale image, where each integer value is a pixel. The second image might be found somewhere within the larger one. Return whether it is. 5 | 6 | Given array: [[12,34,45,56], and array: [[67,78], return true . [98,87,76,65],[43,32] ] [56, 67 , 78 ,89] , [54, 43 , 32 ,21] ] 7 | 8 | Second: Return location of first match found ( [-1,-1] if no match). In example above, return [2,1] . 9 | */ 10 | 11 | function matrixSearch(matrix, image) { 12 | const first = image[0][0]; 13 | const imageHeight = image.length; 14 | const imageWidth = image[0].length; 15 | const relevantHeight = matrix.length - imageHeight + 1; 16 | const relevantWidth = matrix[0].length - imageWidth + 1; 17 | 18 | for (let i = 0; i < relevantHeight; i++) { 19 | for (let j = 0; j < relevantWidth; j++) { 20 | if (matrix[i][j] !== first) continue; 21 | 22 | // move in unison until broken 23 | for (var k = 0, matching = true; k < imageHeight && matching; k++) { 24 | for (let l = 0; l < imageWidth && matching; l++) { 25 | if (image[k][l] !== matrix[i + k][j + l]) { 26 | matching = false; 27 | } 28 | } 29 | } 30 | 31 | if (matching) return [i, j]; 32 | } 33 | } 34 | 35 | return [-1, -1]; 36 | } 37 | 38 | module.exports = { matrixSearch }; 39 | -------------------------------------------------------------------------------- /src/strings/compareVersionNumbers/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const test1V1 = "0.1"; 6 | const test1V2 = "1.1"; 7 | const expected1 = -1; 8 | 9 | const test2V1 = "1.0.1"; 10 | const test2V2 = "1"; 11 | const expected2 = 1; 12 | 13 | const test3V1 = "7.5.2.4"; 14 | const test3V2 = "7.5.3"; 15 | const expected3 = -1; 16 | 17 | const test4V1 = "7.5.2.4"; 18 | const test4V2 = "7.5.2"; 19 | const expected4 = 1; 20 | 21 | const test5V1 = "1.01"; 22 | const test5V2 = "1.001"; 23 | const expected5 = 0; 24 | // Explanation: Ignoring leading zeroes, both “01” and “001" represent the same number “1” 25 | 26 | const test6V1 = "1.0.1"; 27 | const test6V2 = "1"; 28 | const expected6 = 1; 29 | 30 | const testCases = [ 31 | { args: [test1V1, test1V2], expected: expected1 }, 32 | { args: [test2V1, test2V2], expected: expected2 }, 33 | { args: [test3V1, test3V2], expected: expected3 }, 34 | { args: [test4V1, test4V2], expected: expected4 }, 35 | { args: [test5V1, test5V2], expected: expected5 }, 36 | { args: [test6V1, test6V2], expected: expected6 }, 37 | ]; 38 | 39 | testCases.forEach(({ args, expected }, i) => { 40 | describe(`when given testCases[${i}]`, () => { 41 | it("should return an int representing which version number is larger.", () => { 42 | expect(testFn(...args)).toEqual(expected); 43 | }); 44 | }); 45 | }); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /src/arrays/missingValue/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const nums1 = [3, 0, 1]; 6 | const expected1 = 2; 7 | 8 | const nums2 = [3, 0, 1, 2]; 9 | const expected2 = null; 10 | // Explanation: nothing is missing 11 | 12 | /* 13 | Bonus: now the lowest value can now be any integer (including negatives), 14 | instead of always being 0. 15 | */ 16 | 17 | const nums3 = [2, -4, 0, -3, -2, 1]; 18 | const expected3 = -1; 19 | 20 | const nums4 = [5, 2, 7, 8, 4, 9, 3]; 21 | const expected4 = 6; 22 | 23 | const testCases = [ 24 | { 25 | args: [nums1], 26 | expected: expected1, 27 | description: "an unordered sequence 0-3", 28 | }, 29 | { args: [nums2], expected: expected2, description: "no missing value" }, 30 | { 31 | args: [nums3], 32 | expected: expected3, 33 | description: "a BONUS with the sequence -4-2", 34 | }, 35 | { 36 | args: [nums4], 37 | expected: expected4, 38 | description: "a BONUS with the sequence 2-9", 39 | }, 40 | ]; 41 | 42 | testCases.forEach(({ args, expected, description }) => { 43 | describe("when given " + description, () => { 44 | it("should return the missing value from an array containing a consecutive sequence of ints that is unordered but with one missing.", () => { 45 | expect(testFn(...args)).toEqual(expected); 46 | }); 47 | }); 48 | }); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /src/strings/stringToWordArray/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Helpful notes: 3 | 4 | '\n' == true 5 | => false 6 | 7 | if ('\n') { console.log(true) } 8 | => true 9 | 10 | if ('\n' == false) { console.log(true) } 11 | => true 12 | */ 13 | 14 | const str1 = "Life is not a drill!"; 15 | const expected1 = ["Life", "is", "not", "a", "drill!"]; 16 | 17 | /** 18 | * Converts a string of space separated words into an array of words. 19 | * - Time: O(?). 20 | * - Space: O(?). 21 | * @param {string} wordsStr Space separated words. 22 | * @returns {string} An array of words. 23 | */ 24 | function stringToWordArr(wordsStr) {} 25 | 26 | /*****************************************************************************/ 27 | 28 | /** 29 | * Converts a string of space separated words into an array of words. 30 | * - Time: O(n) linear. 31 | * - Space: O(n) linear. 32 | * @param {string} wordsStr Space separated words. 33 | * @returns {string} An array of words. 34 | */ 35 | function stringToWordArr(wordsStr) { 36 | const words = []; 37 | let currWord = ""; 38 | 39 | for (const char of wordsStr) { 40 | // space characters are falsy 41 | if (char == false) { 42 | // in case of multiple spaces, word might still be empty 43 | if (currWord.length > 0) { 44 | words.push(currWord); 45 | currWord = ""; 46 | } 47 | } else { 48 | currWord += char; 49 | } 50 | } 51 | // when no space at end, need to include last word 52 | if (currWord.length > 0) { 53 | words.push(currWord); 54 | } 55 | return words; 56 | } 57 | 58 | module.exports = { stringToWordArr }; 59 | -------------------------------------------------------------------------------- /src/fromJob/flattenObjectOfArrays/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const object1 = { 6 | closedCreditMemos: [], 7 | closedDeliveryOrders: [], 8 | closedPickupOrders: [ 9 | { id: 112, type: "pickup" }, 10 | { id: 117, type: "pickup" }, 11 | ], 12 | openCreditMemos: [], 13 | openDeliveryOrders: [ 14 | { 15 | id: 123, 16 | type: "delivery", 17 | gateCode: "#2552", 18 | }, 19 | { 20 | id: 153, 21 | type: "delivery", 22 | instructions: "Place in secure delivery box.", 23 | }, 24 | ], 25 | openPickupOrders: [ 26 | { 27 | id: 123, 28 | type: "pickup", 29 | }, 30 | ], 31 | returnPickupOrders: [], 32 | }; 33 | 34 | const expected1 = [ 35 | { id: 112, type: "pickup" }, 36 | { id: 117, type: "pickup" }, 37 | { id: 123, type: "delivery" }, 38 | { id: 153, type: "delivery" }, 39 | { id: 123, type: "pickup" }, 40 | ]; 41 | 42 | const testCases = [ 43 | { 44 | arg: object1, 45 | expected: expected1, 46 | }, 47 | ]; 48 | 49 | testCases.forEach(({ arg, expected }, i) => { 50 | describe(`when given testCases[${i}]`, () => { 51 | it("return a one-dim array of all the objects inside the arrays that are in the given object.", () => 52 | expect(testFn(arg)).toEqual(expected)); 53 | }); 54 | }); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /src/recursion/factorial/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Recursive Factorial 3 | 4 | Input: integer 5 | Output: integer, product of ints from 1 up to given integer 6 | 7 | If less than zero, treat as zero. 8 | Bonus: If not integer, truncate (remove decimals). 9 | 10 | Experts tell us 0! is 1. 11 | 12 | rFact(3) = 6 (1*2*3) 13 | rFact(6.8) = 720 (1*2*3*4*5*6) 14 | */ 15 | 16 | const num1 = 3; 17 | const expected1 = 6; 18 | // Explanation: 1*2*3 = 6 19 | 20 | const num2 = 6.8; 21 | const expected2 = 720; 22 | // Explanation: 1*2*3*4*5*6 = 720 23 | 24 | const num3 = 0; 25 | const expected3 = 1; 26 | 27 | /** 28 | * Recursively multiples 1 to the given int. 29 | * - Time: O(?). 30 | * - Space: O(?). 31 | * @param {number} n The int to factorial. Treat negatives as zero and 32 | * floor decimals. 33 | * @returns {number} The result of !n. 34 | */ 35 | function factorial(n) {} 36 | 37 | /*****************************************************************************/ 38 | 39 | /** 40 | * Recursively multiples 1 to the given int. 41 | * - Time: O(n) linear. 42 | * - Space: O(n) linear due to the call stack. 43 | * @param {number} n The int to factorial. Treat negatives as zero and 44 | * floor decimals. 45 | * @returns {number} The result of !n. 46 | */ 47 | function factorial(n) { 48 | // Termination Condition if it's bad data (not a number) 49 | if (isNaN(parseInt(n))) { 50 | return null; 51 | } 52 | 53 | n = Math.floor(n); 54 | 55 | // Base case 56 | if (n <= 0) { 57 | return 1; 58 | } 59 | return n * factorial(n - 1); 60 | } 61 | 62 | module.exports = { factorial }; 63 | -------------------------------------------------------------------------------- /src/arrays/mode/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const nums1 = []; 6 | const expected1 = []; 7 | 8 | const nums2 = [1]; 9 | const expected2 = [1]; 10 | 11 | const nums3 = [5, 1, 4]; 12 | const expected3 = []; 13 | 14 | const nums4 = [5, 1, 4, 1]; 15 | const expected4 = [1]; 16 | 17 | const nums5 = [5, 1, 4, 1, 5]; 18 | const expected5 = [5, 1]; 19 | // - order doesn't matter 20 | 21 | const testCases = [ 22 | { args: [nums1], expected: expected1, description: "an empty array" }, 23 | { args: [nums2], expected: expected2, description: "a single number" }, 24 | { args: [nums3], expected: expected3, description: "no duplicates" }, 25 | { 26 | args: [nums4], 27 | expected: expected4, 28 | description: "a small array with one duplicate", 29 | }, 30 | { 31 | args: [nums5], 32 | expected: expected5, 33 | description: 34 | "a small array with two of the numbers having the same frequency", 35 | }, 36 | ]; 37 | 38 | testCases.forEach(({ args, expected, description }) => { 39 | describe("when given " + description, () => { 40 | it("should return an array of the integers that occur most frequently in the given array (more than one only if some have the same frequency).", () => { 41 | expect(testFn(...args)).toEqual( 42 | jasmine.arrayWithExactContents(expected) 43 | ); 44 | }); 45 | }); 46 | }); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /src/objects/lens/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const user1 = { 6 | id: 101, 7 | email: "jack@dev.com", 8 | personalInfo: { 9 | name: "Jack", 10 | address: { 11 | street: "Westwish st", 12 | city: "wallas", 13 | state: "WX", 14 | }, 15 | }, 16 | favorites: { 17 | number: 0, 18 | }, 19 | }; 20 | 21 | const keys1 = ["personalInfo", "address", "city"]; 22 | const expected1 = "wallas"; 23 | 24 | const keys2 = ["personalInfo", "address", "country"]; 25 | const expected2 = null; 26 | 27 | const keys3 = ["personalInfo", "mainHobby", "yearsActive"]; 28 | const expected3 = null; 29 | 30 | const keys4 = ["favorites", "number"]; 31 | const expected4 = 0; 32 | 33 | const keys5 = []; 34 | const expected5 = user1; 35 | 36 | const testCases = [ 37 | { args: [user1, keys1], expected: expected1 }, 38 | { args: [user1, keys2], expected: expected2 }, 39 | { args: [user1, keys3], expected: expected3 }, 40 | { args: [user1, keys4], expected: expected4 }, 41 | { args: [user1, keys5], expected: expected5 }, 42 | ]; 43 | testCases.forEach(({ args, expected }, i) => { 44 | describe(`when given testCases[${i}]`, () => { 45 | it("should return the value at the end of the given path of keys, or null if it doesn't exist.", () => { 46 | expect(testFn(...args)).toEqual(expected); 47 | }); 48 | }); 49 | }); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /src/sets/intro.md: -------------------------------------------------------------------------------- 1 | # Sets 2 | 3 | - A set is a mathematical term for a collection of values 4 | - We will mostly use arrays when doing `set` based operations because, although a `Set` datatype exists and can be useful, JS doesn't natively have a multi-set data type. 5 | 6 | --- 7 | 8 | ## `Set` Type in JS 9 | 10 | - `new Set(val1, val2, valn)` 11 | - can pass in an array and when converted to a set it will be auto deduped 12 | - iterate 13 | - `.size` 14 | - `.add(val)` 15 | - `.has(val)` 16 | - `.delete(val)` 17 | - returns `true` if value found & deleted 18 | 19 | --- 20 | 21 | ## Types of Sets 22 | 23 | ### Normal Set 24 | 25 | - No dupes allowed, attempting to add a dupe will result in nothing being added. Creating a set from an array or string with dupes will remove the dupes. 26 | - does not track count of values b/c no dupes 27 | 28 | --- 29 | 30 | ### Multiset (contains dupes) 31 | 32 | - tracks count of values because there are dupes 33 | 34 | --- 35 | 36 | ### Ordered Set / Multiset 37 | 38 | --- 39 | 40 | ### Unordered Set / Multiset 41 | 42 | --- 43 | 44 | ### Intersection 45 | 46 | - only values that are shared between the sets deduped 47 | 48 | --- 49 | 50 | ### Union 51 | 52 | - [Union Example](https://i.ytimg.com/vi/WqYQ3OakKP0/maxresdefault.jpg) 53 | - all values from both sets included but deduped 54 | - ![Union vs Intersection](https://i.pinimg.com/originals/c9/45/d1/c945d12fcf677cc2f783a5c2f2b6acbc.png) 55 | 56 | --- 57 | 58 | ### Union Multiset 59 | 60 | - the higher count of duped values are kept 61 | - if there are 3 number ones in one set and 2 number ones in the other set, 3 number ones would be kept 62 | -------------------------------------------------------------------------------- /src/strings/rot13/index.js: -------------------------------------------------------------------------------- 1 | // https://www.codewars.com/kata/530e15517bc88ac656000716/train/javascript 2 | 3 | /* 4 | ROT13 is a simple letter substitution cipher that replaces 5 | a letter with the letter 13 letters after it in the alphabet. 6 | ROT13 is an example of the Caesar cipher. 7 | 8 | Create a function that takes a string and returns the string 9 | ciphered with Rot13. If there are numbers or special characters 10 | included in the string, they should be returned as they are. 11 | Only letters from the latin/english alphabet should be shifted, 12 | like in the original Rot13 "implementation". 13 | */ 14 | 15 | /*****************************************************************************/ 16 | 17 | const alphabet = [ 18 | "a", 19 | "b", 20 | "c", 21 | "d", 22 | "e", 23 | "f", 24 | "g", 25 | "h", 26 | "i", 27 | "j", 28 | "k", 29 | "l", 30 | "m", 31 | "n", 32 | "o", 33 | "p", 34 | "q", 35 | "r", 36 | "s", 37 | "t", 38 | "u", 39 | "v", 40 | "w", 41 | "x", 42 | "y", 43 | "z", 44 | ]; 45 | 46 | function rot13(s) { 47 | const chars = s.split(""); 48 | 49 | for (let i = 0; i < chars.length; i++) { 50 | let alphabetIdx = alphabet.indexOf(chars[i]); 51 | 52 | if (alphabetIdx > -1) { 53 | let newAlphabetIdx = alphabetIdx + 13; 54 | if (newAlphabetIdx > alphabet.length - 1) 55 | // get the remainder and start indexing again from the beginning 56 | newAlphabetIdx = newAlphabetIdx - alphabet.length - 1; 57 | 58 | chars[i] = [alphabet[newAlphabetIdx]]; 59 | } 60 | } 61 | return chars.join(""); 62 | } 63 | 64 | module.exports = { rot13 }; 65 | -------------------------------------------------------------------------------- /src/arrays/interleaveArrays/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const arrA1 = [1, 2, 3]; 6 | const arrB1 = ["a", "b", "c"]; 7 | const expected1 = [1, "a", 2, "b", 3, "c"]; 8 | 9 | const arrA2 = [1, 3]; 10 | const arrB2 = [2, 4, 6, 8]; 11 | const expected2 = [1, 2, 3, 4, 6, 8]; 12 | 13 | const arrA3 = [1, 3, 5, 7]; 14 | const arrB3 = [2, 4]; 15 | const expected3 = [1, 2, 3, 4, 5, 7]; 16 | 17 | const arrA4 = []; 18 | const arrB4 = [42, 0, 6]; 19 | const expected4 = [42, 0, 6]; 20 | 21 | const testCases = [ 22 | { 23 | args: [arrA1, arrB1], 24 | expected: expected1, 25 | description: "three numbers and three letters", 26 | }, 27 | { 28 | args: [arrA2, arrB2], 29 | expected: expected2, 30 | description: "a first array half the size of the second array", 31 | }, 32 | { 33 | args: [arrA3, arrB3], 34 | expected: expected3, 35 | description: "a second array half the size of the first array", 36 | }, 37 | { 38 | args: [arrA4, arrB4], 39 | expected: expected4, 40 | description: "the first array empty", 41 | }, 42 | ]; 43 | 44 | testCases.forEach(({ args, expected, description }) => { 45 | describe("when given " + description, () => { 46 | it("should return a new array that contains the items of the given arrays interleaved (alternated).", () => { 47 | expect(testFn(...args)).toEqual(expected); 48 | }); 49 | }); 50 | }); 51 | }); 52 | }); 53 | -------------------------------------------------------------------------------- /src/callbacks/dropIt/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const nums1 = [1, 4, 3, 6, 9, 15]; 6 | 7 | const callback1 = (elem) => { 8 | return elem > 5; 9 | }; 10 | const expected1 = [6, 9, 15]; 11 | 12 | const callback2 = (elem) => { 13 | return elem > 2; 14 | }; 15 | const expected2 = [4, 3, 6, 9, 15]; 16 | 17 | const callback3 = (elem) => false; 18 | const expected3 = []; 19 | 20 | const testCases = [ 21 | { 22 | args: [nums1, callback1], 23 | expected: expected1, 24 | description: "a callback that checks for greater than 5", 25 | }, 26 | { 27 | args: [nums1, callback2], 28 | expected: expected2, 29 | description: "a callback that checks for greater than 2", 30 | }, 31 | { 32 | args: [nums1, callback3], 33 | expected: expected3, 34 | description: "a callback that always returns false", 35 | }, 36 | ]; 37 | 38 | testCases.forEach(({ args: [nums, cb], expected, description }) => { 39 | describe("when given " + description, () => { 40 | const numsCopy = [...nums]; 41 | const actual = testFn(numsCopy, cb); 42 | 43 | it("should return the given array after removing every item from index 0 until the callback returns true.", () => { 44 | expect(actual).toEqual(expected); 45 | }); 46 | 47 | it("should have mutated and returned the given array.", () => { 48 | expect(actual).toBe(numsCopy); 49 | }); 50 | }); 51 | }); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /src/objects/coronaVirusAtRisk/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const friend1 = { 6 | firstName: "Friend", 7 | lastName: "One", 8 | isSocialDistancing: false, 9 | hasCovid: true, 10 | }; 11 | 12 | const friend2 = { 13 | firstName: "Friend", 14 | lastName: "Two", 15 | isSocialDistancing: false, 16 | hasCovid: true, 17 | }; 18 | 19 | const friend3 = { 20 | firstName: "Friend", 21 | lastName: "Three", 22 | isSocialDistancing: false, 23 | hasCovid: false, 24 | }; 25 | 26 | const people1 = [ 27 | { 28 | firstName: "Person", 29 | lastName: "One", 30 | isSocialDistancing: false, 31 | friends: [friend2, friend3], 32 | }, 33 | { 34 | firstName: "Person", 35 | lastName: "Two", 36 | isSocialDistancing: true, 37 | friends: [friend2, friend1], 38 | }, 39 | { 40 | firstName: "Person", 41 | lastName: "Three", 42 | isSocialDistancing: false, 43 | friends: [friend2, friend1], 44 | }, 45 | ]; 46 | 47 | const expected1 = ["Person One", "Person Three"]; 48 | 49 | const testCases = [{ args: [people1], expected: expected1 }]; 50 | 51 | testCases.forEach(({ args, expected }, i) => { 52 | describe(`when given testCases[${i}]`, () => { 53 | it("should return an array of the names of people who are at risk of contracting corona virus.", () => 54 | expect(testFn(...args)).toEqual(expected)); 55 | }); 56 | }); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /src/arrays/nthLast/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | // Last element: 6 | const arr1 = ["a", "b", "c", "d"]; 7 | const nthLast1 = 1; 8 | const expected1 = "d"; 9 | 10 | // Second to last element: 11 | const arr2 = ["a", "b", "c", "d"]; 12 | const nthLast2 = 2; 13 | const expected2 = "c"; 14 | 15 | const arr3 = ["a", "b", "c", "d"]; 16 | const nthLast3 = 0; 17 | const expected3 = null; 18 | 19 | const arr4 = ["a", "b", "c", "d"]; 20 | const nthLast4 = -1; 21 | const expected4 = null; 22 | 23 | const arr5 = []; 24 | const nthLast5 = 2; 25 | const expected5 = null; 26 | 27 | const testCases = [ 28 | { 29 | args: [arr1, nthLast1], 30 | expected: expected1, 31 | }, 32 | { args: [arr2, nthLast2], expected: expected2 }, 33 | { args: [arr3, nthLast3], expected: expected3 }, 34 | { args: [arr4, nthLast4], expected: expected4 }, 35 | { 36 | args: [arr5, nthLast5], 37 | expected: expected5, 38 | description: `an empty array and nthToLast=${nthLast5}`, 39 | }, 40 | ]; 41 | 42 | testCases.forEach( 43 | ({ 44 | args: [arr, nthLast], 45 | expected, 46 | description = `a non-empty array and nthToLast=${nthLast}`, 47 | }) => { 48 | describe("when given " + description, () => { 49 | it("should return the nth item from the back of the given array.", () => { 50 | expect(testFn(arr, nthLast)).toEqual(expected); 51 | }); 52 | }); 53 | } 54 | ); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /src/arrays/checkTicTacToeWinner/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const grid1 = [ 6 | ["x", "x", ""], 7 | ["x", "x", "o"], 8 | ["", "o", ""], 9 | ]; 10 | const expected1 = false; 11 | 12 | const grid2 = [ 13 | ["", "o", "x"], 14 | ["o", "x", ""], 15 | ["x", "", ""], 16 | ]; 17 | const expected2 = true; 18 | 19 | const grid3 = [ 20 | ["x", "", "o"], 21 | ["x", "x", "o"], 22 | ["", "", "o"], 23 | ]; 24 | const expected3 = true; 25 | 26 | const grid4 = [ 27 | ["", "", ""], 28 | ["o", "o", ""], 29 | ["x", "x", "x"], 30 | ]; 31 | const expected4 = true; 32 | 33 | const testCases = [ 34 | { 35 | args: [grid1], 36 | expected: expected1, 37 | description: "multiple two in a row", 38 | }, 39 | { 40 | args: [grid2], 41 | expected: expected2, 42 | description: "a bottom left to top right win for 'x'", 43 | }, 44 | { 45 | args: [grid3], 46 | expected: expected3, 47 | description: "a right column win for 'o'", 48 | }, 49 | { 50 | args: [grid4], 51 | expected: expected4, 52 | description: "a bottom row win for 'x'", 53 | }, 54 | ]; 55 | 56 | testCases.forEach(({ args, expected, description }) => { 57 | describe("when given " + description, () => { 58 | it("should determine if a tic tac toe winner exists.", () => { 59 | expect(testFn(...args)).toEqual(expected); 60 | }); 61 | }); 62 | }); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /src/recursion/generateCoinChange/index.js: -------------------------------------------------------------------------------- 1 | // http://algorithms.dojo.news/static/Algorithms/index.html#LinkTarget_2129 2 | 3 | /* 4 | Generate All Possible Coin Change 5 | 6 | Create generate All CoinChange(cents) . Given a number of American cents, compute and return an array enumerating all possible ways to represent it, with pennies (1 cent), nickels (5 cents), dimes (10 cents), quarters (25 cents). For 5 , return [{dimes:0,nickels:1,pennies:0,quarters:0}, {dimes:0,nickels:0,pennies:5,quarters:0}{}] . Do not return duplicate results. 7 | */ 8 | 9 | function generateCoinChange( 10 | cents, 11 | solutions = [], 12 | partial = { quarters: 0, dimes: 0, nickels: 0, pennies: 0 } 13 | ) { 14 | solutions.push({ 15 | ...partial, 16 | pennies: cents, 17 | }); 18 | 19 | if (!partial.quarters) { 20 | const maxQuarters = Math.floor(cents / 25); 21 | 22 | for (let i = 1; i <= maxQuarters; i++) { 23 | generateCoinChange(cents - i * 25, solutions, { 24 | ...partial, 25 | quarters: i, 26 | }); 27 | } 28 | } 29 | 30 | if (!partial.dimes) { 31 | const maxDimes = Math.floor(cents / 10); 32 | 33 | for (let i = 1; i <= maxDimes; i++) { 34 | generateCoinChange(cents - i * 10, solutions, { 35 | ...partial, 36 | dimes: i, 37 | }); 38 | } 39 | } 40 | 41 | if (!partial.nickels) { 42 | const maxNickels = Math.floor(cents / 5); 43 | 44 | for (let i = 1; i <= maxNickels; i++) { 45 | generateCoinChange(cents - i * 5, solutions, { 46 | ...partial, 47 | nickels: i, 48 | }); 49 | } 50 | } 51 | 52 | return solutions; 53 | } 54 | 55 | module.exports = { 56 | generateCoinChange, 57 | }; 58 | -------------------------------------------------------------------------------- /src/intervals/mergeSortedIntervals/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const intervals1 = [ 6 | [1, 3], 7 | [2, 6], 8 | [8, 10], 9 | [15, 18], 10 | ]; 11 | const expected1 = [ 12 | [1, 6], 13 | [8, 10], 14 | [15, 18], 15 | ]; 16 | // Explanation: Since intervals [1,3] and [2,6] overlaps, merge them into [1,6]. 17 | 18 | const intervals2 = [ 19 | [1, 4], 20 | [4, 5], 21 | ]; 22 | const expected2 = [[1, 5]]; 23 | // Explanation: Intervals [1,4] and [4,5] are considered overlapping. 24 | 25 | const intervals3 = [ 26 | [2, 4], 27 | [8, 10], 28 | [15, 20], 29 | ]; 30 | const expected3 = [ 31 | [2, 4], 32 | [8, 10], 33 | [15, 20], 34 | ]; 35 | 36 | const testCases = [ 37 | { 38 | args: [intervals1], 39 | expected: expected1, 40 | description: "the first two intervals overlapping", 41 | }, 42 | { 43 | args: [intervals2], 44 | expected: expected2, 45 | description: "only two intervals that overlap", 46 | }, 47 | { 48 | args: [intervals3], 49 | expected: expected3, 50 | description: "no overlapping intervals", 51 | }, 52 | ]; 53 | 54 | testCases.forEach(({ args, expected, description }) => { 55 | describe("when given " + description, () => { 56 | it("should merge overlapping intervals into a new array from a given array of sorted intervals.", () => 57 | expect(testFn(...args)).toEqual(expected)); 58 | }); 59 | }); 60 | }); 61 | }); 62 | -------------------------------------------------------------------------------- /src/objects/makeFrequencyTable/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const arr1 = ["a", "a", "a"]; 6 | const expected1 = { 7 | a: 3, 8 | }; 9 | 10 | const arr2 = ["a", "b", "a", "c", "B", "c", "c", "d"]; 11 | const expected2 = { 12 | a: 2, 13 | b: 1, 14 | c: 3, 15 | B: 1, 16 | d: 1, 17 | }; 18 | 19 | const arr3 = []; 20 | const expected3 = {}; 21 | 22 | const testCases = [ 23 | { 24 | args: [arr1], 25 | expected: expected1, 26 | description: "an array of 'a' repeated three times", 27 | }, 28 | { 29 | args: [arr2], 30 | expected: expected2, 31 | description: 32 | "an array of letters a-d with some dupes and different casing", 33 | }, 34 | { args: [arr3], expected: expected3, description: "an empty array" }, 35 | ]; 36 | 37 | testCases.forEach(({ args, expected }, i) => { 38 | describe(`when given testCases[${i}]`, () => { 39 | it("should return an object that has keys corresponding to the given array's items and values that are a count of the item's frequency.", () => { 40 | const actual = testFn(...args); 41 | 42 | if (actual instanceof Map) { 43 | const pojo = [...actual.entries()].reduce((obj, [key, value]) => { 44 | obj[key] = value; 45 | return obj; 46 | }, {}); 47 | expect(pojo).toEqual(expected); 48 | } else { 49 | expect(actual).toEqual(expected); 50 | } 51 | }); 52 | }); 53 | }); 54 | }); 55 | }); 56 | -------------------------------------------------------------------------------- /src/DOM/iterativelyRenderTree/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Iteratively renders HTML lists with nested lists for the children matching 3 | the given parent-child-relationships based on the ids. 4 | 5 | Display the id as the innerHTML. 6 | */ 7 | 8 | const data1 = [ 9 | { parent: null, id: "A" }, 10 | { parent: "A", id: "B" }, 11 | { parent: "A", id: "C" }, 12 | { parent: "A", id: "D" }, 13 | { parent: "B", id: "E" }, 14 | { parent: "C", id: "F" }, 15 | { parent: "D", id: "G" }, 16 | ]; 17 | 18 | /* 19 | Expected1: 20 |
    21 |
  • 22 | A 23 |
      24 |
    • 25 | B 26 |
        27 |
      • E
      • 28 |
      29 |
    • 30 |
    • 31 | C 32 |
        33 |
      • F
      • 34 |
      35 |
    • 36 |
    • 37 | D 38 |
        39 |
      • G
      • 40 |
      41 |
    • 42 |
    43 |
  • 44 |
45 | */ 46 | 47 | /** TODO 48 | * Iteratively renders an HTML list containing child lists corresponding to 49 | * the parent-child-relationship based on the given ids and displays the id. 50 | * @param {{parent: string, id: string}[]} data 51 | */ 52 | function iterativelyRenderTree(data) { 53 | let rootId = null; 54 | const idToChildrenMap = new Map(); 55 | 56 | for (const elem of data) { 57 | if (elem.parent === null) { 58 | rootId = elem.id; 59 | } 60 | 61 | if (idToChildrenMap.has(elem.id) === false) { 62 | idToChildrenMap.set(elem.id, []); 63 | } 64 | 65 | idToChildrenMap.get(elem.id).push(elem); 66 | } 67 | 68 | const stack = []; 69 | for (const [id, children] of idToChildrenMap.entries()) { 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/arrays/kMostFrequent/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const nums1 = [2, 1, 1, 3, 1, 2]; 6 | const k1 = 2; 7 | const expected1 = [1, 2]; 8 | // Explanation: return the two most frequent elements, 1 and 2 are the two most frequent elements 9 | 10 | const nums2 = [0, 2, 0, 3, 2, 0]; 11 | const k2 = 1; 12 | const expected2 = [0]; 13 | // Explanation: k being 1 means return the single most frequent element 14 | 15 | // 6 occurs 6 times, 3 occurs 3 times, 2 occurs 2 times, 1 occurs 1 time. 16 | const nums3 = [1, 6, 3, 3, 6, 6, 3, 6, 2, 2, 6, 6]; 17 | const k3 = 3; 18 | const expected3 = [6, 3, 2]; 19 | 20 | const testCases = [ 21 | { 22 | args: [nums1, k1], 23 | expected: expected1, 24 | description: `an array of 3 numbers with each duplicated a few times and k=${k1}`, 25 | }, 26 | { 27 | args: [nums2, k2], 28 | expected: expected2, 29 | description: `an array of 3 numbers with one that occurs more than the rest and k=${k2}`, 30 | }, 31 | { 32 | args: [nums3, k3], 33 | expected: expected3, 34 | description: `an array of 3 numbers each duplicated and k=${k3}`, 35 | }, 36 | ]; 37 | 38 | testCases.forEach(({ args, expected, description }) => { 39 | describe("when given " + description, () => { 40 | it("should return the k most frequently occurring integers from the array in any order.", () => { 41 | expect(testFn(...args)).toEqual( 42 | jasmine.arrayWithExactContents(expected) 43 | ); 44 | }); 45 | }); 46 | }); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /src/recursion/greatestCommonFactor/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Greatest Common Factor / Denominator 3 | 4 | Input: two integers 5 | Output: greatest common factor (the largest integer that can be evenly divided into both given ints) 6 | 7 | Greek mathematician Euclid demonstrated these facts: 8 | 9 | 1) gcf(a,b) == a , if a == b; 10 | 11 | 2) gcf(a,b) == gcf(a-b,b) , if a>b; 12 | 13 | 3) gcf(a,b) == gcf(a,b-a) , if b>a. 14 | 15 | Second: rework facts #2 and #3 to reduce stack consumption and expand rGCF ’s reach. You should be able to compute rGCF(123456,987654) 16 | */ 17 | 18 | const a1 = 5; 19 | const b1 = 5; 20 | const expected1 = 5; 21 | 22 | const a2 = 6; 23 | const b2 = 20; 24 | const expected2 = 2; 25 | 26 | const a3 = 54; 27 | const b3 = 12; 28 | const expected3 = 6; 29 | 30 | const a4 = 12; 31 | const b4 = 54; 32 | const expected4 = 6; 33 | 34 | const a5 = 65; 35 | const b5 = 25; 36 | const expected5 = 5; 37 | 38 | const a6 = 123456; 39 | const b6 = 987654; 40 | const expected6 = 6; 41 | 42 | /** 43 | * Returns the greatest common factor of the two given numbers. 44 | * @param {number} a 45 | * @param {number} b 46 | * @returns {number} The greatest common factor. 47 | */ 48 | function rGCF(a, b) {} 49 | 50 | /*****************************************************************************/ 51 | 52 | // Maximum call stack exceeded for large inputs. 53 | function rGCF(a, b) { 54 | if (a === b) { 55 | return a; 56 | } 57 | 58 | if (a > b) { 59 | return rGCF(a - b, b); 60 | } 61 | 62 | if (a < b) { 63 | return rGCF(a, b - a); 64 | } 65 | } 66 | 67 | function rGCF2(a, b) { 68 | if (!b) { 69 | return a; 70 | } 71 | 72 | return rGCF2(b, a % b); 73 | } 74 | 75 | module.exports = { /* rGCF, */ rGCF2 }; 76 | -------------------------------------------------------------------------------- /src/arrays/removeAt/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const arr1 = ["a", "b", "c"]; 6 | const removeIdx1 = 1; 7 | const expected1 = "b"; 8 | // after function call, arr1 should be: 9 | const arr1Expected = ["a", "c"]; 10 | 11 | const arr2 = ["a", "b", "c"]; 12 | const removeIdx2 = 3; 13 | const expected2 = null; 14 | const arr2Expected = ["a", "b", "c"]; 15 | 16 | const arr3 = ["a", "b", "c"]; 17 | const removeIdx3 = -3; 18 | const expected3 = null; 19 | const arr3Expected = ["a", "b", "c"]; 20 | 21 | const testCases = [ 22 | { 23 | args: [arr1, removeIdx1], 24 | expectedRet: expected1, 25 | expectedArr: arr1Expected, 26 | }, 27 | { 28 | args: [arr2, removeIdx2], 29 | expectedRet: expected2, 30 | expectedArr: arr2Expected, 31 | }, 32 | { 33 | args: [arr3, removeIdx3], 34 | expectedRet: expected3, 35 | expectedArr: arr3Expected, 36 | }, 37 | ]; 38 | 39 | testCases.forEach( 40 | ({ 41 | args: [givenArr, removeIdx], 42 | expectedRet, 43 | expectedArr, 44 | description, 45 | }) => { 46 | describe("when given " + description, () => { 47 | it("should remove and return the item at the specified index", () => { 48 | expect(testFn(givenArr, removeIdx)).toEqual(expectedRet); 49 | }); 50 | 51 | it("should have removed the item at the given index from the given array.", () => { 52 | expect(givenArr).toEqual(expectedArr); 53 | }); 54 | }); 55 | } 56 | ); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /src/recursion/sumToOneDigit/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Sum To One Digit 3 | Implement a function sumToOne(num)​ that, 4 | given a number, sums that number’s digits 5 | repeatedly until the sum is only one digit. Return 6 | that final one digit result. 7 | 8 | Tips: 9 | to access digits from a number, need to convert it .toString() to access each digit via index 10 | parseInt(arg) returns arg parsed as an integer, or NaN if it couldn't be converted to an int 11 | isNaN(arg) used to check if something is NaN 12 | */ 13 | 14 | const num1 = 5; 15 | const expected1 = 5; 16 | 17 | const num2 = 10; 18 | const expected2 = 1; 19 | 20 | const num3 = 25; 21 | const expected3 = 7; 22 | 23 | /** 24 | * Sums the given number's digits until the number becomes one digit. 25 | * @param {number} num The number to sum to one digit. 26 | * @returns {number} One digit. 27 | */ 28 | function sumToOneDigit(num) {} 29 | 30 | /*****************************************************************************/ 31 | 32 | function sumToOneDigit(n) { 33 | // Termination Condition if it's bad data (not a number) 34 | if (isNaN(parseInt(n))) { 35 | return null; 36 | } 37 | 38 | // base case: return solution 39 | if (n < 10) { 40 | return n; 41 | } 42 | 43 | const strNum = n.toString(); 44 | let sum = 0; 45 | 46 | for (const strDigit of strNum) { 47 | sum += parseInt(strDigit); 48 | } 49 | 50 | return sumToOneDigit(sum); 51 | } 52 | 53 | function sumToOneDigit2(num) { 54 | if (num < 10) { 55 | return num; 56 | } 57 | 58 | let sum = 0; 59 | 60 | while (num > 0) { 61 | sum += num % 10; 62 | num = Math.floor(num / 10); 63 | } 64 | return sumToOneDigit2(sum); 65 | } 66 | 67 | module.exports = { sumToOneDigit, sumToOneDigit2 }; 68 | -------------------------------------------------------------------------------- /src/arrays/countEvenNegatives/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Given an array of numbers, 3 | return a count of how many are both even and negative. 4 | */ 5 | 6 | const nums1 = [1, 5, -1, 2, -4, 9, -10, 0, -3, -2]; 7 | const expected1 = 3; 8 | 9 | const nums2 = []; 10 | const expected2 = 0; 11 | 12 | const nums3 = [-4, -2, -6]; 13 | const expected3 = 3; 14 | 15 | /** 16 | * Counts how many numbers are both even and negative. 17 | * - Time: O(?). 18 | * - Space: O(?). 19 | * @param {number} nums 20 | * @returns {number} The count. 21 | */ 22 | function countEvenNegatives(nums) {} 23 | 24 | /*****************************************************************************/ 25 | 26 | /** 27 | * Counts how many numbers are both even and negative. 28 | * - Time: O(n) linear, n = nums.length. We have to loop over the whole array. 29 | * - Space: O(1) constant. The amount of extra space taken up by our algo 30 | * remains constant even as the given array grows in length because we are 31 | * not storing more items if the array is larger since we are just storing 32 | * a single count. 33 | * @param {number} nums 34 | * @returns {number} The count. 35 | */ 36 | function countEvenNegatives(nums = []) { 37 | let count = 0; 38 | 39 | for (let i = 0; i < nums.length; i++) { 40 | if (nums[i] < 0 && nums[i] % 2 === 0) { 41 | count++; 42 | } 43 | } 44 | return count; 45 | } 46 | 47 | /** 48 | * - Time: O(n) linear, n = nums.length. We have to loop over the whole array. 49 | * - Space: O(n) linear. The filter method is creating a new array. 50 | */ 51 | const functionalCountEvenNegatives = (nums = []) => 52 | nums.filter((n) => n < 0 && n % 2 === 0).length; 53 | 54 | module.exports = { 55 | countEvenNegatives, 56 | functionalCountEvenNegatives, 57 | }; 58 | -------------------------------------------------------------------------------- /src/objects/santasNaughtyList/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const students = [ 6 | { 7 | firstName: "FN1", 8 | lastName: "LN1", 9 | habits: [ 10 | "doesn't wash dishes", 11 | "falls asleep in lecture", 12 | "shows up early", 13 | ], 14 | }, 15 | { 16 | firstName: "FN2", 17 | lastName: "LN2", 18 | habits: ["shows up late", "washes dishes", "helps peers"], 19 | }, 20 | { 21 | firstName: "FN3", 22 | lastName: "LN3", 23 | habits: ["doesn't wash dishes", "hoards snacks", "shows up late"], 24 | }, 25 | { 26 | firstName: "FN4", 27 | lastName: "LN4", 28 | habits: ["shows up early", "helps peers", "washes dishes"], 29 | }, 30 | ]; 31 | 32 | const badHabit1 = "doesn't wash dishes"; 33 | const expected1 = ["FN1 LN1", "FN3 LN3"]; 34 | 35 | const badHabit2 = "shows up late"; 36 | const expected2 = ["FN2 LN2", "FN3 LN3"]; 37 | 38 | const badHabit3 = "vapes too much"; 39 | const expected3 = []; 40 | 41 | const testCases = [ 42 | { args: [students, badHabit1], expected: expected1 }, 43 | { args: [students, badHabit2], expected: expected2 }, 44 | { args: [students, badHabit3], expected: expected3 }, 45 | ]; 46 | 47 | testCases.forEach(({ args, expected }, i) => { 48 | describe(`when given testCases[${i}]`, () => { 49 | it("should an array of all the student objects that have a matching given bad habit.", () => { 50 | expect(testFn(...args)).toEqual(expected); 51 | }); 52 | }); 53 | }); 54 | }); 55 | }); 56 | -------------------------------------------------------------------------------- /src/strings/isPalindrome/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | String: Is Palindrome 3 | 4 | Create a function that returns a boolean whether the string is a strict palindrome. 5 | - palindrome = string that is same forwards and backwards 6 | 7 | Do not ignore spaces, punctuation and capitalization 8 | */ 9 | 10 | const str1 = "a x a"; 11 | const expected1 = true; 12 | 13 | const str2 = "racecar"; 14 | const expected2 = true; 15 | 16 | const str3 = "Dud"; 17 | const expected3 = false; 18 | 19 | const str4 = "oho!"; 20 | const expected4 = false; 21 | 22 | /** 23 | * Determines if the given str is a palindrome (same forwards and backwards). 24 | * - Time: O(?). 25 | * - Space: O(?). 26 | * @param {string} str 27 | * @returns {boolean} Whether the given str is a palindrome or not. 28 | */ 29 | function isPalindrome(str) {} 30 | 31 | /*****************************************************************************/ 32 | 33 | /** 34 | * - Time: O(n/2) -> O(n) linear. 35 | * - Space: O(1) constant. 36 | * @param {string} str 37 | * @returns {boolean} 38 | */ 39 | function isPalindrome(str = "") { 40 | for (let i = 0; i < Math.floor(str.length / 2); i++) { 41 | // Looping inwards from both sides. 42 | const leftChar = str[i]; 43 | const rightChar = str[str.length - 1 - i]; 44 | 45 | if (leftChar !== rightChar) { 46 | return false; // early exit 47 | } 48 | } 49 | return true; 50 | } 51 | 52 | /** 53 | * - Time: O(3n) -> O(n) linear. Each method used is looping. 54 | * - Space: O(2n) linear. Split and join both create a copy. 55 | * @param {string} str 56 | * @returns {boolean} 57 | */ 58 | const functionIsPalindrome = (str = "") => 59 | str === str.split("").reverse().join(""); 60 | 61 | module.exports = { isPalindrome, functionIsPalindrome }; 62 | -------------------------------------------------------------------------------- /src/objects/getMaxServings/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const recipe1 = { 6 | "organic fat": 99, 7 | "broccoli seeds": 1, 8 | okra: 1, 9 | potato: 1, 10 | spicy: 5, 11 | "gourmet memes": 4200, 12 | }; 13 | 14 | const available1 = { 15 | "organic fat": 990, 16 | "broccoli seeds": 1, 17 | okra: 10, 18 | potato: 10, 19 | spicy: 50, 20 | "gourmet memes": 42000, 21 | sugar: 9001, 22 | spice: 5, 23 | "everything nice": 1, 24 | "triple point water": 5, 25 | }; 26 | const expected1 = 1; 27 | // because only 1 broccoli seeds is available and that is the limiting ingredient 28 | 29 | // same as available1, except broccoli seeds has 10. 30 | const available2 = { ...available1, ["broccoli seeds"]: 10 }; 31 | const expected2 = 10; 32 | 33 | // same as available1 except broccoli seeds key is deleted. 34 | const available3 = { ...available1 }; 35 | delete available3["broccoli seeds"]; 36 | const expected3 = 0; // broccoli seeds key doesn't exist in available ingredients 37 | 38 | const testCases = [ 39 | { args: [recipe1, available1], expected: expected1 }, 40 | { args: [recipe1, available2], expected: expected2 }, 41 | { args: [recipe1, available3], expected: expected3 }, 42 | ]; 43 | 44 | testCases.forEach(({ args, expected }, i) => { 45 | describe(`when given testCases[${i}]`, () => { 46 | it("should return maximum amount of servings that can be made from the given recipe and available ingredients.", () => 47 | expect(testFn(...args)).toEqual(expected)); 48 | }); 49 | }); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /src/strings/reverseString/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | String: Reverse 3 | 4 | Given a string, 5 | return a new string that is the given string reversed 6 | */ 7 | 8 | const str1 = "creature"; 9 | const expected1 = "erutaerc"; 10 | 11 | const str2 = "dog"; 12 | const expected2 = "god"; 13 | 14 | const str3 = "hello"; 15 | const expected3 = "olleh"; 16 | 17 | const str4 = ""; 18 | const expected4 = ""; 19 | 20 | /** 21 | * Reverses the given str. 22 | * - Time: O(?). 23 | * - Space: O(?). 24 | * @param {string} str String to be reversed. 25 | * @returns {string} The given str reversed. 26 | */ 27 | function reverseString(str) {} 28 | 29 | /*****************************************************************************/ 30 | 31 | /** 32 | * - Time: O(n) linear. 33 | * - Space: O(n) linear. 34 | * @param {string} str 35 | * @returns {string} 36 | */ 37 | function reverseString(str = "") { 38 | let reversed = ""; 39 | 40 | for (let i = str.length - 1; i >= 0; i--) { 41 | reversed += str[i]; 42 | } 43 | 44 | return reversed; 45 | } 46 | 47 | /** 48 | * - Time: O(n) linear. 49 | * - Space: O(n) linear. 50 | * @param {string} str 51 | * @returns {string} 52 | */ 53 | function reverseString2(str = "") { 54 | let reversed = ""; 55 | 56 | for (let i = 0; i < str.length; i++) { 57 | // prepend instead of append since we aren't looping backwards. 58 | reversed = str[i] + reversed; 59 | } 60 | 61 | return reversed; 62 | } 63 | 64 | /** 65 | * - Time: O(3n) -> O(n) linear. 66 | * - Space: O(2n) -> O(n) linear. Split and join are both duplicating data. 67 | * @param {string} str 68 | * @returns {string} 69 | */ 70 | const functionalReverseStr = (str = "") => str.split("").reverse().join(""); 71 | 72 | module.exports = { reverseString, reverseString2, functionalReverseStr }; 73 | -------------------------------------------------------------------------------- /src/strings/outputToJson/output.txt: -------------------------------------------------------------------------------- 1 | ID : 0 2 | Status : Ok 3 | Name : OS 4 | State : Ready 5 | Hot Spare Policy violated : Not Assigned 6 | Encrypted : Not Applicable 7 | Layout : RAID-5 8 | Size : 200.00 GB (214748364800 bytes) 9 | T10 Protection Information Status : No 10 | Associated Fluid Cache State : Not Applicable 11 | Device Name : Windows Disk 0 12 | Bus Protocol : SATA 13 | Media : HDD 14 | Read Policy : No Read Ahead 15 | Write Policy : Write Back 16 | Cache Policy : Not Applicable 17 | Stripe Element Size : 64 KB 18 | Disk Cache Policy : Enabled 19 | 20 | ID : 1 21 | Status : Ok 22 | Name : DATA 23 | State : Ready 24 | Hot Spare Policy violated : Not Assigned 25 | Encrypted : Not Applicable 26 | Layout : RAID-5 27 | Size : 7,250.00 GB (7784628224000 bytes) 28 | T10 Protection Information Status : No 29 | Associated Fluid Cache State : Not Applicable 30 | Device Name : Windows Disk 1 31 | Bus Protocol : SATA 32 | Media : HDD 33 | Read Policy : No Read Ahead 34 | Write Policy : Write Back 35 | Cache Policy : Not Applicable 36 | Stripe Element Size : 64 KB 37 | Disk Cache Policy : Enable -------------------------------------------------------------------------------- /src/data_structures/Trie/intro.md: -------------------------------------------------------------------------------- 1 | # Trie 2 | 3 | ## Intro 4 | 5 | - best known use case is auto-complete text. 6 | - also called digital tree or prefix tree, is a kind of search tree—an ordered tree data structure used to store a dynamic set or associative array where the keys are usually strings 7 | - The trie data structure (initially pronounced “tree” as in the middle syllable of re*trie*val, but now universally pronounced “try” to avoid confusion) is useful in scenarios usually reserved for a hash. 8 | - auto-complete saves additional info on the nodes about how frequently it is used as a word to improve predictive power 9 | - Each node's value will be a letter to represent a letter in a word 10 | - each node has children (arry of nodes alphabetized) to represent the next possible letters in the word (empty array if the word has ended), but there could be a node that has children while still being a full word already, for words contained in other words, e.g., geek in geeks, geek is a full word alread but has 's' as a child. 11 | - [diagram](https://4.bp.blogspot.com/-GNWc5KUMGYc/WAskP-EHFKI/AAAAAAAAEz4/8yikxc2niYgyqH0FWFafq5UTp_kUK6O5ACLcB/s1600/TrieDataStructureImpl.png) 12 | 13 | ## Starter Code 14 | 15 | ```js 16 | class TrieNode { 17 | constructor(val = null) { 18 | this.val = val; 19 | this.children = []; 20 | } 21 | } 22 | 23 | class TrieSet { 24 | constructor() { 25 | this.root = new TrieNode(""); 26 | } 27 | 28 | method1(params) { 29 | // 'this' keyword will refer to the 30 | // HashMap instance that method1 was called on 31 | } 32 | } 33 | 34 | // Alternate way to add method to class after it has been declared 35 | TrieSet.prototype.newMethodName = function (params) { 36 | // 'this' keyword will refer to the 37 | // TrieSet instance that method1 was called on 38 | }; 39 | ``` 40 | -------------------------------------------------------------------------------- /src/data_structures/Graphs/travelingSalesman/travelingSalesman.js: -------------------------------------------------------------------------------- 1 | /* 2 | Given a list of cities and the distances between each pair of cities, what is 3 | the shortest possible route that visits each city exactly once and returns to 4 | the origin city? 5 | 6 | In Technical Terms: 7 | Given a complete graph with weighted edges (as an adjacency map) what is the 8 | Hamiltonian cycle (path that visits every node once) of minimum cost? 9 | 10 | Time Complexity: 11 | Brute Force - O(n!) - Factorial, checks every possible path. 12 | Dynamic Programming: O(n^2 * 2^n) 13 | 14 | n n! n^2 * 2^n 15 | ------------------------------------------------------ 16 | 1 1 2 17 | ------------------------------------------------------ 18 | 2 2 16 19 | ------------------------------------------------------ 20 | 3 6 72 21 | ------------------------------------------------------ 22 | 4 24 256 23 | ------------------------------------------------------ 24 | 5 120 800 25 | ------------------------------------------------------ 26 | 6 720 2304 27 | ------------------------------------------------------ 28 | ... ... ... 29 | ------------------------------------------------------ 30 | 15 1307674368000 7372800 31 | ------------------------------------------------------ 32 | 16 20922789888000 16777216 33 | ------------------------------------------------------ 34 | 17 355687428096000 37879808 35 | ------------------------------------------------------ 36 | 37 | DP Idea: compute the optimal solution for all the subpaths of length N while 38 | using information from the already known optimal partial tours of length N-1. 39 | 40 | Pick starting node "S" whose index is 0 <= S < N (including 0 to N exclusive) 41 | */ 42 | -------------------------------------------------------------------------------- /src/amazon/musicRuntime/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const busDuration1 = 300; 6 | const songDurations1 = [70, 120, 200, 45, 210, 40, 60, 50]; 7 | const expected1 = [4, 6]; // 210, 60 8 | /* Explanation: 9 | There are multiple pairs that add up to 30 seconds before the bus duration. 10 | The pair at indexes 4 and 6 is the pair with the longest song that is chosen. 11 | */ 12 | 13 | const busDuration2 = 300; 14 | const songDurations2 = [70, 120, 200, 230, 45, 210, 40, 60, 50]; 15 | const expected2 = [3, 6]; // 230, 40 16 | /* Explanation: 17 | This is the pair with the longest song. 18 | */ 19 | 20 | const busDuration3 = 300; 21 | const songDurations3 = [70, 120, 20, 23, 45, 21, 40, 60, 50]; 22 | const expected3 = [-1, -1]; // not found. 23 | 24 | const testCases = [ 25 | { 26 | args: [busDuration1, songDurations1], 27 | expected: expected1, 28 | description: "two possible solutions", 29 | }, 30 | { 31 | args: [busDuration2, songDurations2], 32 | expected: expected2, 33 | description: "two possible neighboring solutions", 34 | }, 35 | { 36 | args: [busDuration3, songDurations3], 37 | expected: expected3, 38 | description: "no solution", 39 | }, 40 | ]; 41 | 42 | testCases.forEach(({ args, expected, description }) => { 43 | describe("when given " + description, () => { 44 | it("should return the pair of songs that is 30 seconds less than the given bus duration or [-1, -1].", () => { 45 | expect(testFn(...args)).toEqual( 46 | jasmine.arrayWithExactContents(expected) 47 | ); 48 | }); 49 | }); 50 | }); 51 | }); 52 | }); 53 | -------------------------------------------------------------------------------- /src/arrays/socialDistancingEnforcer/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Given an array of ints representing a line of people where the space between 3 | indexes is 1 foot, with 0 meaning no one is there and 1 meaning someone is in 4 | that space, 5 | 6 | return whether or not there is at least 6 feet separating every person. 7 | 8 | Bonus: O(n) linear time (avoid nested loops that cause re-visiting indexes). 9 | */ 10 | 11 | const queue1 = [0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1]; 12 | const expected1 = false; 13 | 14 | const queue2 = [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1]; 15 | const expected2 = true; 16 | 17 | const queue3 = [1, 0, 0, 0, 0, 0, 0, 0, 1]; 18 | const expected3 = true; 19 | 20 | const queue4 = []; 21 | const expected4 = true; 22 | 23 | /** 24 | * Determines whether each occupied space in the line of people is separated by 25 | * 6 empty spaces. 26 | * - Time: O(?). 27 | * - Space: O(?). 28 | * @param {Array<0|1>} queue 29 | * @returns {Boolean} 30 | */ 31 | function socialDistancingEnforcer(queue) {} 32 | 33 | /*****************************************************************************/ 34 | 35 | /** 36 | * Determines whether each occupied space in the line of people is separated by 37 | * 6 empty spaces. 38 | * - Time: O(n) linear. 39 | * - Space: O(1) constant. 40 | * @param {Array<0|1>} queue 41 | * @returns {Boolean} 42 | */ 43 | function socialDistancingEnforcer(queue = []) { 44 | let distance = 0; 45 | let firstPersonSeen = false; 46 | 47 | // Use the existing i value 48 | for (let i = 0; i < queue.length; i++) { 49 | if (queue[i] === 0) { 50 | distance += 1; 51 | } else { 52 | if (firstPersonSeen && distance < 6) { 53 | return false; 54 | } 55 | 56 | firstPersonSeen = true; 57 | distance = 0; 58 | } 59 | } 60 | return true; 61 | } 62 | 63 | module.exports = { socialDistancingEnforcer }; 64 | -------------------------------------------------------------------------------- /src/arrays/twoSum/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const nums1 = [2, 11, 7, 15]; 6 | const targetSum1 = 9; 7 | const expected1 = [0, 2]; 8 | // Explanation: nums[0] + nums[2] = 2 + 7 = 9 9 | 10 | const nums2 = [10, 3, 2, 5, 4, -1]; 11 | const targetSum2 = 6; 12 | const expected2 = [2, 4]; 13 | 14 | const nums3 = [3, 8, 4, 1, 9, 0, -2]; 15 | const targetSum3 = 6; 16 | const expected3 = [1, 6]; 17 | 18 | const nums4 = [3, 8, 4, 1, 9, 0, -2]; 19 | const targetSum4 = 8; 20 | const expected4 = [1, 5]; 21 | 22 | const testCases = [ 23 | { 24 | args: [nums1, targetSum1], 25 | expected: expected1, 26 | description: "an array with the first number as part of the solution", 27 | }, 28 | { 29 | args: [nums2, targetSum2], 30 | expected: expected2, 31 | description: 32 | "an array where the solution numbers are separated by one index", 33 | }, 34 | { 35 | args: [nums3, targetSum3], 36 | expected: expected3, 37 | description: 38 | "an array where a negative number at the end is part of the solution", 39 | }, 40 | { 41 | args: [nums4, targetSum4], 42 | expected: expected4, 43 | description: "an array where 0 is part of the solution", 44 | }, 45 | ]; 46 | 47 | testCases.forEach(({ args, expected, description }) => { 48 | describe("when given " + description, () => { 49 | it("should find the two ints in the given array that add up to the given sum and return their indexes.", () => { 50 | expect(testFn(...args)).toEqual( 51 | jasmine.arrayWithExactContents(expected) 52 | ); 53 | }); 54 | }); 55 | }); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /src/recreated_methods/Array/join/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const arr1 = [1, 2, 3]; 6 | const separator1 = ", "; 7 | const expected1 = "1, 2, 3"; 8 | 9 | const arr2 = [1, 2, 3]; 10 | const separator2 = "-"; 11 | const expected2 = "1-2-3"; 12 | 13 | const arr3 = [1, 2, 3]; 14 | const separator3 = " - "; 15 | const expected3 = "1 - 2 - 3"; 16 | 17 | const arr4 = [1]; 18 | const separator4 = ", "; 19 | const expected4 = "1"; 20 | 21 | const arr5 = []; 22 | const separator5 = ", "; 23 | const expected5 = ""; 24 | 25 | const testCases = [ 26 | { 27 | args: [arr1, separator1], 28 | expected: expected1, 29 | description: "three items to join with comma and a space", 30 | }, 31 | { 32 | args: [arr2, separator2], 33 | expected: expected2, 34 | description: "three items to join with a hyphen", 35 | }, 36 | { 37 | args: [arr3, separator3], 38 | expected: expected3, 39 | description: 40 | "three items to join with a hyphen and a space on both sides", 41 | }, 42 | { 43 | args: [arr4, separator4], 44 | expected: expected4, 45 | description: "one item only", 46 | }, 47 | { 48 | args: [arr5, separator5], 49 | expected: expected5, 50 | description: "an empty array ", 51 | }, 52 | ]; 53 | 54 | testCases.forEach(({ args, expected }, i) => { 55 | describe(`when given testCases[${i}]`, () => { 56 | it("should return a string that contains the items of the given array joined and separated by the given separator.", () => { 57 | expect(testFn(...args)).toEqual(expected); 58 | }); 59 | }); 60 | }); 61 | }); 62 | }); 63 | -------------------------------------------------------------------------------- /src/recreated_methods/Array/pop/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const arr1 = [1, 2, 3]; 6 | const expected1 = 3; 7 | // what arr1 should be after running pop function 8 | const expectedArr1 = [1, 2]; 9 | 10 | const arr2 = ["hello"]; 11 | const expected2 = "hello"; 12 | const expectedArr2 = []; // the only item was removed 13 | 14 | const arr3 = ["hello", "world"]; 15 | const expected3 = "world"; 16 | const expectedArr3 = ["hello"]; // the last item was removed 17 | 18 | const arr4 = []; 19 | const expected4 = undefined; 20 | const expectedArr4 = []; 21 | 22 | const testCases = [ 23 | { 24 | args: [arr1], 25 | expectedRet: expected1, 26 | expectedArr: expectedArr1, 27 | description: "three numbers", 28 | }, 29 | { 30 | args: [arr2], 31 | expectedRet: expected2, 32 | expectedArr: expectedArr2, 33 | description: "one word", 34 | }, 35 | { 36 | args: [arr3], 37 | expectedRet: expected3, 38 | expectedArr: expectedArr3, 39 | description: "two words", 40 | }, 41 | { 42 | args: [arr4], 43 | expectedRet: expected4, 44 | expectedArr: expectedArr4, 45 | description: "an empty array", 46 | }, 47 | ]; 48 | 49 | testCases.forEach(({ args: [arr], expectedRet, expectedArr }, i) => { 50 | describe(`when given testCases[${i}]`, () => { 51 | it("should return the last item from the given array.", () => { 52 | expect(testFn(arr)).toBe(expectedRet); 53 | }); 54 | 55 | it("should have removed the last item from the given array.", () => { 56 | expect(arr).toEqual(expectedArr); 57 | }); 58 | }); 59 | }); 60 | }); 61 | }); 62 | -------------------------------------------------------------------------------- /src/sets/orderedIntersection/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const numsA1 = [0, 1, 2, 2, 2, 7]; 6 | const numsB1 = [2, 2, 6, 6, 7]; 7 | const expected1 = [2, 7]; 8 | 9 | const numsA2 = [0, 1, 2, 2, 2, 7]; 10 | const numsB2 = [2, 2]; 11 | const expected2 = [2]; 12 | 13 | const numsA3 = [0, 1, 2, 2, 2, 7]; 14 | const numsB3 = [10]; 15 | const expected3 = []; 16 | 17 | const testCases = [ 18 | { 19 | args: [numsA1, numsB1], 20 | expected: expected1, 21 | description: "a first array longer by one than the second array", 22 | }, 23 | { 24 | args: [numsA2, numsB2], 25 | expected: expected2, 26 | description: 27 | "a first array more than double the size of the second array", 28 | }, 29 | { 30 | args: [numsA3, numsB3], 31 | expected: expected3, 32 | description: 33 | "a second array with only one number that is larger than all the first array numbers", 34 | }, 35 | ]; 36 | 37 | testCases.forEach(({ args: [numsA, numsB], expected, description }) => { 38 | describe("when given " + description, () => { 39 | const copyOfNumsA = [...numsA]; 40 | const copyOfNumsB = [...numsB]; 41 | const actual = testFn(numsA, numsB); 42 | 43 | it("should return the ordered deduped intersection of two given sorted arrays.", () => { 44 | expect(actual).toEqual(expected); 45 | }); 46 | 47 | it("should not mutate the first given array", () => { 48 | expect(numsA).toEqual(copyOfNumsA); 49 | }); 50 | 51 | it("should not mutate the second given array", () => { 52 | expect(numsB).toEqual(copyOfNumsB); 53 | }); 54 | }); 55 | }); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /src/strings/isRotation/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Create the function isRotation(str1,str2) that 3 | returns whether the second string is a rotation of the first. 4 | */ 5 | 6 | const strA1 = "ABCD"; 7 | const strB1 = "CDAB"; 8 | // Explanation: if you start from A in the 2nd string, the letters are in the same order, just rotated 9 | const expected1 = true; 10 | 11 | const strA2 = "ABCD"; 12 | const strB2 = "CDBA"; 13 | // Explanation: all same letters in 2nd string, but out of order 14 | const expected2 = false; 15 | 16 | const strA3 = "ABCD"; 17 | const strB3 = "BCDAB"; 18 | // Explanation: same letters in correct order but there is an extra letter. 19 | const expected3 = false; 20 | 21 | /** 22 | * Determines whether the second string is a rotated version of the first. 23 | * - Time: O(?). 24 | * - Space: O(?). 25 | * @param {string} s1 26 | * @param {string} s2 27 | * @returns {boolean} Whether the second string is a rotated version of the 1st. 28 | */ 29 | function isRotation(s1, s2) {} 30 | 31 | /*****************************************************************************/ 32 | 33 | /** 34 | * Solution approach: 35 | * All rotated versions of s2 are included in s1 + s1. 36 | * s1: "ABCD". 37 | * s1 + s1: "ABCDABCD". 38 | * 39 | * s2 Rotation variations: 40 | * s2: "CDAB". 41 | * s2: "DABC". 42 | * s2: "BCDA". 43 | * - Time: O(4n) -> O(n) linear. Concatenating s1 + s1 requires the characters 44 | * of s1 to be copied into a new string twice (2n). The .includes is then 45 | * looping over the string that is twice the length of s1 (2n) again. Add 46 | * up both 2n to get 4n. 47 | * - Space: O(2n) -> O(n) linear, where n is s1.length, 2n from s1 + s1. 48 | */ 49 | function isRotation(s1 = "", s2 = "") { 50 | if (s1.length !== s2.length || s1 === s2) { 51 | return false; 52 | } 53 | return (s1 + s1).includes(s2); 54 | } 55 | 56 | module.exports = { isRotation }; 57 | -------------------------------------------------------------------------------- /src/objects/updateInventory/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const newInv1 = [ 6 | { name: "Grain of Rice", quantity: 9000 }, 7 | { name: "Peanut Butter", quantity: 50 }, 8 | { name: "Royal Jelly", quantity: 20 }, 9 | ]; 10 | const currInv1 = [ 11 | { name: "Peanut Butter", quantity: 20 }, 12 | { name: "Grain of Rice", quantity: 1 }, 13 | ]; 14 | const expected1 = [ 15 | { name: "Peanut Butter", quantity: 70 }, 16 | { name: "Grain of Rice", quantity: 9001 }, 17 | { name: "Royal Jelly", quantity: 20 }, 18 | ]; 19 | 20 | const newInv2 = []; 21 | const currInv2 = [{ name: "Peanut Butter", quantity: 20 }]; 22 | const expected2 = [{ name: "Peanut Butter", quantity: 20 }]; 23 | 24 | const newInv3 = [{ name: "Peanut Butter", quantity: 20 }]; 25 | const currInv3 = []; 26 | const expected3 = [{ name: "Peanut Butter", quantity: 20 }]; 27 | 28 | const testCases = [ 29 | { 30 | args: [newInv1, currInv1], 31 | expected: expected1, 32 | description: "one two inventory item and two existing items", 33 | }, 34 | { 35 | args: [newInv2, currInv2], 36 | expected: expected2, 37 | description: "an empty array of new inventory", 38 | }, 39 | { 40 | args: [newInv3, currInv3], 41 | expected: expected3, 42 | description: "one new inventory item and empty current inventory", 43 | }, 44 | ]; 45 | 46 | testCases.forEach(({ args, expected }, i) => { 47 | describe(`when given testCases[${i}]`, () => { 48 | it("should return whether or not the 1st given string is a rotation of the 2nd given string.", () => { 49 | expect(testFn(...args)).toEqual(expected); 50 | }); 51 | }); 52 | }); 53 | }); 54 | }); 55 | -------------------------------------------------------------------------------- /src/strings/getQuoteFromCaret/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Given a str and an in-bounds idx that represents the position of the caret 3 | * return the substr that is enclosed by double quotes that the caret is within 4 | * or an empty string if the caret is not within double quotes. 5 | */ 6 | 7 | const str1 = `wow "jabascript cool" lol "foo"`; 8 | const idx1 = 10; 9 | const expected1 = "jabascript cool"; 10 | 11 | const str2 = `hello "world", good morning.`; 12 | const idx2 = 2; 13 | const expected2 = ""; 14 | 15 | /** 16 | * Finds the double quote enclosed substr that the caret is within. 17 | * @param {string} str 18 | * @param {number} caretIdx Represents the location of the caret. 19 | * @returns {string} The double quote enclosed substr. 20 | */ 21 | function getQuoteFromCaret(str, caretIdx) {} 22 | 23 | /*****************************************************************************/ 24 | 25 | /** 26 | * Finds the double quote enclosed substr that the caret is within. 27 | * @param {string} str 28 | * @param {number} caretIdx Represents the location of the caret. 29 | * @returns {string} The double quote enclosed substr. 30 | */ 31 | function getQuoteFromCaret(str, caretIdx) { 32 | let quote = ""; 33 | 34 | let leftQuoteFound = false; 35 | let leftIdx = caretIdx; 36 | 37 | while (leftIdx >= 0) { 38 | if (str[leftIdx] === `"`) { 39 | leftQuoteFound = true; 40 | break; 41 | } 42 | 43 | quote = str[leftIdx] + quote; 44 | leftIdx--; 45 | } 46 | 47 | let rightIdx = caretIdx + 1; 48 | let rightQuoteFound = false; 49 | 50 | while (rightIdx < str.length) { 51 | if (str[rightIdx] === `"`) { 52 | rightQuoteFound = true; 53 | break; 54 | } 55 | 56 | quote += str[rightIdx]; 57 | rightIdx++; 58 | } 59 | 60 | if (leftQuoteFound && rightQuoteFound) { 61 | return quote; 62 | } 63 | 64 | return ""; 65 | } 66 | 67 | module.exports = { getQuoteFromCaret }; 68 | -------------------------------------------------------------------------------- /src/arrays/sumArrColumns/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Input: Two arrays of equal length containing integers 3 | Output: A new array where each item is the sum of 4 | the items in arr1 and arr2 at that same index 5 | */ 6 | 7 | const numbersA1 = [20, 10, 30]; 8 | const numbersB1 = [10, 30, 20]; 9 | const expected1 = [30, 40, 50]; 10 | 11 | /** 12 | * Returns a new array that is the sum of the columns of the two given arrays 13 | * of equal lengths. 14 | * - Time: O(?). 15 | * - Space: O(?). 16 | * @param {Array} nums1 17 | * @param {Array} nums2 18 | * @returns {Array} The column sums. 19 | */ 20 | function sumArrColumns(nums1, nums2) { 21 | // code here 22 | } 23 | 24 | // Tests 25 | const result1 = sumArrColumns(numbersA1, numbersB1); 26 | console.log(result1, "should equal", expected1); 27 | 28 | /*****************************************************************************/ 29 | 30 | /** 31 | * Returns a new array that is the sum of the columns of the two given arrays 32 | * of equal lengths. 33 | * - Time: O(n) linear, n = length of either nums1 or nums2 since they will 34 | * have the same length. 35 | * - Space: O(n) linear. The new array created will have the same length. 36 | * @param {Array} nums1 37 | * @param {Array} nums2 38 | * @returns {Array} The column sums. 39 | */ 40 | function sumArrColumns(nums1 = [], nums2 = []) { 41 | const summedCols = []; 42 | 43 | for (let i = 0; i < nums1.length; i++) { 44 | summedCols.push(nums1[i] + nums2[i]); 45 | } 46 | return summedCols; 47 | } 48 | 49 | /** 50 | * - Time: O(n) linear. 51 | * - Space: O(n) linear. `.map` creates a new array. 52 | * @param {Array} nums1 53 | * @param {Array} nums2 54 | * @returns {Array} 55 | */ 56 | const functionalSumArrColumns = (nums1 = [], nums2 = []) => 57 | nums1.map((n1, i) => n1 + nums2[i]); 58 | 59 | module.exports = { 60 | sumArrColumns, 61 | functionalSumArrColumns, 62 | }; 63 | -------------------------------------------------------------------------------- /schedules/web_fund.md: -------------------------------------------------------------------------------- 1 | # Web Fund Algo Schedule 2 | 3 | - [Pair Programming](../pair-programming.md) 4 | - **NOTE: A new set of web fund algos were added to web fund 2021 curriculum so these are no longer used, but they are a great fundamental set if more algos are desired and the platform doesn't cover the recreation of some of the fundamental array methods that are covered here.** 5 | - [Printable Basic 13](https://docs.google.com/document/d/1Vw-8ZzZy_kfkcK-6MUkXJNfNQ7qX9_nkxnIBNoVNdbM/edit#heading=h.wr6t3eu5n64f) 6 | 7 | --- 8 | 9 | ## Week 1 - Intro 10 | 11 | 1. Mon 12 | - Orientation 13 | - basics review: variables, arrays, loops, functions 14 | - [Functions Intro](../src/intro/basicAlgos/intro.md) 15 | 2. Tue 16 | - [basicAlgos](../src/intro/basicAlgos/index.js) 17 | 3. Wed 18 | - [indexOf](../src/recreated_methods/Array/indexOf/index.js) 19 | - unfinished [basicAlgos](../src/intro/basicAlgos/index.js) 20 | 4. Thur 21 | - [nthLast](../src/arrays/nthLast/index.js) 22 | - [countEvenNegatives](../src/arrays/countEvenNegatives/index.js) 23 | 5. Fri 24 | - [slice](../src/recreated_methods/Array/slice/index.js) 25 | - [capitalization](../src/strings/capitalization/index.js) 26 | 27 | --- 28 | 29 | ## Week 2 - Arrays 30 | 31 | 1. Mon 32 | - [concat](../src/recreated_methods/Array/concat/index.js) 33 | - [concatSelf](../src/arrays/concatSelf/index.js) 34 | 2. Tue 35 | - [indexOfMinVal](../src/arrays/indexOfMinVal/index.js) 36 | - [reverseArr](../src/arrays/reverseArr/index.js) 37 | 3. Wed 38 | - [unshift](../src/recreated_methods/Array/unshift/index.js) 39 | - [shift](../src/recreated_methods/Array/shift/index.js) 40 | 4. Thur 41 | - [removeAt](../src/arrays/removeAt/index.js) 42 | - [minToFront](../src/arrays/minToFront/index.js) 43 | 5. Fri 44 | - [flatten2dArray](../src/arrays/flatten2dArray/index.js) 45 | - [secondLargest](../src/arrays/secondLargest/index.js) 46 | - [sumArrColumns](../src/arrays/sumArrColumns/index.js) 47 | -------------------------------------------------------------------------------- /src/data_structures/Trie/index.js: -------------------------------------------------------------------------------- 1 | class TrieNode { 2 | constructor(val = null) { 3 | this.val = val; 4 | // children will be TrieNodes as well 5 | this.children = []; 6 | } 7 | } 8 | 9 | class TrieSet { 10 | constructor() { 11 | this.root = new TrieNode(""); 12 | } 13 | 14 | add(val, node = this.root, partial = "") { 15 | // when val str has been sliced all the way it will be empty str 16 | if (val === "") { 17 | if (node.val === partial) { 18 | return false; 19 | } 20 | 21 | node.val = partial; 22 | return true; 23 | } 24 | 25 | const index = val[0].toLowerCase().charCodeAt(0) - 97; 26 | let nextNode = node.children[index]; 27 | 28 | if (nextNode === undefined) { 29 | nextNode = node.children[index] = new TrieNode(); 30 | } 31 | return this.add(val.slice(1), nextNode, partial + val[0]); 32 | } 33 | 34 | contains(val, node = this.root, partial = "") { 35 | if (node === undefined) { 36 | return false; 37 | } 38 | 39 | if (val === "") { 40 | return node.val === partial; 41 | } 42 | 43 | const index = val[0].toLowerCase().charCodeAt(0) - 97; 44 | return this.contains(val.slice(1), node.children[index], partial + val[0]); 45 | } 46 | 47 | autoComplete(val, node = this.root, completions = []) { 48 | if (node === undefined) return completions; 49 | 50 | if (val === "") { 51 | if (node.val !== null) { 52 | completions.push(node.val); 53 | } 54 | 55 | for (let i = 0; i < node.children.length; i++) { 56 | if (node.children[i] !== undefined) { 57 | this.autoComplete("", node.children[i], completions); 58 | } 59 | } 60 | } else { 61 | const index = val[0].toLowerCase().charCodeAt(0) - 97; 62 | this.autoComplete(val.slice(1), node.children[index], completions); 63 | } 64 | return completions; 65 | } 66 | } 67 | 68 | module.exports = { 69 | TrieSet, 70 | TrieNode, 71 | }; 72 | -------------------------------------------------------------------------------- /src/objects/groupObjects/index.spec.js: -------------------------------------------------------------------------------- 1 | const functions = require("."); 2 | 3 | Object.values(functions).forEach((testFn) => { 4 | describe(testFn.name, () => { 5 | const objects1 = [ 6 | { 7 | name: "Baby Yoda", 8 | category: "cute", 9 | }, 10 | { 11 | name: "Cricket Protein", 12 | category: "food", 13 | }, 14 | { 15 | name: "Shibe", 16 | category: "Cute", 17 | }, 18 | { 19 | name: "Ancient India", 20 | category: "Cradle of Civilization", 21 | }, 22 | { 23 | name: "Wasp Crackers", 24 | category: "Food", 25 | }, 26 | { 27 | name: "The Fertile Crescent", 28 | category: "Cradle of Civilization", 29 | }, 30 | ]; 31 | 32 | const expected1 = { 33 | cute: [ 34 | { 35 | name: "Baby Yoda", 36 | category: "cute", 37 | }, 38 | { 39 | name: "Shibe", 40 | category: "Cute", 41 | }, 42 | ], 43 | food: [ 44 | { 45 | name: "Cricket Protein", 46 | category: "food", 47 | }, 48 | { 49 | name: "Wasp Crackers", 50 | category: "Food", 51 | }, 52 | ], 53 | "cradle of civilization": [ 54 | { 55 | name: "Ancient India", 56 | category: "Cradle of Civilization", 57 | }, 58 | { 59 | name: "The Fertile Crescent", 60 | category: "Cradle of Civilization", 61 | }, 62 | ], 63 | }; 64 | 65 | const testCases = [{ args: [objects1], expected: expected1 }]; 66 | testCases.forEach(({ args, expected }, i) => { 67 | describe(`when given testCases[${i}]`, () => { 68 | it("should return a new array of only the objects from the given array that match the provided search criteria.", () => { 69 | expect(testFn(...args)).toEqual(expected); 70 | }); 71 | }); 72 | }); 73 | }); 74 | }); 75 | -------------------------------------------------------------------------------- /src/objects/invertObj/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Invert Hash 3 | 4 | A hash table / hash map is an obj / dictionary 5 | 6 | Given an object / dict, 7 | return a new object / dict that has the keys and the values swapped so that the keys become the values and the values become the keys 8 | */ 9 | 10 | const obj1 = { name: "Zaphod", charm: "high", morals: "dicey" }; 11 | const expected1 = { Zaphod: "name", high: "charm", dicey: "morals" }; 12 | 13 | /** 14 | * Inverts the given object's key value pairs so that the original values 15 | * become the keys and the original keys become the values. 16 | * - Time: O(?). 17 | * - Space: O(?). 18 | * @param {Object} obj 19 | * @return The given object with key value pairs inverted. 20 | */ 21 | function invertObj(obj) {} 22 | 23 | /*****************************************************************************/ 24 | 25 | /** 26 | * Inverts the given object's key value pairs so that the original values 27 | * become the keys and the original keys become the values. 28 | * - Time: O(n) linear, where n is amount of keys in obj. 29 | * - Space: O(n). 30 | * @param {Object} obj 31 | * @return The given object with key value pairs inverted. 32 | */ 33 | function invertObj(obj = {}) { 34 | const inverted = {}; 35 | 36 | for (let key in obj) { 37 | const value = obj[key]; 38 | 39 | inverted[value] = key; 40 | } 41 | return inverted; 42 | } 43 | 44 | /** 45 | * Inverts the given object's key value pairs so that the original values 46 | * become the keys and the original keys become the values. 47 | * - Time: O(2n) -> O(n) linear, where n is amount of keys in obj. 48 | * - Space: O(n). 49 | * @param {Object} obj 50 | * @return The given object with key value pairs inverted. 51 | */ 52 | const functionalInvertObj = (obj = {}) => 53 | Object.entries(obj).reduce((inverted, [key, value]) => { 54 | inverted[value] = key; 55 | return inverted; 56 | }, {}); 57 | 58 | module.exports = { invertObj, functionalInvertObj }; 59 | --------------------------------------------------------------------------------