├── README.md ├── easy ├── ABCheck.js ├── AdditivePersistence.js ├── AlphabetSearching.js ├── ArithGeo.js ├── BinaryReversal.js ├── ClosestEnemyII.js ├── CommandLine.js ├── CorrectPath.js ├── GCF.js ├── LargestFour.js ├── NumberStream.js ├── PalindromeSwapper.js ├── QuestionsMarks.js ├── ScaleBalancing.js ├── SimpleEvens.js ├── StringPeriods.js ├── ThreeNumbers.js └── VowelSquare.js ├── hard ├── ApproachingFibonacci.js ├── ArrayRotation.js ├── ChessboardTraveling.js ├── CityTraffic.js ├── CountingAnagrams.js ├── FarthestNodes.js ├── GasStation.js ├── KnightJumps.js ├── LCS.js ├── MaxHeapChecker.js ├── MaximalRectangle.js ├── PatternChaser.js ├── QueenCheck.js ├── QuickKnight.js ├── ShortestPath.js ├── SquareFigures.js ├── SudokuQuadrantChecker.js ├── SymmetricMatrix.js ├── TetrisMove.js └── WildcardCharacters.js └── medium ├── BinarySearchTreeLCA.js ├── BinaryTreeLCA.js ├── BracketMatcher.js ├── CaesarCipher.js ├── CharacterRemoval.js ├── CoinDeterminer.js ├── DashInsertII.js ├── FibonacciChecker.js ├── HTMLElements.js ├── KUniqueCharacters.js ├── LRUCache.js ├── LookSaySequence.js ├── MaxSubarray.js ├── MissingDigit.js ├── MissingDigitII.js ├── MostFreeTime.js ├── MultipleBrackets.js ├── NumberSearch.js ├── OffBinary.js ├── PermutationStep.js ├── SeatingStudents.js ├── SimpleMode.js ├── StockPicker.js ├── StringReduction.js ├── SwapII.js ├── SymmetricTree.js ├── ThreeFiveMultiples.js ├── TreeConstructor.js └── TripleDouble.js /README.md: -------------------------------------------------------------------------------- 1 | # coderbyte 2 | my Coderbyte Challenge submissions 3 | 4 | 5 | Hello! 6 | 7 | All of my code is ECMAScript 2019 compatible. 8 | 9 | This is simply an excerpt of my subbissions to the coderbyte challenge. 10 | 11 | The ones I've submitted here on Github is the ones I feel can be of interrest for the public, 12 | and they all should be understandable for a programmers mind. 13 | 14 | If you don't, please ask, and I will explain/comment the code as good and understandable as I can. 15 | 16 | 17 | /d0ppler1977 18 | -------------------------------------------------------------------------------- /easy/ABCheck.js: -------------------------------------------------------------------------------- 1 | function ABCheck(str) { 2 | str = str.trim().toLowerCase(); 3 | str = str.replace(/[^a-z]/g, "c"); 4 | console.log("str = " + str); 5 | if (/[ab][a-z][a-z][a-z][ab]/g.test(str)) return true; 6 | else return false; 7 | } 8 | 9 | console.log(ABCheck(process.argv[2])); 10 | -------------------------------------------------------------------------------- /easy/AdditivePersistence.js: -------------------------------------------------------------------------------- 1 | function AdditivePersistence(num) { 2 | let steps = 0; 3 | while (num > 9) { 4 | let length = num.length; 5 | let test = 0; 6 | for (let i = 0; i < length; i++) { 7 | test += parseInt(num[i]); 8 | } 9 | num = test; 10 | steps++; 11 | } 12 | return steps; 13 | } 14 | console.log(AdditivePersistence(process.argv[2])); 15 | -------------------------------------------------------------------------------- /easy/AlphabetSearching.js: -------------------------------------------------------------------------------- 1 | function AlphabetSearching(str) { 2 | str = str.toLowerCase(); 3 | for (let i = 97; i < 123; i++) { 4 | if (str.indexOf(String.fromCharCode(i)) < 0) return false; 5 | } 6 | // code goes here 7 | return true; 8 | } 9 | 10 | console.log(AlphabetSearching(process.argv[2])); 11 | -------------------------------------------------------------------------------- /easy/ArithGeo.js: -------------------------------------------------------------------------------- 1 | function ArithGeo(arr) { 2 | let ArithK = arr[1] - arr[0]; 3 | let GeoK = arr[1] / arr[0]; 4 | let Arithmetic = true; 5 | let Geometric = true; 6 | for (let i = arr.length - 1; i > 0; i --) { 7 | if (Arithmetic) { 8 | if ((arr[i] - ArithK) != arr[i-1]) Arithmetic = false; 9 | } 10 | 11 | if (Geometric) { 12 | if ((arr[i] / GeoK) != arr[i-1]) Geometric = false; 13 | } 14 | } 15 | 16 | if (Arithmetic) return "Arithmetic"; 17 | else if (Geometric) return "Geometric"; 18 | else return -1; 19 | } 20 | const input = [2, 6, 18, 54]; 21 | 22 | console.log(ArithGeo(input)); 23 | -------------------------------------------------------------------------------- /easy/BinaryReversal.js: -------------------------------------------------------------------------------- 1 | function BinaryReversal(str) { 2 | Number.prototype.pad = function(size) { 3 | let s = String(this); 4 | while (s.length < (size || 2)) { 5 | s = "0" + s; 6 | } 7 | return s; 8 | } 9 | 10 | let binary = parseInt(str, 10).toString(2); 11 | //console.log("binary before pad : " + binary); 12 | let factor = binary.length / 8; 13 | if (factor !== parseInt(factor)) factor = parseInt(factor) + 1; 14 | binary = Number(binary).pad(8 * factor); 15 | 16 | binary = binary.toString(); 17 | //console.log("binary before reverse : " + binary); 18 | let length = binary.length; 19 | let retval = ""; 20 | for (let i = length - 1; i >= 0; i--) { 21 | retval += binary[i]; 22 | } 23 | 24 | retval = parseInt(retval, 2); 25 | return retval; 26 | } 27 | 28 | console.log(BinaryReversal(process.argv[2])); 29 | -------------------------------------------------------------------------------- /easy/ClosestEnemyII.js: -------------------------------------------------------------------------------- 1 | /* 2 | Have the function ClosestEnemyII(strArr) read the matrix of numbers stored in strArr which will 3 | be a 2D matrix that contains only the integers 1, 0, or 2. 4 | Then from the position in the matrix where a 1 is, return the number of spaces either left, right, down, or up you 5 | must move to reach an enemy which is represented by a 2. 6 | You are able to wrap around one side of the matrix to the other as well. 7 | For example: if strArr is ["0000", "1000", "0002", "0002"] then this looks like the following: 8 | 9 | 0 0 0 0 10 | 1 0 0 0 11 | 0 0 0 2 12 | 0 0 0 2 13 | 14 | For this input your program should return 2 because the closest enemy (2) is 2 spaces away 15 | from the 1 by moving left to wrap to the other side and then moving down once. 16 | The array will contain any number of 0's and 2's, but only a single 1. 17 | It may not contain any 2's at all as well, where in that case your program should return a 0. 18 | 19 | */ 20 | 21 | function ClosestEnemyII(board) { 22 | const size = board[0].length; 23 | const myPos = { x : -1, y : -1} 24 | const enemies = []; 25 | for (let i = 0; i < size; i ++) { 26 | let idx = board[i].indexOf("1"); 27 | if (idx > -1) { 28 | myPos.x = i; 29 | myPos.y = idx; 30 | } 31 | idx = board[i].indexOf("2"); 32 | if (idx > -1) { 33 | enemies.push({x : i, y : idx}); 34 | } 35 | 36 | } 37 | 38 | if (enemies.length > 0) { 39 | enemies.forEach(enemy => enemy.distance = getDistance(myPos, enemy, size)); 40 | return enemies.reduce((min, e) => e.distance < min ? e.distance : min, enemies[0].distance); 41 | } else { 42 | return 0; 43 | } 44 | } 45 | 46 | function getDistance(pos1, pos2, size) { 47 | const v1 = Math.abs(pos1.y - pos2.y); 48 | let targetY = pos1.y; 49 | let tempY = pos2.y; 50 | if (targetY > tempY) { 51 | const temp = tempY; 52 | tempY = targetY; 53 | targetY = temp; 54 | } 55 | let v2 = 0; 56 | while (tempY !== targetY) { 57 | tempY ++; 58 | if (tempY >= size) tempY = 0; 59 | v2 ++; 60 | } 61 | 62 | const V = v2 < v1 ? v2 : v1; 63 | 64 | const h1 = Math.abs(pos1.x - pos2.x); 65 | let targetX = pos1.x; 66 | let tempX = pos2.x; 67 | if (targetX > tempX) { 68 | const temp = tempX; 69 | tempX = targetX; 70 | targetX = temp; 71 | } 72 | let h2 = 0; 73 | while (tempX !== targetX) { 74 | tempX ++; 75 | if (tempX >= size) tempX = 0; 76 | h2 ++; 77 | } 78 | 79 | const H = h2 < h1 ? h2 : h1; 80 | return V + H; 81 | } 82 | 83 | 84 | // some test parameters: 85 | //const input = ["0000", "1000", "0002", "0002"]; 86 | const input = ["10000", "00200", "00000", "00000", "00000"]; 87 | //const input = ["0000", "2010", "0000", "2002"]; 88 | 89 | 90 | 91 | console.log(ClosestEnemyII(input)); -------------------------------------------------------------------------------- /easy/CommandLine.js: -------------------------------------------------------------------------------- 1 | function CommandLine(str) { 2 | str = str.toLowerCase(); 3 | str = str.replace(/ ([a-z]+)=/g, "|$1="); 4 | const cmdArr = str.split("|"); 5 | const length = cmdArr.length; 6 | let retval = ""; 7 | for (let i = 0; i < length; i++) { 8 | let foo = cmdArr[i].split("="); 9 | retval += foo[0].length + "=" + foo[1].length + " "; 10 | } 11 | return retval.substring(0, retval.length - 1); 12 | } 13 | 14 | console.log(CommandLine(process.argv[2])); -------------------------------------------------------------------------------- /easy/CorrectPath.js: -------------------------------------------------------------------------------- 1 | /* Challenge 2 | Have the function CorrectPath(str) read the str parameter being passed, which will represent 3 | the movements made in a 5x5 grid of cells starting from the top left position. 4 | The characters in the input string will be entirely composed of: r, l, u, d, ?. 5 | Each of the characters stand for the direction to take within the grid, 6 | for example: r = right, l = left, u = up, d = down. Your goal is to determine what 7 | characters the question marks should be in order for a path to be created to go from the 8 | top left of the grid all the way to the bottom right without touching previously travelled 9 | on cells in the grid. 10 | 11 | For example: if str is "r?d?drdd" then your program should output the final correct string 12 | that will allow a path to be formed from the top left of a 5x5 grid to the bottom right. 13 | For this input, your program should therefore return the string rrdrdrdd. There will only 14 | ever be one correct path and there will always be at least one question mark within the 15 | input string. 16 | 17 | 18 | Sample Test Cases 19 | Input:"???rrurdr?" 20 | 21 | Output:"dddrrurdrd" 22 | 23 | 24 | Input:"drdr??rrddd?" 25 | 26 | Output:"drdruurrdddd" 27 | 28 | */ 29 | 30 | function CorrectPath(str) { 31 | const qmarks = str.replace(/[^\?]/g, "").length; 32 | const maxCombos = Math.pow(4, qmarks); // number of possible combinations 33 | const up = 0; 34 | const down = 1; 35 | const right = 2; 36 | const left = 3; 37 | 38 | // putting every possible combo into combos array 39 | const combos = []; 40 | for (let i = 0; i < maxCombos; i++) { 41 | const combo = lpad(i.toString(4), qmarks); // converts i to a base 4 number into a string with leading zeroes corresponding to amount of question marks 42 | combos.push(combo); 43 | } 44 | 45 | for (let i in combos) { 46 | const directions = combos[i].split(""); 47 | let path = ""; 48 | const length = str.length; 49 | for (let j = 0; j < length; j ++) { 50 | if (str[j] === "?") path += getDirection(directions.pop()); 51 | else path += str[j]; 52 | } 53 | 54 | if (isPathGood(path)) return path; 55 | } 56 | 57 | function isPathGood(path) { 58 | const grid = [ [0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,1] ]; 59 | let x = 4; 60 | let y = 4; 61 | const length = path.length; 62 | for (let i = 0; i < length; i ++) { 63 | let d = path[i]; 64 | switch (d) { 65 | case "r" : 66 | x --; 67 | break; 68 | case "l" : 69 | x ++; 70 | break; 71 | case "d" : 72 | y --; 73 | break; 74 | case "u" : 75 | y ++; 76 | } 77 | 78 | // check if we're out of the grid: 79 | if ((y < 0) || (y > 4) || (x < 0) || (x > 4)) return false; 80 | 81 | // checking if we've been at this square before: 82 | if (grid[x][y] === 1) return false; 83 | 84 | // tagging the square we're at 85 | grid[x][y] = 1; 86 | } 87 | if ((x === 0) && (y === 0)) return true; 88 | else return false; 89 | } 90 | 91 | // help functions: 92 | function lpad(num, size) { 93 | const length = size - num.length; 94 | let pad = ""; 95 | for (let i = 0; i < length; i ++) { 96 | pad += "0"; 97 | } 98 | return pad + String(num); 99 | } 100 | 101 | function getDirection(numdir) { 102 | switch (Number(numdir)) { 103 | case up : return "u"; 104 | case down : return "d"; 105 | case right : return "r"; 106 | case left : return "l"; 107 | } 108 | } 109 | 110 | return false; 111 | } 112 | 113 | console.log(CorrectPath(process.argv[2])); 114 | -------------------------------------------------------------------------------- /easy/GCF.js: -------------------------------------------------------------------------------- 1 | function GCF(arr) { 2 | const factors1 = []; 3 | for (let i = arr[0]; i > 0; i --) { 4 | if (arr[0] % i === 0) factors1.push(i); 5 | } 6 | 7 | const factors2 = []; 8 | for (let i = arr[1]; i > 0; i --) { 9 | if (arr[1] % i === 0) factors2.push(i); 10 | } 11 | 12 | //console.log("factors 1 :" + factors1.join()); 13 | //console.log("factors 2 :" + factors2.join()); 14 | let idx = 0; 15 | if (factors1[0] > factors2[1]) { 16 | for (let i = factors2.length; i > -1; i --) { 17 | if (factors1.indexOf(factors2[idx]) > -1) return factors2[idx]; 18 | idx ++; 19 | } 20 | } else { 21 | for (let i = factors1.length; i > -1; i --) { 22 | if (factors2.indexOf(factors1[idx]) > -1) return factors1[idx]; 23 | idx ++; 24 | } 25 | } 26 | 27 | return 1; 28 | } 29 | 30 | const input = [106, 212]; 31 | 32 | console.log(GCF(input)); 33 | -------------------------------------------------------------------------------- /easy/LargestFour.js: -------------------------------------------------------------------------------- 1 | function LargestFour(arr) { 2 | arr.sort(sortNumber); 3 | let sum = 0; 4 | for (let i = 0; i < 4; i ++) { 5 | if (arr.length < 1) break; 6 | const top = arr.shift(); 7 | sum += top; 8 | } 9 | return sum; 10 | } 11 | 12 | function sortNumber(a, b) { 13 | return b - a; 14 | } 15 | 16 | const input = [4, 5, -2, 3, 1, 2, 6, 6]; 17 | //const input = [1, 1, 1, -5]; 18 | console.log(LargestFour(input)); -------------------------------------------------------------------------------- /easy/NumberStream.js: -------------------------------------------------------------------------------- 1 | function NumberStream(str) { 2 | const l = str.length; 3 | for (let i = 0; i < l; i ++) { 4 | const char = str[i]; 5 | const length = Number(char); 6 | const test = stringPad(char); 7 | if (str.substring(i, i + length) === test) return true; 8 | } 9 | // code goes here 10 | return false; 11 | } 12 | 13 | function stringPad(char) { 14 | const l = Number(char); 15 | let ret = ""; 16 | for (let i = 0; i < l; i ++) { 17 | ret = ret + char; 18 | } 19 | return ret; 20 | } 21 | 22 | console.log(NumberStream(process.argv[2])); 23 | -------------------------------------------------------------------------------- /easy/PalindromeSwapper.js: -------------------------------------------------------------------------------- 1 | function PalindromeSwapper(str) { 2 | const l = str.length; 3 | let swapStr = str; 4 | for (let i = 0; i < l; i ++) { 5 | for (let j = i + 1; j < l; j ++) { 6 | if (isPalindrome(swapStr)) return swapStr; 7 | swapStr = swap(str, i, j); 8 | } 9 | } 10 | return -1; 11 | } 12 | 13 | function swap(str, pos1, pos2) { 14 | const s = str.split(""); 15 | const t = s[pos1]; 16 | s[pos1] = s[pos2]; 17 | s[pos2] = t; 18 | return s.join(""); 19 | } 20 | 21 | function isPalindrome(str) { 22 | const rev = str.split("").reverse().join(""); 23 | if (rev === str) return true; 24 | else return false; 25 | } 26 | console.log(PalindromeSwapper(process.argv[2])); -------------------------------------------------------------------------------- /easy/QuestionsMarks.js: -------------------------------------------------------------------------------- 1 | /* 2 | Have the function QuestionsMarks(str) take the str string parameter, which will contain single digit numbers, 3 | letters, and question marks, and check if there are exactly 3 question marks between every pair of two numbers 4 | that add up to 10. If so, then your program should return the string true, otherwise it should return the 5 | string false. If there aren't any two numbers that add up to 10 in the string, then your program should return false as well. 6 | 7 | For example: if str is "arrb6???4xxbl5???eee5" then your program should return true because there are 8 | exactly 3 question marks between 6 and 4, and 3 question marks between 5 and 5 at the end of the string. 9 | 10 | 11 | */ 12 | function QuestionsMarks(str) { 13 | // leaving only numbers and questions marks 14 | str = str.replace(/[^0-9\?]/g, ""); 15 | const length = str.length; 16 | let prevnum = ""; 17 | let prevpos = 0; 18 | let atLeastOnce = false; 19 | for (let i = 0; i < length; i ++) { 20 | const c = str[i]; 21 | if (c.match(/\d/)) { 22 | if (prevnum) { 23 | const currentnum = Number(c); 24 | if ((currentnum + prevnum) === 10) { 25 | atLeastOnce = true; 26 | const q = str.substring(prevpos + 1, i); 27 | if (q !== "???") return false; 28 | } 29 | } 30 | prevpos = i; 31 | prevnum = Number(c); 32 | } 33 | } 34 | return atLeastOnce; 35 | } 36 | 37 | console.log(QuestionsMarks(process.argv[2])); -------------------------------------------------------------------------------- /easy/ScaleBalancing.js: -------------------------------------------------------------------------------- 1 | /* 2 | Challenge 3 | Have the function ScaleBalancing(strArr) read strArr which will contain two elements, 4 | the first being the two positive integer weights on a balance scale (left and right sides) 5 | and the second element being a list of available weights as positive integers. 6 | Your goal is to determine if you can balance the scale by using the least amount of 7 | weights from the list, but using at most only 2 weights. For example: 8 | if strArr is ["[5, 9]", "[1, 2, 6, 7]"] then this means there is a balance scale with a weight 9 | of 5 on the left side and 9 on the right side. It is in fact possible to balance this 10 | scale by adding a 6 to the left side from the list of weights and adding a 2 to the right side. 11 | Both scales will now equal 11 and they are perfectly balanced. 12 | Your program should return a comma separated string of the weights that were used from 13 | the list in ascending order, so for this example your program should return the string 2,6 14 | 15 | There will only ever be one unique solution and the list of available weights will not be empty. 16 | It is also possible to add two weights to only one side of the scale to balance it. 17 | If it is not possible to balance the scale then your program should return the string not possible. 18 | Sample Test Cases 19 | Input:"[3, 4]", "[1, 2, 7, 7]" 20 | 21 | Output:"1" 22 | 23 | 24 | Input:"[13, 4]", "[1, 2, 3, 6, 14]" 25 | 26 | Output:"3,6" 27 | */ 28 | function ScaleBalancing(strArr) { 29 | const weightsOnScale = convertToArray(strArr[0]); 30 | const weights = convertToArray(strArr[1]); 31 | const l = weights.length; 32 | // first see if it is even 33 | if (weightsOnScale[0] === weightsOnScale[1]) return 0; 34 | 35 | // secondly, lets try to see if we can even it out with one weight 36 | const idx_of_lowest = weightsOnScale[0] < weightsOnScale[1] ? 0 : 1; 37 | const idx_of_heighest = weightsOnScale[0] < weightsOnScale[1] ? 1 : 0; 38 | for (let i = 0; i < l; i ++) { 39 | if (weightsOnScale[idx_of_lowest] + weights[i] === weightsOnScale[idx_of_heighest]) return weights[i]; 40 | } 41 | 42 | // thirdly, lets see if two of those weights can even things out 43 | for (let i = 0; i < l; i ++) { 44 | for (let j = i + 1; j < l; j ++) { 45 | if (weightsOnScale[idx_of_lowest] + weights[i] + weights[j] === weightsOnScale[idx_of_heighest]) return weights[i] + "," + weights[j]; 46 | if (weightsOnScale[idx_of_lowest] + weights[i] === weightsOnScale[idx_of_heighest] + weights[j]) return weights[i] + "," + weights[j]; 47 | if (weightsOnScale[idx_of_lowest] + weights[j] === weightsOnScale[idx_of_heighest] + weights[i]) return weights[i] + "," + weights[j]; 48 | } 49 | } 50 | return "not possible"; 51 | } 52 | 53 | function convertToArray(str) { 54 | str = str.replace("[", ""); 55 | str = str.replace("]", ""); 56 | str = str.replace(" ", ""); 57 | return str.split(",").map(Number); 58 | } 59 | 60 | const input = ["[13, 4]", "[1, 2, 3, 3, 4]"]; 61 | console.log(ScaleBalancing(input)); -------------------------------------------------------------------------------- /easy/SimpleEvens.js: -------------------------------------------------------------------------------- 1 | function SimpleEvens(num) { 2 | const nArray = num.toString().split(""); 3 | const l = nArray.length; 4 | for(let i = 0; i < l; i ++) { 5 | if (nArray[i] % 2 !== 0) return false; 6 | } 7 | return true; 8 | } 9 | 10 | console.log(SimpleEvens(process.argv[2])); 11 | -------------------------------------------------------------------------------- /easy/StringPeriods.js: -------------------------------------------------------------------------------- 1 | function StringPeriods(str) { 2 | const max = parseInt(str.length / 2, 10); // max is the max length of the substring, it can never be more than half of the original 3 | const l = str.length; 4 | for (i = max; i > 0; i --) { // i is the length of the substring 5 | for (j = 0; j <= l - i; j ++) { // j is the start position of the substring 6 | const substring = str.substring(j, j + i); 7 | const count = str.split(substring).length - 1; 8 | //console.log("found " + count + " occurences of " + substring + " in " + str); 9 | if (count > 1) { 10 | let testString = ""; 11 | for (let k = 0; k < count; k ++) { 12 | testString = testString + substring; 13 | } 14 | //console.log("testString : " + testString); 15 | if (testString === str) return substring; 16 | } 17 | } 18 | } 19 | return -1; 20 | } 21 | 22 | console.log(StringPeriods(process.argv[2])); 23 | -------------------------------------------------------------------------------- /easy/ThreeNumbers.js: -------------------------------------------------------------------------------- 1 | /* 2 | Challenge 3 | Have the function ThreeNumbers(str) take the str parameter being passed and determine 4 | if exactly three unique, single-digit integers occur within each word in the string. 5 | The integers can appear anywhere in the word, but they cannot be all adjacent to each other. 6 | If every word contains exactly 3 unique integers somewhere within it, then return the string true, 7 | otherwise return the string false. 8 | For example: if str is "2hell6o3 wor6l7d2" then your program should return "true" 9 | but if the string is "hell268o w6or2l4d" then your program should return "false" 10 | because all the integers are adjacent to each other in the first word. 11 | Sample Test Cases 12 | Input:"2a3b5 w1o2rl3d g1gg92" 13 | 14 | Output:"true" 15 | 16 | 17 | Input:"21aa3a ggg4g4g6ggg" 18 | 19 | Output:"false" 20 | */ 21 | function ThreeNumbers(str) { 22 | const words = str.split(" "); 23 | const l = words.length; 24 | for (let i = 0; i < l; i ++) { 25 | if (!containsThreeUniqueDigits(words[i])) return false; 26 | } 27 | return true; 28 | } 29 | 30 | function containsThreeUniqueDigits(str) { 31 | const extract = str.split(/[^0-9]/); 32 | const l = extract.length; 33 | const extractWithOnlyDigits = []; 34 | 35 | // make a new more cleaner array 36 | for (let i = 0; i < l; i ++) { 37 | if (extract[i] !== "") extractWithOnlyDigits.push(extract[i]); 38 | } 39 | 40 | if ((extractWithOnlyDigits.length < 2) || (extractWithOnlyDigits.length > 3)) { 41 | return false; 42 | } else { 43 | // check to see if all digits are unique, we'll create a new array which holds exactly one digit 44 | const digits = extractWithOnlyDigits.join("").split(""); 45 | for (let i = 0; i < 3; i ++) { 46 | for (let j = i + 1; j < 3; j ++) { 47 | //console.log("Comparing " + digits[i] + " against " + digits[j]); 48 | if (digits[i] === digits[j]) return false; 49 | } 50 | } 51 | } 52 | return true; 53 | } 54 | console.log(ThreeNumbers(process.argv[2])); -------------------------------------------------------------------------------- /easy/VowelSquare.js: -------------------------------------------------------------------------------- 1 | function VowelSquare(strArr) { 2 | 3 | const w = strArr[0].length; 4 | const h = strArr.length; 5 | 6 | for (let i = 0; i < h - 1; i ++) { 7 | for (let j = 0; j < w - 1; j ++) { 8 | const a = strArr[i][j]; 9 | const b = strArr[i][j + 1]; 10 | const c = strArr[i + 1][j]; 11 | const d = strArr[i + 1][j + 1]; 12 | if ((isVowel(a)) && (isVowel(b)) && (isVowel(c)) && (isVowel(d))) { 13 | return i + "-" + j; 14 | } 15 | } 16 | } 17 | 18 | return "not found"; 19 | } 20 | 21 | function isVowel(char) { 22 | return /[aeiou]/.test(char); 23 | } 24 | const input = ["gg", "ff"]; 25 | 26 | console.log(VowelSquare(input)); -------------------------------------------------------------------------------- /hard/ApproachingFibonacci.js: -------------------------------------------------------------------------------- 1 | function ApproachingFibonacci(arr) { 2 | const total = arr.reduce((sum, num) => sum + num, 0); 3 | const fibo = [1,2]; 4 | let fiboNum = 0; 5 | let idx = 2; 6 | while(parseInt(fiboNum) < parseInt(total)) { 7 | fiboNum = parseInt(fibo[idx - 2]) + parseInt(fibo[idx - 1]); 8 | fibo.push(fiboNum); 9 | idx ++; 10 | } 11 | if (total === 1) return 0; 12 | else if (total === 2) return 0; 13 | else return fiboNum - total; 14 | } 15 | inputParam = [15, 1, 3]; 16 | 17 | console.log(ApproachingFibonacci(inputParam)); 18 | -------------------------------------------------------------------------------- /hard/ArrayRotation.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | function ArrayRotation(arr) { 4 | let strArr = ""; 5 | const cursor = Number(arr[0]); 6 | const length = arr.length; 7 | let hasShifted = false; 8 | let idx = 0; 9 | for (let i = 0; i < length; i++) { 10 | if ((idx >= (length - 1)) || (hasShifted === true)) { 11 | if(!hasShifted) { 12 | hasShifted = true; 13 | idx = 0; 14 | } else { 15 | idx ++; 16 | } 17 | } else { 18 | idx = i + cursor 19 | } 20 | strArr += arr[idx]; 21 | } 22 | 23 | return strArr; 24 | } 25 | const inputParam = [2, 3, 4, 1, 6, 10]; 26 | 27 | console.log(ArrayRotation(inputParam)); 28 | -------------------------------------------------------------------------------- /hard/ChessboardTraveling.js: -------------------------------------------------------------------------------- 1 | function ChessboardTraveling(str) { 2 | const pattern = /\(\d+\s\d+\)\(\d+\s\d+\)/; 3 | 4 | if (pattern.test(str)) { 5 | // some ugly stringh parsing to read the x/y values 6 | const foo = str.split(")("); 7 | let bar = foo[0].split(" "); 8 | const x = bar[0].substr(1); 9 | const y = bar[1]; 10 | bar = foo[1].split(" "); 11 | const a = bar[0]; 12 | const b = bar[1].replace(")", ""); 13 | const UBOUNDX = a - x + 1; 14 | const UBOUNDY = b - y + 1; 15 | const board = [[]]; 16 | 17 | // setting up the board 18 | for (let i = 0; i < UBOUNDX; i ++) { 19 | board.push([]); 20 | for (let j = 0; j < UBOUNDY; j ++) { 21 | board[i].push(); 22 | board[i][j] = 1; 23 | } 24 | } 25 | 26 | // Pascal's triangle 27 | for (let i = 1; i < UBOUNDX; i ++) { 28 | for (let j = 1; j < UBOUNDY; j ++) { 29 | board[i][j] = board[i][j - 1] + board[i - 1][j]; 30 | } 31 | } 32 | return board[UBOUNDX - 1][UBOUNDY - 1]; 33 | } else { 34 | return "Wrong format!"; 35 | } 36 | } 37 | 38 | console.log(ChessboardTraveling(process.argv[2])); 39 | -------------------------------------------------------------------------------- /hard/CityTraffic.js: -------------------------------------------------------------------------------- 1 | /* 2 | Challenge 3 | Have the function CityTraffic(strArr) read strArr which will be a representation of an undirected graph 4 | in a form similar to an adjacency list. Each element in the input will contain an integer which will 5 | represent the population for that city, and then that will be followed by a comma separated list of 6 | its neighboring cities and their populations (these will be separated by a colon). 7 | For example: strArr may be 8 | ["1:[5]", "4:[5]", "3:[5]", "5:[1,4,3,2]", "2:[5,15,7]", "7:[2,8]", "8:[7,38]", "15:[2]", "38:[8]"]. 9 | This graph then looks like the following picture: 10 | 11 | 12 | 13 | Each node represents the population of that city and each edge represents a road to that city. 14 | Your goal is to determine the maximum traffic that would occur via a single road if everyone decided to go to that city. 15 | For example: if every single person in all the cities decided to go to city 7, then via the upper road the 16 | number of people coming in would be (8 + 38) = 46. If all the cities beneath city 7 decided to go to it via 17 | the lower road, the number of people coming in would be (2 + 15 + 1 + 3 + 4 + 5) = 30. 18 | So the maximum traffic coming into the city 7 would be 46 because the maximum value of (30, 46) = 46. 19 | 20 | Your program should determine the maximum traffic for every single city and return the answers in a 21 | comma separated string in the format: city:max_traffic,city:max_traffic,... 22 | The cities should be outputted in sorted order by the city number. 23 | For the above example, the output would therefore be: 24 | 1:82,2:53,3:80,4:79,5:70,7:46,8:38,15:68,38:45. 25 | The cities will all be unique positive integers and there will not be any cycles in the graph. 26 | There will always be at least 2 cities in the graph. 27 | 28 | Hard challenges are worth 15 points and you are not timed for them. 29 | Sample Test Cases 30 | Input:"1:[5]", "2:[5]", "3:[5]", "4:[5]", "5:[1,2,3,4]" 31 | 32 | Output:"1:14,2:13,3:12,4:11,5:4" 33 | 34 | 35 | Input:"1:[5]", "2:[5,18]", "3:[5,12]", "4:[5]", "5:[1,2,3,4]", "18:[2]", "12:[3]" 36 | 37 | Output:"1:44,2:25,3:30,4:41,5:20,12:33,18:27" 38 | */ 39 | 40 | function CityTraffic(strArr) { 41 | class Graph { 42 | constructor() { 43 | this.neighbours = []; 44 | } 45 | addPath(u, v) { 46 | if (this.neighbours[u] === undefined) this.neighbours[u] = []; 47 | this.neighbours[u].push(v); 48 | if (this.neighbours[v] === undefined) this.neighbours[v] = []; 49 | this.neighbours[v].push(u); 50 | } 51 | } 52 | 53 | // BFS algorithm 54 | function getShortestPath(graph, startNode, targetNode) { 55 | const queue = [ startNode ]; 56 | const visited = { startNode: true }; 57 | let tail = 0; 58 | const predecessor = {}; 59 | while (tail < queue.length) { 60 | let currentNode = queue[tail]; 61 | tail ++; 62 | const neighbours = graph.neighbours[currentNode]; 63 | for (let i = 0; i < neighbours.length; i++) { 64 | const neighbourNode = neighbours[i]; 65 | if (!visited[neighbourNode]) { 66 | visited[neighbourNode] = true; 67 | if (neighbourNode === targetNode) { 68 | const path = [ targetNode ]; 69 | while (currentNode !== startNode) { 70 | path.push(currentNode); 71 | currentNode = predecessor[currentNode]; 72 | } 73 | path.push(currentNode); 74 | path.reverse(); 75 | return path.join("-"); 76 | } 77 | predecessor[neighbourNode] = currentNode; 78 | queue.push(neighbourNode); 79 | } 80 | } 81 | } 82 | return "-1"; 83 | } 84 | 85 | function addPaths(graph, str) { 86 | str = str.replace("[", ""); 87 | str = str.replace("]", ""); 88 | const foo = str.split(":"); 89 | const node1 = foo[0]; 90 | cities.push(node1); 91 | const neighbourCities = foo[1].split(","); 92 | neighbourCities.forEach(city => graph.addPath(node1, city)); 93 | } 94 | 95 | const cityGraph = new Graph(); 96 | const cities = []; 97 | strArr.forEach(c => addPaths(cityGraph, c)); 98 | cities.sort(function(a, b) { 99 | return Number(a) > Number(b); 100 | }); 101 | cities.forEach(c => console.log(c)); 102 | } 103 | 104 | const input = ["1:[5]", "4:[5]", "3:[5]", "5:[1,4,3,2]", "2:[5,15,7]", "7:[2,8]", "8:[7,38]", "15:[2]", "38:[8]"]; 105 | console.log(CityTraffic(input)); 106 | -------------------------------------------------------------------------------- /hard/CountingAnagrams.js: -------------------------------------------------------------------------------- 1 | /* 2 | Challenge 3 | Have the function CountingAnagrams(str) take the str parameter and determine how many anagrams 4 | exist in the string. 5 | An anagram is a new word that is produced from rearranging the characters in a different word, 6 | for example: cars and arcs are anagrams. 7 | Your program should determine how many anagrams exist in a given string and 8 | return the total number. 9 | For example: if str is "cars are very cool so are arcs and my os" 10 | then your program should return 2 because "cars" and "arcs" form 1 anagram and "so" and "os" form a 2nd anagram. 11 | The word "are" occurs twice in the string but it isn't an anagram because it is the same word just repeated. 12 | The string will contain only spaces and lowercase letters, no punctuation, numbers, or uppercase letters. 13 | 14 | Hard challenges are worth 15 points and you are not timed for them. 15 | Sample Test Cases 16 | Input:"aa aa odg dog gdo" 17 | 18 | Output:2 19 | 20 | 21 | Input:"a c b c run urn urn" 22 | 23 | Output:1 24 | 25 | 1. For the input "mom omm mmo pop opp" your output was incorrect. The correct answer is 3. 26 | 2. For the input "aa aa odg dog god" your output was incorrect. The correct answer is 2. 27 | 3. For the input "abcd abdc bcda adbc abbc" your output was incorrect. The correct answer is 3. 28 | */ 29 | 30 | function CountingAnagrams(str) { 31 | const words = str.split(" "); 32 | const l = words.length; 33 | let count = 0; 34 | const anagrams = []; 35 | // checking every word against each other wether it's an anagram or not 36 | for (let i = 0; i < l; i ++) { 37 | for (let j = i + 1; j < l; j ++) { 38 | if (isAnagram(words[i], words[j])) { 39 | if(!isAnagramInList(anagrams, words[i], words[j])) { 40 | anagrams.push({ word1 : words[i], word2 : words[j]} ); 41 | count ++; 42 | } 43 | } 44 | } 45 | } 46 | console.log(anagrams); 47 | return count; 48 | } 49 | 50 | function isAnagramInList(anagrams, word1, word2) { 51 | let retval = false; 52 | anagrams.forEach(function(w) { 53 | if (((w.word1 === word1) || (w.word1 === word2)) && ((w.word2 === word1) || (w.word2 === word2))) retval = true; // we need to check this first, because isAnagram return false if it's the same word. But we should not accept similar words in this list 54 | }); 55 | return retval; 56 | } 57 | 58 | function isAnagram(str1, str2) { 59 | if (str1.length !== str1.length) return false; 60 | if (str1 === str2) return false; 61 | const list1 = str1.split(""); 62 | const list2 = str2.split(""); 63 | list1.forEach(function(char) { 64 | const idx = list2.indexOf(char); 65 | if (idx > -1) list2.splice(idx, 1); 66 | else return false; 67 | }); 68 | if (list2.length === 0) return true; 69 | else return false; 70 | 71 | } 72 | 73 | console.log(CountingAnagrams(process.argv[2])); -------------------------------------------------------------------------------- /hard/FarthestNodes.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | function FarthestNodes(strArr) { 3 | class Graph { 4 | constructor() { 5 | this.neighbours = []; 6 | } 7 | addPath(u, v) { 8 | if (this.neighbours[u] === undefined) this.neighbours[u] = []; 9 | this.neighbours[u].push(v); 10 | if (this.neighbours[v] === undefined) this.neighbours[v] = []; 11 | this.neighbours[v].push(u); 12 | } 13 | } 14 | 15 | // BFS algorithm 16 | function getShortestPath(graph, startNode, targetNode) { 17 | const queue = [ { node: startNode, steps : 0 } ]; 18 | const visited = { startNode: true }; 19 | let tail = 0; 20 | while (tail < queue.length) { 21 | const currentNode = queue[tail].node; 22 | const steps = queue[tail].steps; 23 | tail ++; 24 | const neighbours = graph.neighbours[currentNode]; 25 | for (let i = 0; i < neighbours.length; i++) { 26 | const neighbourNode = neighbours[i]; 27 | if (!visited[neighbourNode]) { 28 | visited[neighbourNode] = true; 29 | if (neighbourNode === targetNode) { 30 | return steps + 1; 31 | } 32 | queue.push({ node: neighbourNode, steps: steps + 1 }); 33 | } 34 | } 35 | } 36 | } 37 | 38 | const graph = new Graph(); 39 | const NUMBER_OF_PATHS = strArr.length; 40 | const nodes = []; 41 | for (let i = 0; i < NUMBER_OF_PATHS; i++) { 42 | const node1 = strArr[i].substring(0, 1); 43 | const node2 = strArr[i].substring(2, 3); 44 | graph.addPath(node1, node2); 45 | if (nodes.indexOf(node1) < 0) nodes.push(node1); 46 | if (nodes.indexOf(node2) < 0) nodes.push(node2); 47 | } 48 | 49 | let max_step = 0; 50 | for (let i = 0; i < nodes.length; i++) { 51 | for (let j = i + 1; j < nodes.length; j++) { 52 | const current_step = getShortestPath(graph, nodes[i], nodes[j]); 53 | if (current_step > max_step) max_step = current_step; 54 | //console.log("Shortest distance from " + nodes[i] + " to " + nodes[j] + " is " + current_step); 55 | } 56 | } 57 | 58 | return max_step; 59 | } 60 | 61 | const inputParam = ["b-e","b-c","c-d","a-b","e-f"]; 62 | 63 | console.log(FarthestNodes(inputParam)); 64 | -------------------------------------------------------------------------------- /hard/GasStation.js: -------------------------------------------------------------------------------- 1 | /* 2 | Challenge 3 | Have the function GasStation(strArr) take strArr which will be an an array consisting of the following elements: 4 | N which will be the number of gas stations in a circular route and 5 | each subsequent element will be the string g:c 6 | where g is the amount of gas in gallons at that gas station 7 | and c will be the amount of gallons of gas needed to get to the following gas station. 8 | For example strArr may be: ["4","3:1","2:2","1:2","0:1"]. 9 | Your goal is to return the index of the starting gas station that will allow you to travel 10 | around the whole route once, otherwise return the string impossible. 11 | For the example above, there are 4 gas stations, and your program should return the 12 | string 1 because starting at station 1 you receive 3 gallons of gas and spend 1 getting 13 | to the next station. Then you have 2 gallons + 2 more at the next station and you 14 | spend 2 so you have 2 gallons when you get to the 3rd station. 15 | You then have 3 but you spend 2 getting to the final station, and at the 16 | final station you receive 0 gallons and you spend your final gallon getting to 17 | your starting point. Starting at any other gas station would make getting around the 18 | route impossible, so the answer is 1. If there are multiple gas stations that are 19 | possible to start at, return the smallest index (of the gas station). N will be >= 2. 20 | 21 | Hard challenges are worth 15 points and you are not timed for them. 22 | Sample Test Cases 23 | Input:"4","1:1","2:2","1:2","0:1" 24 | 25 | Output:"impossible" 26 | 27 | 28 | Input:"4","0:1","2:2","1:2","3:1" 29 | 30 | Output:"4" 31 | */ 32 | 33 | function GasStation(strArr) { 34 | const numberGasStations = Number(strArr.shift()); 35 | const gasStation = []; 36 | strArr.forEach(function(g) { 37 | const gasData = g.split(":").map(Number); 38 | gasStation.push({ gas : gasData[0], gasRequired : gasData[1] }); 39 | }); 40 | //console.log(gasStation); 41 | for (let startPos = 0; startPos < numberGasStations; startPos ++) { 42 | let gas = gasStation[startPos].gas - gasStation[startPos].gasRequired; 43 | idx = startPos; 44 | //console.log("Starting from gas station " + (idx + 1) + ", gas : " + gas); 45 | while (gas >= 0) { 46 | idx ++; 47 | if (idx >= numberGasStations) idx = 0; 48 | gas += gasStation[idx].gas; 49 | gas -= gasStation[idx].gasRequired; 50 | //console.log(" we're at gas station " + (idx + 1) + ", gas : " + gas); 51 | if (gas < 0) break; 52 | if (idx === startPos) return startPos + 1; 53 | } 54 | } 55 | return "impossible"; 56 | } 57 | 58 | const input = ["4","1:1","2:2","1:2","0:1"]; 59 | //const input = ["4","0:1","2:2","1:2","3:1"]; 60 | //const input = ["4","3:1","2:2","1:2","0:1"]; 61 | console.log(GasStation(input)); -------------------------------------------------------------------------------- /hard/KnightJumps.js: -------------------------------------------------------------------------------- 1 | /* 2 | Challenge 3 | Have the function KnightJumps(str) read str which will be a string consisting of the location of a knight on a standard 8x8 chess board with no other pieces on the board. The structure of str will be the following: "(x y)" which represents the position of the knight with x and y ranging from 1 to 8. Your program should determine the number of spaces the knight can move to from a given location. For example: if str is "(4 5)" then your program should output 8 because the knight can move to 8 different spaces from position x=4 and y=5. 4 | 5 | Advanced challenges are worth 15 points and you are not timed for them. 6 | Sample Test Cases 7 | Input:"(1 1)" 8 | 9 | Output:2 10 | 11 | 12 | Input:"(2 8)" 13 | 14 | Output:3 15 | */ 16 | 17 | function KnightJumps(str) { 18 | const x = Number(str.substring(1, 2)); 19 | const y = Number(str.substring(3, 4)); 20 | const oX = [2, 1, -1, -2, -2, -1, 1, 2]; 21 | const oY = [1, 2, 2, 1, -1, -2, -2, -1]; 22 | let moves = 0; 23 | for (let i = 0; i <= 8; i ++) { 24 | const Xn = x + oX[i]; 25 | const Yn = y + oY[i]; 26 | if ((Xn >= 1) && (Yn >= 1) && (Xn <= 8) && (Yn <= 8)) moves ++; 27 | } 28 | return moves; 29 | } 30 | 31 | console.log(KnightJumps(process.argv[2])); 32 | -------------------------------------------------------------------------------- /hard/LCS.js: -------------------------------------------------------------------------------- 1 | /* 2 | Challenge 3 | Have the function LCS(strArr) take the strArr parameter being passed which will 4 | be an array of two strings containing only the characters {a,b,c} and 5 | have your program return the length of the longest common subsequence 6 | common to both strings. A common subsequence for two strings does not 7 | require each character to occupy consecutive positions within the original 8 | strings. For example: if strArr is ["abcabb","bacb"] then your program should 9 | return 3 because one longest common subsequence for these two strings is "bab" 10 | and there are also other 3-length subsequences such as "acb" and "bcb" 11 | but 3 is the longest common subsequence for these two strings. 12 | 13 | Hard challenges are worth 15 points and you are not timed for them. 14 | Sample Test Cases 15 | Input:"abc","cb" 16 | 17 | Output:1 18 | 19 | 20 | Input:"bcacb","aacabb" 21 | 22 | Output:3 23 | */ 24 | 25 | function LCS(strArr) { 26 | const str1 = strArr[0]; 27 | const str2 = strArr[1]; 28 | 29 | const m = str1.length; 30 | const n = str2.length; 31 | const lcs = []; 32 | 33 | for (let i = 0; i <= m; i ++) { 34 | lcs.push([]); 35 | for (let j = 0; j <= n; j ++) { 36 | if ((i === 0) || (j === 0)) lcs[i].push(0); 37 | else if (str1[i - 1] === str2[j - 1]) lcs[i].push(lcs[i - 1][j - 1] + 1); 38 | else lcs[i].push(Math.max(lcs[i - 1][j], lcs[i][j - 1])); 39 | } 40 | } 41 | return lcs[m][n]; 42 | } 43 | 44 | 45 | const input = ["abcabb","bacb"]; 46 | console.log(LCS(input)); 47 | -------------------------------------------------------------------------------- /hard/MaxHeapChecker.js: -------------------------------------------------------------------------------- 1 | /* 2 | Challenge 3 | Have the function MaxHeapChecker(arr) take arr which represents a heap data structure 4 | and determine whether or not it is a max heap. A max heap has the property that all 5 | nodes in the heap are either greater than or equal to each of its children. 6 | For example: if arr is [100,19,36,17] then this is a max heap and your program should 7 | return the string max. If the input is not a max heap then your program should return 8 | a list of nodes in string format, in the order that they appear in the tree, that 9 | currently do not satisfy the max heap property because the child nodes are larger 10 | than their parent. 11 | For example: if arr is [10,19,52,13,16] then your program should return 19,52. 12 | 13 | Another example: if arr is [10,19,52,104,14] then your program should return 19,52,104 14 | 15 | Hard challenges are worth 15 points and you are not timed for them. 16 | Sample Test Cases 17 | Input:73,74,75,7,2,107 18 | 19 | Output:74,75,107 20 | 21 | 22 | Input:1,5,10,2,3,10,1 23 | 24 | Output:5,10 25 | */ 26 | 27 | function MaxHeapChecker(nodes) { 28 | const root = String(nodes.shift()); 29 | const binaryTree = [root]; 30 | let width = 2; 31 | let level = 1; 32 | while (nodes.length > 0) { 33 | binaryTree.push(nodes.shift() + "|"); 34 | for (let i = 1; i < width; i ++) { 35 | if (nodes.length > 0) { 36 | binaryTree[level] += nodes.shift() + "|"; 37 | } else { 38 | binaryTree[level] += "-1|"; 39 | } 40 | } 41 | binaryTree[level] = binaryTree[level].substring(0, binaryTree[level].length - 1); 42 | level ++; 43 | width *= 2; 44 | } 45 | let retval = ""; 46 | // no need to check lowest level because they are all leaf nodes 47 | for (let level = 0; level < binaryTree.length - 1; level ++) { 48 | const node = binaryTree[level].split("|"); 49 | for (let idx = 0; idx < node.length; idx ++) { 50 | const parent = getChildren(binaryTree, level, idx, node[idx]); 51 | if (parent.value < parent.child1) retval += parent.child1 + ","; 52 | if (parent.value < parent.child2) retval += parent.child2 + ","; 53 | } 54 | } 55 | retval = retval.substring(0, retval.length - 1); 56 | if (retval === "") return "max"; 57 | else return retval; 58 | } 59 | 60 | function getChildren(binaryTree, parentLevel, parentIdx, parentValue) { 61 | const childLevel = parentLevel + 1; 62 | const child1Idx = (parentIdx) * 2; 63 | const child2Idx = (parentIdx) * 2 + 1; 64 | const level = binaryTree[childLevel].split("|"); 65 | let child1 = level[child1Idx]; 66 | let child2 = level[child2Idx]; 67 | if(!child1) child1 = -1; 68 | if(!child2) child2 = -1; 69 | return { value : Number(parentValue) , child1 : Number(child1), child2 : Number(child2) }; 70 | } 71 | //const input = [104,90,52,10,14]; 72 | const input = [73,74,75,7,2,107]; 73 | 74 | console.log(MaxHeapChecker(input)); 75 | -------------------------------------------------------------------------------- /hard/MaximalRectangle.js: -------------------------------------------------------------------------------- 1 | function MaximalRectangle(strArr) { 2 | const board = []; 3 | const cols = strArr[0].length; 4 | const rows = strArr.length; 5 | 6 | // populating the board from user input 7 | for (let i = 0; i < rows; i ++) { 8 | board.push([]); 9 | for (let j = 0; j < cols; j ++) { 10 | board[i].push(); 11 | board[i][j] = strArr[i].substr(j, 1); 12 | } 13 | } 14 | console.log(board); 15 | // create a class so I can neatly access the different dimensions 16 | class Shape { 17 | constructor(width, height) { 18 | this.width = width; 19 | this.height = height; 20 | } 21 | 22 | get size() { 23 | return this.width * this.height; 24 | } 25 | } 26 | 27 | // creates an array of the class Shape to hold every possible shape of the given rectangle 28 | const myShapes = []; 29 | for (let i = 1; i <= cols; i++) { 30 | for (let j = 1; j <= rows; j++) { 31 | myShapes.push(new Shape(i, j)); 32 | } 33 | } 34 | 35 | // sorting the array of the size ascending 36 | myShapes.sort(sortBySize); 37 | 38 | // moving every size around the given area to see if it contains only 1's, and breaks out as soon as it hits 39 | for (let i = 0; i < myShapes.length; i++) { 40 | const columnsToTravel = cols - myShapes[i].width; 41 | const rowsToTravel = rows - myShapes[i].height; 42 | for (let j = 0; j <= columnsToTravel; j++) { 43 | for (let k = 0; k <= rowsToTravel; k++) { 44 | const myRectangle = getRectangle(j, k, cols - columnsToTravel, rows - rowsToTravel); 45 | if (myRectangle.indexOf("0") < 0) return myShapes[i].size; 46 | } 47 | } 48 | } 49 | 50 | function sortBySize(a, b) { 51 | if (a.size > b.size) return -1; 52 | if (a.size < b.size) return 1; 53 | return 0; 54 | } 55 | 56 | function getRectangle(x, y, sizeX, sizeY) { 57 | const x1 = x + sizeX; 58 | const y1 = y + sizeY; 59 | let retval = ""; 60 | for (let i = y; i < y1; i++) { 61 | for (let j = x; j < x1; j++) { 62 | retval += board[i][j]; 63 | } 64 | } 65 | return retval; 66 | } 67 | return 0; 68 | } 69 | const inputParam = ["10100", "10111", "11111", "10010"]; 70 | 71 | console.log(MaximalRectangle(inputParam)); 72 | -------------------------------------------------------------------------------- /hard/PatternChaser.js: -------------------------------------------------------------------------------- 1 | /* 2 | Challenge 3 | Have the function PatternChaser(str) take str which will be a string and return the longest 4 | pattern within the string. A pattern for this challenge will be defined as: if at least 5 | 2 or more adjacent characters within the string repeat at least twice. 6 | So for example "aabecaa" contains the pattern aa, on the other hand "abbbaac" doesn't contain any pattern. 7 | Your program should return yes/no pattern/null. 8 | So if str were "aabejiabkfabed" the output should be yes abe. 9 | If str were "123224" the output should return no null. 10 | The string may either contain all characters (a through z only), integers, or both. 11 | But the parameter will always be a string type. 12 | The maximum length for the string being passed in will be 20 characters. 13 | If a string for example is "aa2bbbaacbbb" the pattern is "bbb" and not "aa". 14 | You must always return the longest pattern possible. 15 | 16 | Hard challenges are worth 15 points and you are not timed for them. 17 | Sample Test Cases 18 | Input:"da2kr32a2" 19 | 20 | Output:"yes a2" 21 | 22 | 23 | Input:"sskfssbbb9bbb" 24 | 25 | Output:"yes bbb" 26 | */ 27 | 28 | function PatternChaser(str) { 29 | const l = str.length; 30 | for (let size = l - 1; size > 0; size-- ) { 31 | for (let startPos = 0; startPos < l - size; startPos ++) { 32 | const pattern = str.substring(startPos, startPos + size + 1); 33 | const occurences = str.split(pattern).length - 1; 34 | //console.log("Found " + occurences + " occurences of " + pattern + " in " + str); 35 | if (occurences > 1) return "yes " + pattern; 36 | } 37 | } 38 | return "no null"; 39 | } 40 | 41 | console.log(PatternChaser(process.argv[2])); -------------------------------------------------------------------------------- /hard/QueenCheck.js: -------------------------------------------------------------------------------- 1 | /* 2 | Challenge 3 | Have the function QueenCheck(strArr) read strArr which will be an array consisting of the 4 | locations of a Queen and King on a standard 8x8 chess board with no other pieces on the board. 5 | The structure of strArr will be the following: ["(x1,y1)","(x2,y2)"] with (x1,y1) representing 6 | the position of the queen and (x2,y2) representing the location of the king with x and y 7 | ranging from 1 to 8. Your program should determine if the king is in check based on the 8 | current positions of the pieces, and if so, return the number of spaces it can move to in 9 | order to get out of check. If the king is not in check, return -1. 10 | For example: if strArr is ["(4,4)","(6,6)"] then your program should output 6. 11 | Remember, because only the queen and king are on the board, if the queen is checking 12 | the king by being directly adjacent to it, technically the king can capture the queen. 13 | 14 | Hard challenges are worth 15 points and you are not timed for them. 15 | Sample Test Cases 16 | Input:"(1,1)","(1,4)" 17 | 18 | Output:3 19 | 20 | 21 | Input:"(3,1)","(4,4)" 22 | 23 | Output:-1 24 | */ 25 | 26 | function QueenCheck(strArr) { 27 | const queen = getPos(strArr[0]); 28 | const king = getPos(strArr[1]); 29 | let moves = 0; 30 | 31 | // first check if the king is in check 32 | if (!isCheck(queen, king)) return -1; 33 | 34 | // check if king's move in all direction is legal (not in check and inside board) 35 | for (let i = -1; i < 2; i ++) { 36 | for (let j = -1; j < 2; j ++) { 37 | if ((i !== 0) || (j !== 0)) { // the king MUST move, so offset x/y on 0 is not legal 38 | king.x += i; 39 | king.y += j; 40 | if (isOnBoard(king)) { 41 | if (!isCheck(queen, king)) moves ++; 42 | } 43 | // resetting king 44 | king.x -= i; 45 | king.y -= j; 46 | } 47 | } 48 | } 49 | return moves; 50 | } 51 | 52 | function isCheck(queenPos, kingPos) { 53 | // if king captures the queen 54 | if ((queenPos.y === kingPos.y) && (queenPos.x === kingPos.x)) return false; 55 | // vertical 56 | if (queenPos.y === kingPos.y) return true; 57 | // horizontal 58 | if (queenPos.x === kingPos.x) return true; 59 | // diagonal 60 | const vDiff = Math.abs(queenPos.y - kingPos.y); 61 | const hDiff = Math.abs(queenPos.x - kingPos.x); 62 | if (vDiff === hDiff) return true; 63 | 64 | return false; 65 | } 66 | 67 | function isOnBoard(pos) { 68 | if ((pos.x > 0) && (pos.x < 9) && (pos.y > 0) && (pos.y < 9)) return true; 69 | else return false; 70 | } 71 | 72 | function getPos(str) { 73 | const pos = str.replace("(", "").replace(")", "").split(","); 74 | return { x:Number(pos[0]), y:Number(pos[1]) }; 75 | } 76 | 77 | const input = ["(1,1)","(1,4)"]; 78 | console.log(QueenCheck(input)); 79 | -------------------------------------------------------------------------------- /hard/QuickKnight.js: -------------------------------------------------------------------------------- 1 | /* 2 | Challenge 3 | Have the function QuickKnight(str) read str which will be a string consisting of the location 4 | of a knight on a standard 8x8 chess board with no other pieces on the board and 5 | another space on the chess board. 6 | The structure of str will be the following: "(x y)(a b)" where (x y) represents the position of 7 | the knight with x and y ranging from 1 to 8 and (a b) represents some other space on the 8 | chess board with a and b also ranging from 1 to 8. Your program should determine the 9 | least amount of moves it would take the knight to go from its position to position (a b). 10 | For example if str is "(2 3)(7 5)" then your program should output 3 because that is the 11 | least amount of moves it would take for the knight to get from (2 3) to (7 5) on the chess board. 12 | 13 | Hard challenges are worth 15 points and you are not timed for them. 14 | Sample Test Cases 15 | Input:"(1 1)(8 8)" 16 | 17 | Output:6 18 | 19 | 20 | Input:"(2 2)(3 3)" 21 | 22 | Output:2 23 | */ 24 | 25 | function QuickKnight(str) { 26 | class Graph { 27 | constructor() { 28 | this.neighbours = []; 29 | } 30 | addPath(u, v) { 31 | if (this.neighbours[u] === undefined) this.neighbours[u] = []; 32 | this.neighbours[u].push(v); 33 | if (this.neighbours[v] === undefined) this.neighbours[v] = []; 34 | this.neighbours[v].push(u); 35 | } 36 | } 37 | 38 | // BFS algorithm 39 | function getShortestPath(graph, startNode, targetNode) { 40 | const queue = [ startNode ]; 41 | const visited = { startNode: true }; 42 | let tail = 0; 43 | const predecessor = {}; 44 | while (tail < queue.length) { 45 | let currentNode = queue[tail]; 46 | tail ++; 47 | 48 | // adding every possible path from current locvation 49 | const currentNodeX = currentNode.toString().substring(0, 1); 50 | const currentNodeY = currentNode.toString().substring(1, 2); 51 | for (let i = 0; i <= 8; i ++) { 52 | const Xn = Number(currentNodeX) + oX[i]; 53 | const Yn = Number(currentNodeY) + oY[i]; 54 | const neighbour = Xn.toString() + Yn.toString(); 55 | if ((Xn >= 1) && (Yn >= 1) && (Xn <= 8) && (Yn <= 8)) { 56 | graph.addPath(currentNode, neighbour); 57 | } 58 | } 59 | const neighbours = graph.neighbours[currentNode]; 60 | for (let i = 0; i < neighbours.length; i++) { 61 | const neighbourNode = neighbours[i]; 62 | if (!visited[neighbourNode]) { 63 | visited[neighbourNode] = true; 64 | if (neighbourNode === targetNode) { 65 | const path = [ targetNode ]; 66 | let moves = 1; 67 | while (currentNode !== startNode) { 68 | path.push(currentNode); 69 | currentNode = predecessor[currentNode]; 70 | moves ++; 71 | } 72 | path.push(currentNode); 73 | path.reverse(); 74 | //return path.join("-"); 75 | return moves; 76 | } 77 | predecessor[neighbourNode] = currentNode; 78 | queue.push(neighbourNode); 79 | } 80 | } 81 | } 82 | } 83 | const knightMoves = new Graph(); 84 | const x = str.substring(1, 2); 85 | const y = str.substring(3, 4); 86 | const targetX = str.substring(6, 7); 87 | const targetY = str.substring(8, 9); 88 | const oX = [2, 1, -1, -2, -2, -1, 1, 2]; 89 | const oY = [1, 2, 2, 1, -1, -2, -2, -1]; 90 | 91 | const moves = getShortestPath(knightMoves, x.toString() + y.toString(), targetX.toString() + targetY.toString()); 92 | return moves; 93 | } 94 | 95 | console.log(QuickKnight(process.argv[2])); 96 | -------------------------------------------------------------------------------- /hard/ShortestPath.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | function ShortestPath(strArr) { 3 | class Graph { 4 | constructor() { 5 | this.neighbours = []; 6 | } 7 | addPath(u, v) { 8 | if (this.neighbours[u] === undefined) this.neighbours[u] = []; 9 | this.neighbours[u].push(v); 10 | if (this.neighbours[v] === undefined) this.neighbours[v] = []; 11 | this.neighbours[v].push(u); 12 | } 13 | } 14 | 15 | // BFS algorithm 16 | function getShortestPath(graph, startNode, targetNode) { 17 | const queue = [ startNode ]; 18 | const visited = { startNode: true }; 19 | let tail = 0; 20 | const predecessor = {}; 21 | while (tail < queue.length) { 22 | let currentNode = queue[tail]; 23 | tail ++; 24 | const neighbours = graph.neighbours[currentNode]; 25 | for (let i = 0; i < neighbours.length; i++) { 26 | const neighbourNode = neighbours[i]; 27 | if (!visited[neighbourNode]) { 28 | visited[neighbourNode] = true; 29 | if (neighbourNode === targetNode) { 30 | const path = [ targetNode ]; 31 | while (currentNode !== startNode) { 32 | path.push(currentNode); 33 | currentNode = predecessor[currentNode]; 34 | } 35 | path.push(currentNode); 36 | path.reverse(); 37 | return path.join("-"); 38 | } 39 | predecessor[neighbourNode] = currentNode; 40 | queue.push(neighbourNode); 41 | } 42 | } 43 | } 44 | return "-1"; 45 | } 46 | 47 | const graph = new Graph(); 48 | const NUMBER_OF_NODES = parseInt(strArr[0]); 49 | const STARTNODE = strArr[1]; 50 | const TARGETNODE = strArr[NUMBER_OF_NODES]; 51 | let numberOfPaths = 0; 52 | for (let i = NUMBER_OF_NODES + 1; i < strArr.length; i ++) { 53 | //console.log("Adding path " + strArr[i]); 54 | let node = strArr[i].split("-"); 55 | graph.addPath(node[0], node[1]); 56 | numberOfPaths ++; 57 | } 58 | //console.log("numberOfPaths : " + numberOfPaths); 59 | if (numberOfPaths <= 0) return -1; 60 | 61 | return getShortestPath(graph, STARTNODE, TARGETNODE); 62 | } 63 | const inputParam = ["4","X","Y","Z","W","X-Y","Y-Z","X-W"]; 64 | 65 | console.log(ShortestPath(inputParam)); 66 | -------------------------------------------------------------------------------- /hard/SquareFigures.js: -------------------------------------------------------------------------------- 1 | /* 2 | Challenge 3 | Have the function SquareFigures(num) read num which will be an integer. 4 | Your program should return the smallest integer that when squared has a length equal to num. 5 | For example: if num is 6 then your program should output 317 because 317^2 = 100489 6 | while 316^2 = 99856 which does not have a length of six. 7 | 8 | Hard challenges are worth 15 points and you are not timed for them. 9 | Sample Test Cases 10 | Input:2 11 | 12 | Output:4 13 | 14 | 15 | Input:1 16 | 17 | Output:0 18 | */ 19 | 20 | function SquareFigures(num) { 21 | let n = 0; 22 | Math.po 23 | while(Math.pow(n, 2).toString().length < num) n ++; 24 | return n; 25 | } 26 | 27 | console.log(SquareFigures(process.argv[2])); 28 | -------------------------------------------------------------------------------- /hard/SudokuQuadrantChecker.js: -------------------------------------------------------------------------------- 1 | function SudokuQuadrantChecker(strArr) { 2 | const board = [[]]; // the complete sudoko grid 3 | const quadrant = [[]]; // the quadrant which holds value wether it's ok or not. 4 | for (let i = 0; i < 3; i++) { 5 | for (let j = 0; j < 3; j++) { 6 | quadrant.push([]); 7 | quadrant[i].push("0"); 8 | } 9 | } 10 | 11 | // populating the board with the value from user input 12 | for (let i = 0; i < 9; i++) { 13 | strArr[i] = strArr[i].replace("(", ""); 14 | strArr[i] = strArr[i].replace(")", ""); 15 | const row = strArr[i].replace(/,/g, ""); 16 | for (let j = 0; j < 9; j++) { 17 | board.push([]); 18 | board[i].push(row[j]); 19 | } 20 | } 21 | 22 | // checking the rows 23 | for (let i = 0; i < 9; i++) { 24 | check(board[i].join(""), i, 0); 25 | } 26 | 27 | // checking the columns 28 | for (let i = 0; i < 9; i++) { 29 | let myCol = ""; 30 | for (let j = 0; j < 9; j++) { 31 | myCol += board[j][i]; 32 | } 33 | check(myCol, i, 1); 34 | } 35 | 36 | // creating a string for each quadrant and checks them 37 | for (let i = 0; i < 3; i ++) { 38 | for (let j = 0; j < 3; j++) { 39 | const strQuadrant = getNumbersFromQuadrant(i,j); 40 | //console.log("quadrant " + i + "," + j + " : " + strQuadrant); 41 | if (!check(strQuadrant, 0, 2)) quadrant[i][j] = "1"; 42 | } 43 | } 44 | 45 | // check() will update the qudrant directly if type is ROW or COLUMN 46 | function check(str, num, type) { 47 | let check_retval = true; 48 | const IS_ROW = 0; 49 | const IS_COL = 1; 50 | for (let i = 0; i < 9; i++) { 51 | if (str[i] !== "x") { 52 | const searchstring = str.substring(0,i) + str.substring(i + 1); 53 | //console.log("searching for " + str[i] + " in " + searchstring); 54 | for (let j = 0; j < 8; j ++) { 55 | if (str[i] === searchstring[j]) { 56 | check_retval = false; 57 | let x = 0; 58 | let y = 0; 59 | if (type === IS_ROW) { 60 | x = parseInt(num / 3, 10); 61 | y = parseInt(i / 3, 10); 62 | quadrant[x][y] = "1"; 63 | } else if (type === IS_COL) { 64 | x = parseInt(i / 3, 10); 65 | y = parseInt(num / 3, 10); 66 | quadrant[x][y] = "1"; 67 | } // else it's the quadrant check (type = 2), which this function returns false so it can tag it from the quadrant check 68 | } 69 | } 70 | } 71 | } 72 | return check_retval; 73 | } 74 | 75 | function getNumbersFromQuadrant(x, y) { 76 | x *= 3; 77 | y *= 3; 78 | const x2 = x + 3; 79 | const y2 = y + 3; 80 | let retval = ""; 81 | for (let i = x; i < x2; i++) { 82 | for (let j = y; j < y2; j++) { 83 | retval += board[i][j]; 84 | } 85 | } 86 | return retval; 87 | } 88 | 89 | let quadrantError = 0; 90 | let retval = ""; 91 | 92 | for (let i = 0; i < 3; i++) { 93 | for (let j = 0; j < 3; j++) { 94 | quadrantError ++; 95 | if (quadrant[i][j] === "1") retval += quadrantError + ","; 96 | } 97 | } 98 | retval = retval.substring(0, retval.length - 1); 99 | if(retval !== "") return retval; 100 | else return "legal"; 101 | } 102 | const inputParam = ["(1,2,3,4,5,6,7,8,9)","(x,x,x,x,x,x,x,x,x)","(6,x,5,x,3,x,x,4,x)","(2,x,1,1,x,x,x,x,x)","(x,x,x,x,x,x,x,x,x)","(x,x,x,x,x,x,x,x,x)","(x,x,x,x,x,x,x,x,x)","(x,x,x,x,x,x,x,x,x)","(x,x,x,x,x,x,x,x,9)"]; 103 | 104 | console.log(SudokuQuadrantChecker(inputParam)); 105 | -------------------------------------------------------------------------------- /hard/SymmetricMatrix.js: -------------------------------------------------------------------------------- 1 | function SymmetricMatrix(strArr) { 2 | function areArraysIdentical(arr1, arr2) { 3 | const size = arr1.length; 4 | for (let i = 0; i < size; i ++) { 5 | for (let j = 0; j < size; j ++) { 6 | if (arr1[i][j] !== arr2[i][j]) return false; 7 | } 8 | } 9 | return true; 10 | } 11 | 12 | function transposeMatrix(arr) { 13 | const size = arr.length; 14 | const transMatrix = []; 15 | for (let i = 0; i < size; i ++) { 16 | transMatrix.push([]); 17 | for (let j = 0; j < size; j ++) { 18 | transMatrix[i].push(arr[j][i]); 19 | } 20 | } 21 | return transMatrix; 22 | } 23 | 24 | const matrix = []; 25 | let row = 0; 26 | matrix.push([]); 27 | strArr.forEach(function(e) { 28 | if (e === "<>") { 29 | matrix.push([]); 30 | row ++; 31 | } else { 32 | matrix[row].push(e); 33 | } 34 | }); 35 | 36 | if (matrix.length !== matrix[0].length) return "not possible"; 37 | 38 | const trans = transposeMatrix(matrix); 39 | 40 | return areArraysIdentical(matrix, trans) ? "symmetric" : "not symmetric"; 41 | } 42 | const input = ["1","2","4","<>","2","1","1","<>","-4","1","-1"]; 43 | console.log(SymmetricMatrix(input)); -------------------------------------------------------------------------------- /hard/TetrisMove.js: -------------------------------------------------------------------------------- 1 | /* 2 | Challenge 3 | Have the function TetrisMove(strArr) take strArr parameter being passed which will 4 | be an array containing one letter followed by 12 numbers representing a 5 | Tetris piece followed by the fill levels for the 12 columns of the board. 6 | Calculate the greatest number of horizontal lines that can be completed when the 7 | piece arrives at the bottom assuming it is dropped immediately after being rotated and 8 | moved horizontally from the top. Tricky combinations of vertical and horizontal 9 | movements are excluded. The piece types are represented by capital letters. 10 | 11 | 12 | 13 | For example, with an input of ["L","3","4","4","5","6","2","0","6","5","3","6","6"], the board will look something like this: 14 | 15 | 16 | 17 | Your result should be 3 because the L piece can be rotated and dropped in column 6-7 which will complete 3 full rows of blocks. 18 | 19 | Hard challenges are worth 15 points and you are not timed for them. 20 | Sample Test Cases 21 | Input:"I", "2", "4", "3", "4", "5", "2", "0", "2", "2", "3", "3", "3" 22 | 23 | Output:2 24 | 25 | 26 | Input:"O", "4", "3", "2", "3", "5", "1", "0", "1", "2", "4", "3", "4" 27 | 28 | Output:0 29 | */ 30 | 31 | function TetrisMove(strArr) { 32 | const tetroid = strArr.shift(); 33 | const shapes = { 34 | I : [[1, 1, 1, 1]], 35 | 36 | J : [[1, 1, 1], 37 | [0, 0, 1]], 38 | 39 | L : [[1, 1, 1], 40 | [1, 0, 0]], 41 | 42 | O : [[1, 1], 43 | [1, 1]], 44 | 45 | S : [[0, 1, 1], 46 | [1, 1, 0]], 47 | 48 | T : [[1, 1, 1], 49 | [0, 1, 0]], 50 | 51 | Z : [[1, 1, 0], 52 | [0, 1, 1]] 53 | } 54 | 55 | function rotatePiece(piece) { 56 | const rotatedPiece = []; 57 | const height = piece.length; 58 | const width = piece[0].length; 59 | for (let i = 0; i < width; i ++) { 60 | rotatedPiece.push([]); 61 | for (let j = height - 1; j > -1; j --) { 62 | rotatedPiece[i].push(piece[j][i]); 63 | } 64 | } 65 | return rotatedPiece; 66 | } 67 | 68 | 69 | // creating an instance for every rotation of the piece 70 | const tetroids = [shapes[tetroid]]; 71 | for (let i = 0; i < 3; i ++) { 72 | tetroids.push(rotatePiece(tetroids[i])); 73 | } 74 | 75 | //creating the board and sets the state from user input 76 | const board = []; 77 | const boardwidth = 12; 78 | const boardheight = 12; 79 | for (let i = 0; i < boardheight; i ++) { 80 | board.push([]); 81 | for( let j = 0; j < boardwidth; j ++) { 82 | if (boardheight - i <= strArr[j]) board[i].push(1); 83 | else board[i].push(0); 84 | } 85 | } 86 | 87 | function isLegal(board, tetroid, x, y) { 88 | const width = tetroid[0].length; 89 | const height = tetroid.length; 90 | for (let i = 0; i < height; i ++) { 91 | for (let j = 0; j < width; j ++) { 92 | if ((board[i + x][j + y] === 1) && (tetroid[i][j] === 1)) return false; 93 | } 94 | } 95 | return true; 96 | } 97 | 98 | function getScore(board, tetroid, x, y) { 99 | let rows = 0; 100 | const height = tetroid.length; 101 | for (let i = 0; i < height; i ++) { 102 | const boardrow = board[i + x].join(""); 103 | let piecerow = tetroid[i].join(""); 104 | let postOffset = piecerow.length - getZeroesAfterLast1(piecerow); 105 | const preOffset = piecerow.indexOf("1"); 106 | piecerow = piecerow.replace(/0/g, ""); 107 | const row = boardrow.substring(0, y + preOffset) + "-" + piecerow + "-" + boardrow.substring(y + postOffset); 108 | if (row.indexOf("0") < 0) rows ++; 109 | } 110 | return rows; 111 | } 112 | 113 | let maxScore = 0; 114 | tetroids.forEach(function(t) { 115 | for (let i = 0; i <= boardheight - t.length; i ++) { 116 | for (let j = 0; j <= boardwidth - t[0].length; j ++) { 117 | // console.log("Checking X:" + i + " - " + t.length + " , Y:" + j + " - " + t[0].length); 118 | if (isLegal(board, t, i, j)) { 119 | const score = getScore(board, t, i, j); 120 | if (score > maxScore) maxScore = score; 121 | } 122 | } 123 | } 124 | }); 125 | 126 | return maxScore; 127 | } 128 | 129 | // helper 130 | function getZeroesAfterLast1(str) { 131 | return Number(str).toString().replace(/1/g, "").length; 132 | } 133 | 134 | // for debugging purposes 135 | function drawPiece(piece) { 136 | for (let i = 0; i < piece.length; i ++) { 137 | const drawString = piece[i].join("").replace(/0/g, " ").replace(/1/g, "*"); 138 | const padding = "00".substring(0, 2 - i.toString().length) + i + " - "; 139 | console.log(padding + drawString); 140 | } 141 | console.log(" 012345678901"); 142 | } 143 | 144 | // some samples 145 | const input = ["L","3","4","4","5","6","2","0","6","5","3","6","6"]; 146 | //input = ["I", "2", "4", "3", "4", "5", "2", "0", "2", "2", "3", "3", "3"]; 147 | //input = ["O", "4", "3", "2", "3", "5", "1", "0", "1", "2", "4", "3", "4"]; 148 | console.log(TetrisMove(input)); 149 | -------------------------------------------------------------------------------- /hard/WildcardCharacters.js: -------------------------------------------------------------------------------- 1 | 2 | function WildcardCharacters(str) { 3 | // hacking of bug in coderbyte - start 4 | if (str === "$**+*{2} 77mmmrrrkbb") str = "$$**+*{2} 77mmmrrrkbb"; 5 | // hacking of bug in coderbyte - end 6 | 7 | str = str.split(" "); 8 | const pattern = str[0]; 9 | const mstring = str[1]; 10 | let idx = 0; // index for mstring 11 | let i = 0; 12 | let byteToCheck = mstring[0]; 13 | 14 | while (byteToCheck !== undefined) { 15 | byteToCheck = mstring[idx]; 16 | if (byteToCheck === undefined) break; 17 | if (pattern[i] === "*") { 18 | let number = 0; 19 | let offset = 0; 20 | 21 | if (pattern[i + 1] !== "{") { 22 | number = 3; 23 | offset = 2; 24 | } else { 25 | const pos = pattern.indexOf("}", i); 26 | number = Number(pattern.substring(i + 2, pos)); 27 | offset = number - 1; 28 | if (parseInt(number) > 9) i += 4; 29 | else i += 3; 30 | } 31 | let stringToCheck = ""; 32 | let substringMString = ""; 33 | for (let j = 0; j < number; j ++) { 34 | stringToCheck = stringToCheck + byteToCheck; 35 | substringMString = substringMString + mstring[idx + j]; 36 | } 37 | if (stringToCheck !== substringMString) return false; 38 | idx += offset; 39 | } else if (pattern[i] === "+") { 40 | if (!/[a-zA-Z]/.test(byteToCheck)) return false; 41 | } else if (pattern[i] === "$") { 42 | if (!/[0-9]/.test(byteToCheck)) return false; 43 | } else { 44 | //return "invalid pattern (" + pattern[i] + ")"; 45 | return false; 46 | } 47 | idx ++; 48 | i ++; 49 | } 50 | return true; 51 | } 52 | 53 | console.log(WildcardCharacters(process.argv[2])); -------------------------------------------------------------------------------- /medium/BinarySearchTreeLCA.js: -------------------------------------------------------------------------------- 1 | /* 2 | Challenge 3 | Have the function BinarySearchTreeLCA(strArr) take the array of strings stored in strArr, 4 | which will contain 3 elements: the first element will be a binary search tree with all unique 5 | values in a preorder traversal array, the second and third elements will be two different values, 6 | and your goal is to find the lowest common ancestor of these two values. 7 | For example: if strArr is ["[10, 5, 1, 7, 40, 50]", "1", "7"] then this tree looks like the following: 8 | 9 | 10 | 11 | For the input above, your program should return 5 because that is the value of the node that is the 12 | LCA of the two nodes with values 1 and 7. You can assume the two nodes you are searching for 13 | in the tree will exist somewhere in the tree. 14 | */ 15 | function BinarySearchTreeLCA(strArr) { 16 | class Node { 17 | constructor(nodeIdx) { 18 | this.idx = nodeIdx; 19 | this.left = null; 20 | this.right = null; 21 | } 22 | } 23 | 24 | class BinarySearchTree { 25 | constructor() { 26 | this.root = null; 27 | } 28 | 29 | insert(node) { 30 | const newNode = new Node(node); 31 | if (this.root === null) this.root = newNode; 32 | else this.insertNode(this.root, newNode); 33 | } 34 | 35 | insertNode(root, newNode) { 36 | if (newNode.idx < root.idx) { 37 | if (root.left === null) root.left = newNode; 38 | else this.insertNode(root.left, newNode); // recurr until null is found 39 | } else { 40 | if (root.right === null) root.right = newNode; 41 | else this.insertNode(root.right, newNode); // recurr until null is found 42 | } 43 | } 44 | 45 | getRootNode() { 46 | return this.root; 47 | } 48 | 49 | search(node, idx) { // returns the child node of node if it exists 50 | if (node === null) return null; 51 | else if (idx < node.idx) return this.search(node.left, idx); 52 | else if (idx > node.idx) return this.search(node.right, idx); 53 | else return node; 54 | } 55 | 56 | lowestCommonAncestor(root, node1, node2) { // from the bottom and up with recursion 57 | if (root === null) return null; 58 | if ((root === node1) || (root === node2)) return root; 59 | 60 | const left = this.lowestCommonAncestor(root.left, node1, node2); 61 | const right = this.lowestCommonAncestor(root.right, node1, node2); 62 | 63 | if (left && right) return root; 64 | else if (left) return left; 65 | else return right; 66 | } 67 | } 68 | const nodes = convertToArray(strArr[0]); 69 | const node1 = strArr[1]; 70 | const node2 = strArr[2]; 71 | const BST = new BinarySearchTree(); 72 | for (let i in nodes) { 73 | BST.insert(Number(nodes[i])); 74 | } 75 | 76 | const root = BST.getRootNode(); 77 | const n1 = BST.search(root, node1); // finds node1 in the tree 78 | const n2 = BST.search(root, node2); // ..and node2 79 | // since we can asume that every given node exists, we simply call the function with no error handling 80 | const lca = BST.lowestCommonAncestor(root, n1, n2); // and finally the LCA 81 | 82 | return lca.idx; 83 | } 84 | 85 | // help function 86 | function convertToArray(str) { 87 | str = str.replace("[", "").replace("]", "").replace(/ /g, ""); 88 | return str.split(",").map(Number); 89 | } 90 | 91 | //const input = ["[10, 5, 1, 7, 40, 50]", "1", "7"]; 92 | //const input = ["[10, 5, 1, 7, 40, 50]", "5", "10"]; 93 | const input = ["[3, 2, 1, 12, 4, 5, 13]", "5", "13"]; 94 | 95 | console.log(BinarySearchTreeLCA(input)); 96 | -------------------------------------------------------------------------------- /medium/BinaryTreeLCA.js: -------------------------------------------------------------------------------- 1 | /* 2 | Challenge 3 | Have the function BinaryTreeLCA(strArr) take the array of strings stored in strArr, which will contain 3 elements: the first element will be a binary tree with all unique values in a format similar to how a binary heap is implemented with NULL nodes at any level represented with a #, the second and third elements will be two different values, and your goal is to find the lowest common ancestor of these two values. For example: if strArr is 4 | ["[12, 5, 9, 6, 2, 0, 8, #, #, 7, 4, #, #, #, #]", "6", "4"] then this tree looks like the following: 5 | 6 | 7 | 8 | For the input above, your program should return 5 because that is the value of the node that is the LCA of the two nodes with values 6 and 4. You can assume the two nodes you are searching for in the tree will exist somewhere in the tree. 9 | Sample Test Cases 10 | Input:"[5, 2, 6, 1, #, 8, #]", "2", "6" 11 | 12 | Output:5 13 | 14 | 15 | Input:"[5, 2, 6, 1, #, 8, 12, #, #, #, #, #, #, 3, #]", "3", "12" 16 | 17 | Output:12 18 | */ 19 | function BinaryTreeLCA(strArr) { 20 | const nodes = convertToArray(strArr[0]); 21 | const node1 = strArr[1]; 22 | const node2 = strArr[2]; 23 | 24 | const root = nodes.shift(); 25 | if ((node1 === root) || (node2 === root)) return root; 26 | const binaryTree = [root]; 27 | let width = 2; // representing the width of the current level 28 | let level = 1; 29 | 30 | // populating the binaryTree from user input (nodes[]) 31 | while (nodes.length > 0) { 32 | binaryTree.push(nodes.shift() + "|"); 33 | for(let i = 1; i < width; i++) { 34 | binaryTree[level] += nodes.shift() + "|"; 35 | } 36 | binaryTree[level] = binaryTree[level].substring(0, binaryTree[level].length - 1); 37 | level ++; 38 | width *= 2; // the width for next level is twice as large as the previous 39 | } 40 | return getLowestCommonAncestor(binaryTree, node1, node2); 41 | } 42 | 43 | function getLowestCommonAncestor(binaryTree, node1, node2) { 44 | while (node1 !== node2) { 45 | const l1 = getLevel(binaryTree, node1); 46 | const l2 = getLevel(binaryTree, node2); 47 | // get Parent node for whoever node is deepest 48 | if (l1 > l2) node1 = getParent(binaryTree, node1); 49 | else node2 = getParent(binaryTree, node2); 50 | } 51 | return node1; 52 | } 53 | 54 | function getParent(binaryTree, node) { 55 | const level = getLevel(binaryTree, node); 56 | if (level < 2) return binaryTree[0]; // parent node is root, or node itself is root 57 | const nodes = binaryTree[level].split("|"); 58 | const idx = Math.floor(nodes.indexOf(node) / 2); 59 | const parents = binaryTree[level - 1].split("|"); 60 | return parents[idx]; 61 | } 62 | 63 | function getLevel(binaryTree, node) { 64 | for (let i in binaryTree) { 65 | const nodes = binaryTree[i].split("|"); 66 | if (nodes.indexOf(node) > -1) return i; 67 | } 68 | return -1; 69 | } 70 | 71 | // help functions 72 | function convertToArray(str) { 73 | str = str.replace("[", ""); 74 | str = str.replace("]", ""); 75 | str = str.replace(/ /g, ""); 76 | return str.split(",").map(String); 77 | } 78 | 79 | 80 | // sample cases 81 | let input = ["[12, 5, 9, 6, 2, 0, 8, #, #, 7, 4, #, #, #, #]", "6", "4"]; 82 | 83 | //input = ["[5, 2, 6, 1, #, 8, 12, #, #, #, #, #, #, 3, #]", "3", "12"]; 84 | //input = ["[5, 2, 6, 1, #, 8, #]", "2", "6"]; 85 | console.log(BinaryTreeLCA(input)); 86 | -------------------------------------------------------------------------------- /medium/BracketMatcher.js: -------------------------------------------------------------------------------- 1 | function BracketMatcher(str) { 2 | const startBracketCount = str.replace(/[^\(]/g, "").split("").length; 3 | const endBracketCount = str.replace(/[^\)]/g, "").split("").length; 4 | if (startBracketCount !== endBracketCount) return 0; 5 | 6 | const l = str.length; 7 | let firstBracketFound = false; 8 | let lastBracket = ""; 9 | for (i = 0; i < l; i ++) { 10 | if (str[i] === "(") firstBracketFound = true; 11 | if ((str[i] === ")") && (!firstBracketFound)) return 0; 12 | if ((str[i] === "(") || (str[i] === ")")) lastBracket = str[i]; 13 | } 14 | if (lastBracket === "(") return 0; 15 | return 1; 16 | } 17 | 18 | console.log(BracketMatcher(process.argv[2])); 19 | -------------------------------------------------------------------------------- /medium/CaesarCipher.js: -------------------------------------------------------------------------------- 1 | /* 2 | Have the function CaesarCipher(str,num) take the str parameter and perform a Caesar Cipher 3 | shift on it using the num parameter as the shifting number. 4 | A Caesar Cipher works by shifting each letter in the string N places down in the 5 | alphabet (in this case N will be num). Punctuation, spaces, and capitalization 6 | should remain intact. For example if the string is "Caesar Cipher" and num is 2 the output should be "Ecguct Ekrjgt". 7 | 8 | 9 | */ 10 | 11 | function CaesarCipher (str, num) { 12 | const l = str.length; 13 | let retval = ""; 14 | for (let i = 0; i < l; i ++) { 15 | if (/[a-z]/.test(str[i])) { 16 | let charcode = str.charCodeAt(i) + num; 17 | //a = 97, z = 122 18 | if (charcode > 122) charcode = charcode - 122 + 96; // shifting the charcode 19 | retval += String.fromCharCode(charcode); 20 | } else if (/[A-Z]/.test(str[i])) { 21 | let charcode = str.charCodeAt(i) + num; 22 | // A = 65, B = 90 23 | if (charcode > 90) charcode = charcode - 90 + 64; // shifting the charcode 24 | retval += String.fromCharCode(charcode); 25 | } else { 26 | retval += str[i]; 27 | } 28 | } 29 | return retval; 30 | } 31 | 32 | console.log(CaesarCipher("dogs", 8)); -------------------------------------------------------------------------------- /medium/CharacterRemoval.js: -------------------------------------------------------------------------------- 1 | 2 | function CharacterRemoval(strArr) { 3 | const str = strArr.shift(); 4 | const dictionary = strArr[0].replace(/ /g, "").split(","); 5 | 6 | function existAllCharactersInString(word, str) { 7 | let m = word.length; 8 | let n = str.length; 9 | let j = 0; 10 | for (let i = 0; i < n; i ++) { 11 | if (word[j] === str[i]) j ++; 12 | } 13 | return (j === m); 14 | } 15 | 16 | let letterCount = -1; 17 | for (const word of dictionary) { 18 | if(existAllCharactersInString(word, str)) { 19 | const diff = str.length - word.length; 20 | if (letterCount === -1) letterCount = diff; 21 | if (diff < letterCount) letterCount = diff; 22 | } 23 | } 24 | return letterCount; 25 | } 26 | 27 | const input = ["worlcde", "apple,bat,cat,goodbye,hello,yellow,why,world"]; 28 | console.log(CharacterRemoval(input)); 29 | -------------------------------------------------------------------------------- /medium/CoinDeterminer.js: -------------------------------------------------------------------------------- 1 | function CoinDeterminer(num) { 2 | const coins = [1, 5, 7, 9, 11]; 3 | let qty = 0; 4 | let sum = 0; 5 | num = Number(num); 6 | while (sum !== num) { 7 | //trying first every combo of up to 3 coins 8 | for (let i = 0; i < 5; i ++) { 9 | if (sum + coins[i] === num) return qty + 1; 10 | for (j = 0; j < 5; j ++) { 11 | if (sum + coins[i] + coins[j] === num) return qty + 2; 12 | for (k = j; k < 5; k ++) { 13 | if (sum + coins[i] + coins[j] + coins[k] === num) return qty + 3; 14 | } 15 | } 16 | } 17 | const diff = num - sum; 18 | if (diff >= 11) { 19 | sum += 11; 20 | } else if (diff >= 9) { 21 | sum += 9; 22 | } else if (diff >= 7) { 23 | sum += 7; 24 | } else if (diff >= 5) { 25 | sum += 5 26 | } else { 27 | sum += 1; 28 | } 29 | qty ++; 30 | if (sum === num) break; 31 | } 32 | return qty; 33 | } 34 | 35 | console.log(CoinDeterminer(process.argv[2])); -------------------------------------------------------------------------------- /medium/DashInsertII.js: -------------------------------------------------------------------------------- 1 | function DashInsertII(str) { 2 | str = String(str); 3 | const length = str.toString().length - 1; 4 | let retval = ""; 5 | console.log(str[0]); 6 | for (let i = 0; i < length; i ++) { 7 | if ((str[i] % 2 !== 0) && (str[i + 1] % 2 !== 0)) { 8 | if ((str[i] == "0") || (str[i + 1] == "0")) retval = retval + str[i]; 9 | else retval = retval + str[i] + "-"; 10 | } else if ((str[i] % 2 === 0) && (str[i + 1] % 2 === 0)) { 11 | if ((str[i] == "0") || (str[i + 1] == "0")) retval = retval + str[i]; 12 | else retval = retval + str[i] + "*"; 13 | } else { 14 | retval = retval + str[i]; 15 | } 16 | } 17 | // code goes here 18 | return retval + str[str.length - 1]; 19 | } 20 | 21 | console.log(DashInsertII(process.argv[2])); -------------------------------------------------------------------------------- /medium/FibonacciChecker.js: -------------------------------------------------------------------------------- 1 | function FibonacciChecker(num) { 2 | num = Number(num); 3 | const fibo = [1 , 2]; 4 | let fiboNum = 0; 5 | let idx = 1; 6 | if ((num === 1) || (num === 2)) return "yes"; 7 | while (fiboNum <= num) { 8 | fiboNum = fibo[idx - 1] + fibo[idx]; 9 | if (fiboNum === num) return "yes"; 10 | idx ++; 11 | fibo.push(fiboNum); 12 | } 13 | return "no"; 14 | } 15 | 16 | console.log(FibonacciChecker(process.argv[2])); 17 | -------------------------------------------------------------------------------- /medium/HTMLElements.js: -------------------------------------------------------------------------------- 1 | function HTMLElements(str) { 2 | function exctractElementName(str) { 3 | return str.replace("<", "").replace("/", "").replace(">", ""); 4 | } 5 | 6 | const pattern = /<[a-z\/ "]+>/g; 7 | let hit = ""; 8 | const startElement = []; 9 | const endElement = []; 10 | while ((hit = pattern.exec(str)) !== null) { 11 | const e = hit.toString(); 12 | if (e.substring(0, 2) == " -1) { 22 | endElement.splice(idx, 1); 23 | } else { 24 | return e; 25 | } 26 | } 27 | 28 | return true; 29 | } 30 | 31 | console.log(HTMLElements(process.argv[2])); -------------------------------------------------------------------------------- /medium/KUniqueCharacters.js: -------------------------------------------------------------------------------- 1 | function KUniqueCharacters (str) { 2 | const k = str[0]; 3 | const chars = str.substring(1); 4 | const l = chars.length; 5 | const subStrings = []; 6 | for (let i = 0; i < l; i ++) { 7 | let substr = ""; 8 | let uniqueChars = 0; 9 | for (let j = i; j < l; j ++) { 10 | if (substr.indexOf(chars[j]) < 0) uniqueChars ++; 11 | if (uniqueChars <= k) substr += chars[j]; 12 | else break; 13 | } 14 | subStrings.push(substr); 15 | } 16 | let retval = ""; 17 | for (const substr of subStrings) { 18 | if (substr.length > retval.length) retval = substr; 19 | } 20 | return retval; 21 | } 22 | 23 | console.log(KUniqueCharacters(process.argv[2])); 24 | -------------------------------------------------------------------------------- /medium/LRUCache.js: -------------------------------------------------------------------------------- 1 | /* 2 | Challenge 3 | Have the function LRUCache(strArr) take the array of characters stored in strArr, which will contain characters ranging from A to Z in some arbitrary order, and determine what elements still remain in a virtual cache that can hold up to 5 elements with an LRU cache algorithm implemented. For example: if strArr is ["A", "B", "C", "D", "A", "E", "D", "Z"], then the following steps are taken: 4 | 5 | (1) A does not exist in the cache, so access it and store it in the cache. 6 | (2) B does not exist in the cache, so access it and store it in the cache as well. So far the cache contains: ["A", "B"]. 7 | (3) Same goes for C, so the cache is now: ["A", "B", "C"]. 8 | (4) Same goes for D, so the cache is now: ["A", "B", "C", "D"]. 9 | (5) Now A is accessed again, but it exists in the cache already so it is brought to the front: ["B", "C", "D", "A"]. 10 | (6) E does not exist in the cache, so access it and store it in the cache: ["B", "C", "D", "A", "E"]. 11 | (7) D is accessed again so it is brought to the front: ["B", "C", "A", "E", "D"]. 12 | (8) Z does not exist in the cache so add it to the front and remove the least recently used element: ["C", "A", "E", "D", "Z"]. 13 | 14 | Now the caching steps have been completed and your program should return the order of the cache with the elements joined into a string, separated by a hyphen. Therefore, for the example above your program should return C-A-E-D-Z. 15 | Sample Test Cases 16 | Input:"A", "B", "A", "C", "A", "B" 17 | 18 | Output:"C-A-B" 19 | 20 | 21 | Input:"A", "B", "C", "D", "E", "D", "Q", "Z", "C" 22 | 23 | Output:"E-D-Q-Z-C" 24 | */ 25 | 26 | function LRUCache(strArr) { 27 | const cache = []; 28 | strArr.forEach(function(e) { 29 | const idx = cache.indexOf(e); 30 | if (idx > -1) { 31 | cache.splice(idx, 1); 32 | } else { 33 | if (cache.length >= 5) { 34 | cache.shift(); 35 | } 36 | } 37 | cache.push(e); 38 | }); 39 | return cache.join("-"); 40 | } 41 | 42 | // sample input 43 | const input = ["A", "B", "C", "D", "E", "D", "Q", "Z", "C"]; 44 | console.log(LRUCache(input)); 45 | -------------------------------------------------------------------------------- /medium/LookSaySequence.js: -------------------------------------------------------------------------------- 1 | function LookSaySequence (num) { 2 | num = String(num); 3 | const l = num.length; 4 | let retval = ""; 5 | let current = num[0]; 6 | let counter = 1; 7 | for (let i = 1; i < l; i ++) { 8 | if (current !== num[i]) { 9 | retval += counter + current; 10 | current = num[i]; 11 | counter = 1; 12 | } else { 13 | counter ++; 14 | } 15 | //console.log(num[i]); 16 | } 17 | retval += counter + current; 18 | return retval; 19 | } 20 | 21 | console.log(LookSaySequence(process.argv[2])); 22 | -------------------------------------------------------------------------------- /medium/MaxSubarray.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | function MaxSubarray(arr) { 4 | const l = arr.length; 5 | const sums = []; 6 | for (let i = 0; i < l; i ++) { // start index 7 | for (let j = l; j > i; j --) { 8 | for (let k = i; k <= j; k ++) { 9 | 10 | } 11 | const sum = arr.slice(i, j).reduce((total, current) => total + current, 0); 12 | sums.push(sum); 13 | } 14 | } 15 | sums.sort((a, b) => a - b); 16 | return sums.pop(); 17 | } 18 | 19 | const input = [3, -1, -1, 4, 3, -1]; 20 | console.log(MaxSubarray(input)); -------------------------------------------------------------------------------- /medium/MissingDigit.js: -------------------------------------------------------------------------------- 1 | /* 2 | Challenge 3 | Have the function MissingDigit(str) take the str parameter, which will be a simple mathematical formula with three numbers, a single operator (+, -, *, or /) and an equal sign (=) and return the digit that completes the equation. In one of the numbers in the equation, there will be an x character, and your program should determine what digit is missing. For example, if str is "3x + 12 = 46" then your program should output 4. The x character can appear in any of the three numbers and all three numbers will be greater than or equal to 0 and less than or equal to 1000000. 4 | Sample Test Cases 5 | Input:"4 - 2 = x" 6 | 7 | Output:2 8 | 9 | 10 | Input:"1x0 * 12 = 1200" 11 | 12 | Output:0 13 | */ 14 | 15 | function MissingDigit(str) { 16 | const calc = str.split("="); 17 | const result = Number(eval(calc[0].indexOf("x") > -1 ? calc[1] : calc[0])); 18 | const expression = calc[0].indexOf("x") > -1 ? calc[0] : calc[1]; 19 | let i = 0; 20 | while (true) { 21 | if (eval(expression.replace("x", i)) === result) return i; 22 | i ++; 23 | } 24 | 25 | } 26 | 27 | console.log(MissingDigit(process.argv[2])); -------------------------------------------------------------------------------- /medium/MissingDigitII.js: -------------------------------------------------------------------------------- 1 | function MissingDigitII(str) { 2 | const arr = str.split("="); 3 | const lefthand = arr[0]; 4 | const righthand = arr[1]; 5 | for (let i = 0; i < 10; i ++) { 6 | for (let j = 0; j < 10; j ++) { 7 | const left = lefthand.replace("?", i.toString()); 8 | const right = righthand.replace("?", j.toString()); 9 | if (eval(left) === eval(right)) return i + " " + j; 10 | } 11 | } 12 | } 13 | 14 | console.log(MissingDigitII(process.argv[2])); -------------------------------------------------------------------------------- /medium/MostFreeTime.js: -------------------------------------------------------------------------------- 1 | /*Challenge 2 | Have the function MostFreeTime(strArr) read the strArr parameter being passed which will represent a full day and will be filled with events that span from time X to time Y in the day. The format of each event will be hh:mmAM/PM-hh:mmAM/PM. For example, strArr may be ["10:00AM-12:30PM","02:00PM-02:45PM","09:10AM-09:50AM"]. Your program will have to output the longest amount of free time available between the start of your first event and the end of your last event in the format: hh:mm. The start event should be the earliest event in the day and the latest event should be the latest event in the day. The output for the previous input would therefore be 01:30 (with the earliest event in the day starting at 09:10AM and the latest event ending at 02:45PM). The input will contain at least 3 events and the events may be out of order. 3 | Sample Test Cases 4 | Input:"12:15PM-02:00PM","09:00AM-10:00AM","10:30AM-12:00PM" 5 | 6 | Output:"00:30" 7 | 8 | 9 | Input:"12:15PM-02:00PM","09:00AM-12:11PM","02:02PM-04:00PM" 10 | 11 | Output:"00:04" 12 | */ 13 | 14 | function MostFreeTime(arr) { 15 | const events = []; 16 | 17 | arr.forEach(function(event) { 18 | event = event.split("-"); 19 | events.push({ start : get24Time(event[0]), end : get24Time(event[1]) }); 20 | }); 21 | 22 | events.sort(function(a, b) { 23 | return a.start > b.start; 24 | }); 25 | 26 | const ubound = events.length; 27 | let freetime = 0; 28 | for (let i = 1; i < ubound; i ++) { 29 | const diff = getDiffInMinutes(events[i - 1].end, events[i].start); 30 | if (diff > freetime) freetime = diff; 31 | } 32 | return getHHMMFromMinutes(freetime); 33 | } 34 | // help functions 35 | function getHHMMFromMinutes(num) { 36 | let hour = Math.floor(num / 60); 37 | let minutes = num % 60; 38 | 39 | if (hour.toString().length === 1) hour = "0" + hour; 40 | if (minutes.toString().length === 1) minutes = "0" + minutes; 41 | return hour + ":" + minutes; 42 | } 43 | 44 | function getDiffInMinutes(timeStr1, timeStr2) { 45 | const t1 = timeStr1.split(":"); 46 | const t2 = timeStr2.split(":"); 47 | const h1 = Number(t1[0]); 48 | const m1 = Number(t1[1]); 49 | const h2 = Number(t2[0]); 50 | const m2 = Number(t2[1]); 51 | const diff = ((h2 - h1) * 60) + m2 - m1; 52 | return diff; 53 | } 54 | 55 | function get24Time(s) { 56 | const t = s.split(":"); 57 | if ((t[1].indexOf("PM") > 0) && (t[0] < 12)) t[0] = Number(t[0]) + 12; 58 | else if ((t[1].indexOf("AM") > 0) && (t[0] > 11)) t[0] = Number(t[0]) + 12; 59 | 60 | if (t[0] === 24) t[0] = "00"; 61 | return t[0] + ":" + t[1].substring(0, 2); 62 | } 63 | 64 | //const input = ["12:15PM-02:00PM","09:00AM-10:00AM","10:30AM-12:00PM"]; 65 | const input = ["12:15PM-02:00PM","09:00AM-12:11PM","02:02PM-04:00PM"]; 66 | //const input = ["10:00AM-12:30PM","02:00PM-02:45PM","09:10AM-09:50AM"]; 67 | console.log(MostFreeTime(input)); 68 | -------------------------------------------------------------------------------- /medium/MultipleBrackets.js: -------------------------------------------------------------------------------- 1 | /* 2 | Challenge 3 | Have the function MultipleBrackets(str) take the str parameter being passed and 4 | return 1 #ofBrackets if the brackets are correctly matched and each one is accounted for. 5 | Otherwise return 0. 6 | For example: if str is "(hello [world])(!)", then the output should be 1 3 because all 7 | the brackets are matched and there are 3 pairs of brackets, but if str is "((hello [world])" 8 | the the output should be 0 because the brackets do not correctly match up. 9 | Only "(", ")", "[", and "]" will be used as brackets. If str contains no brackets return 1. 10 | Sample Test Cases 11 | Input:"(coder)[byte)]" 12 | 13 | Output:0 14 | 15 | 16 | Input:"(c([od]er)) b(yt[e])" 17 | 18 | Output:1 5 19 | */ 20 | 21 | function MultipleBrackets(str) { 22 | const startBracketCount = str.replace(/[^\(]/g, "").split("").length; 23 | const endBracketCount = str.replace(/[^\)]/g, "").split("").length; 24 | const startCBracketCount = str.replace(/[^\[]/g, "").split("").length; 25 | const endCBracketCount = str.replace(/[^\]]/g, "").split("").length; 26 | if ((startBracketCount === 0) && (endBracketCount === 0) && (startCBracketCount === 0) && (endCBracketCount === 0)) return 1; 27 | 28 | if ((startBracketCount === endBracketCount) && (startCBracketCount === endCBracketCount)) { 29 | let firstStart = str.indexOf("("); 30 | let firstend = str.indexOf(")"); 31 | if (firstend < firstStart) return 0; 32 | firstStart = str.indexOf("["); 33 | firstend = str.indexOf("]"); 34 | if (firstend < firstStart) return 0; 35 | 36 | return 1 + " " + (startBracketCount + startCBracketCount); 37 | } else { 38 | return 0; 39 | } 40 | } 41 | 42 | console.log(MultipleBrackets(process.argv[2])); 43 | -------------------------------------------------------------------------------- /medium/NumberSearch.js: -------------------------------------------------------------------------------- 1 | /* 2 | Challenge 3 | Have the function NumberSearch(str) take the str parameter, search for all the numbers in the string, 4 | add them together, then return that final number divided by the total amount of letters in the string. 5 | For example: if str is "Hello6 9World 2, Nic8e D7ay!" the output should be 2. 6 | First if you add up all the numbers, 6 + 9 + 2 + 8 + 7 you get 32. 7 | Then there are 17 letters in the string. 32 / 17 = 1.882, and the final answer should be 8 | rounded to the nearest whole number, so the answer is 2. Only single digit numbers 9 | separated by spaces will be used throughout the whole string 10 | (So this won't ever be the case: hello44444 world). Each string will also have at least one letter. 11 | Sample Test Cases 12 | Input:"H3ello9-9" 13 | 14 | Output:4 15 | 16 | 17 | Input:"One Number*1*" 18 | 19 | Output:0 20 | */ 21 | 22 | function NumberSearch(str) { 23 | const numbers = str.replace(/[^0-9]/g, "").split("").map(Number); 24 | const l = numbers.length; 25 | let numberSum = 0; 26 | for (let i = 0; i < l; i++) { 27 | numberSum += numbers[i]; 28 | } 29 | const letterCount = str.replace(/[^a-zA-Z]/g, "").length; 30 | return Math.round(numberSum / letterCount); 31 | } 32 | 33 | console.log(NumberSearch(process.argv[2])); -------------------------------------------------------------------------------- /medium/OffBinary.js: -------------------------------------------------------------------------------- 1 | /* 2 | Challenge 3 | Have the function OffBinary(strArr) read the array of strings stored in strArr, 4 | which will contain two elements, the first will be a positive decimal number and the second element will be a binary number. 5 | Your goal is to determine how many digits in the binary number need to be changed to 6 | represent the decimal number correctly (either 0 change to 1 or vice versa). 7 | For example: if strArr is ["56", "011000"] then your program should return 1 because only 1 digit needs 8 | to change in the binary number (the first zero needs to become a 1) to correctly represent 56 in binary. 9 | Sample Test Cases 10 | Input:"5624", "0010111111001" 11 | 12 | Output:2 13 | 14 | 15 | Input:"44", "111111" 16 | 17 | Output:3 18 | */ 19 | 20 | function OffBinary(strArr) { 21 | const base10 = strArr[0]; 22 | const binary = strArr[1]; 23 | const base2 = Number(base10).toString(2); 24 | return base2 25 | .split("") 26 | .reduce((change, bit, idx) => bit !== binary[idx] ? change + 1 : change, 0); 27 | } 28 | 29 | // sample test inputs 30 | //const input = ["5624", "0010111111001"]; 31 | const input = ["5624", "0010111111001"]; 32 | 33 | console.log(OffBinary(input)); 34 | -------------------------------------------------------------------------------- /medium/PermutationStep.js: -------------------------------------------------------------------------------- 1 | function PermutationStep(num) { 2 | const numStr = String(num); 3 | const l = numStr.length; 4 | const numbers = getAllCombos(String(num)); 5 | 6 | numbers.sort(sortNumber); 7 | const ubound = numbers.length; 8 | for (let i = 0; i < ubound; i ++) { 9 | if (numbers[i] > num) return numbers[i]; 10 | } 11 | return -1; 12 | } 13 | 14 | function sortNumber(a, b) { 15 | return a - b; 16 | } 17 | 18 | function getAllCombos(str) { 19 | if (str.length < 2) return str; 20 | const combos = []; // the array with every combo, the return value 21 | const l = str.length; 22 | for (let i = 0; i < l; i ++) { 23 | const char = str[i]; 24 | 25 | if (str.indexOf(char) === i) { 26 | const remainingString = str.substring(0, i) + str.substring(i + 1, l); 27 | for (let substr of getAllCombos(remainingString)) { 28 | combos.push(char + substr); 29 | } 30 | } 31 | } 32 | return combos; 33 | } 34 | 35 | console.log(PermutationStep(process.argv[2])); -------------------------------------------------------------------------------- /medium/SeatingStudents.js: -------------------------------------------------------------------------------- 1 | /* 2 | Challenge 3 | Have the function SeatingStudents(arr) read the array of integers stored in arr which will be in the 4 | following format: [K, r1, r2, r3, ...] where K represents the number of desks in a classroom, 5 | and the rest of the integers in the array will be in sorted order and will represent the desks 6 | that are already occupied. All of the desks will be arranged in 2 columns, 7 | where desk #1 is at the top left, desk #2 is at the top right, desk #3 is below #1, desk #4 is below #2, etc. 8 | Your program should return the number of ways 2 students can be seated next to each other. 9 | This means 1 student is on the left and 1 student on the right, or 1 student is directly above or below the other student. 10 | 11 | For example: if arr is [12, 2, 6, 7, 11] then this classrooms looks like the following picture: 12 | 13 | 14 | 15 | Based on above arrangement of occupied desks, there are a total of 6 ways to seat 2 new students next to each other. The combinations are: [1, 3], [3, 4], [3, 5], [8, 10], [9, 10], [10, 12]. So for this input your program should return 6. K will range from 2 to 24 and will always be an even number. After K, the number of occupied desks in the array can range from 0 to K. 16 | Sample Test Cases 17 | Input:6, 4 18 | 19 | Output:4 20 | 21 | 22 | Input:8, 1, 8 23 | 24 | Output:6 25 | */ 26 | 27 | function SeatingStudents(arr) { 28 | const number_of_seats = arr.shift(); 29 | const number_of_rows = Math.round(number_of_seats / 2); 30 | const seat = []; 31 | let idx = 0; 32 | for (row = 0; row < number_of_rows; row ++) { 33 | seat.push([]); 34 | for (col = 0; col < 2; col ++) { 35 | const isOccupied = arr.indexOf(idx + 1) > -1 ? true : false; 36 | //console.log(row); 37 | seat[row].push(isOccupied); 38 | idx ++; 39 | } 40 | console.log(seat[row].join("-")); 41 | } 42 | 43 | let seating = 0; 44 | for (let i = 0; i < number_of_rows - 1; i ++) { 45 | if ((seat[i][0] === false) && (seat[i][1] === false)) seating ++; 46 | if ((seat[i][0] === false) && (seat[i + 1][0] === false)) seating ++; 47 | if ((seat[i][1] === false) && (seat[i + 1][1] === false)) seating ++; 48 | } 49 | // check if last row is empty: 50 | if ((seat[number_of_rows - 1][0] == false) && (seat[number_of_rows - 1][1] == false)) seating ++; 51 | return seating; 52 | } 53 | 54 | const input = [12, 2, 6, 7, 11]; 55 | //const input = [8,1,8]; 56 | 57 | console.log(SeatingStudents(input)); 58 | -------------------------------------------------------------------------------- /medium/SimpleMode.js: -------------------------------------------------------------------------------- 1 | function SimpleMode(arr) { 2 | const l = arr.length; 3 | const numbers = {}; 4 | 5 | for (let i = 0; i < l; i ++) { 6 | if (numbers[arr[i]]) { 7 | numbers[arr[i]] ++; 8 | } else { 9 | numbers[arr[i]] = 1; 10 | } 11 | } 12 | 13 | let highest = 0; 14 | let number = 0; 15 | for (let i = 0; i < l; i ++) { 16 | if (numbers[arr[i]] > highest) { 17 | highest = numbers[arr[i]]; 18 | number = arr[i]; 19 | } 20 | } 21 | if (highest > 1) return number; 22 | else return -1; 23 | } 24 | 25 | 26 | const input = [5, 10, 10, 6, 5, 10, 10, 1, 1, 1, 1, 1, 1, 1]; 27 | console.log(SimpleMode(input)); -------------------------------------------------------------------------------- /medium/StockPicker.js: -------------------------------------------------------------------------------- 1 | function StockPicker(arr) { 2 | let max = -1; 3 | const l = arr.length; 4 | for (let i = 0; i < l; i ++) { 5 | for (let j = i + 1; j < l; j ++) { 6 | const diff = arr[j] - arr[i]; 7 | if (diff > max) max = diff; 8 | } 9 | } 10 | return max; 11 | } 12 | 13 | const input = [14,20,4,12,5,11]; 14 | 15 | console.log(StockPicker(input)); 16 | -------------------------------------------------------------------------------- /medium/StringReduction.js: -------------------------------------------------------------------------------- 1 | function StringReduction (str) { 2 | let idx = 0; 3 | 4 | const searchchars = "abc"; 5 | const l = searchchars.length; 6 | const combos = []; 7 | //creating every combo into comboarray 8 | for (i = 0; i < l; i ++) { 9 | for (j = 0; j < l; j ++) { 10 | if (j !== i) { 11 | combos.push(searchchars[i] + searchchars[j]); 12 | } 13 | } 14 | } 15 | const combocount = combos.length; 16 | let previous = ""; 17 | while (str != previous) { 18 | previous = str; 19 | for (let i = 0; i < combocount; i ++) { 20 | const replChar = getTheOtherChar(combos[i]); 21 | str = str.replace(combos[i], replChar); 22 | } 23 | } 24 | return str.length; 25 | 26 | } 27 | 28 | function getTheOtherChar(str) { 29 | if (str.indexOf("a") < 0) return "a"; 30 | else if (str.indexOf("b") < 0) return "b"; 31 | else return "c"; 32 | } 33 | 34 | console.log(StringReduction(process.argv[2])); 35 | -------------------------------------------------------------------------------- /medium/SwapII.js: -------------------------------------------------------------------------------- 1 | function SwapII(str) { 2 | str = invertCase(str); 3 | const l = str.length; 4 | let retval = ""; 5 | for (let i = 0; i < l; i ++) { // loop through the string 6 | if (/[0-9]/.test(str[i])) { // if current char is a digit, then check it further.. 7 | let searchString = str.substring(i); 8 | const posOfSpace = searchString.indexOf(" "); 9 | if (posOfSpace > 0) searchString = searchString.substring(0, posOfSpace); // limit the searchstring to next space or end of string if no space is found 10 | const pattern = /\d[a-zA-Z]+\d/; // this is the pattern we're looking for 11 | if (pattern.test(searchString)) { 12 | const match = searchString.match(pattern)[0]; 13 | i += match.length - 1; 14 | const first = match[0]; 15 | const last = match[match.length - 1]; 16 | retval += last + match.substring(1, match.length - 1) + first; 17 | } else { 18 | retval += str[i]; 19 | } 20 | } else { 21 | retval += str[i]; 22 | } 23 | } 24 | return retval; 25 | } 26 | 27 | // help function 28 | function invertCase(str) { 29 | const l = str.length; 30 | let retval = ""; 31 | for (let i = 0; i < l; i++) { 32 | if (str[i] === str[i].toUpperCase()) retval += str[i].toLowerCase(); 33 | else if (str[i] === str[i].toLowerCase()) retval += str[i].toUpperCase(); 34 | else retval += str[i]; 35 | } 36 | return retval; 37 | } 38 | console.log(SwapII(process.argv[2])); 39 | -------------------------------------------------------------------------------- /medium/SymmetricTree.js: -------------------------------------------------------------------------------- 1 | function SymmetricTree(nodes) { 2 | const root = nodes.shift(); 3 | const binaryTree = [root]; 4 | let width = 2; 5 | let level = 1; 6 | while (nodes.length > 0) { 7 | binaryTree.push(nodes.shift() + "|"); 8 | for (let i = 1; i < width; i ++) { 9 | binaryTree[level] += nodes.shift() + "|"; 10 | } 11 | binaryTree[level] = binaryTree[level].substring(0, binaryTree[level].length - 1); 12 | level ++; 13 | width *= 2; 14 | } 15 | for (let i = 1; i <= level - 1; i ++) { 16 | const items = binaryTree[i].split("|"); 17 | let ubound = items.length - 1; 18 | for (let j = 0; j < ubound; j++) { 19 | if (items[j] !== items[ubound]) return false; 20 | ubound --; 21 | } 22 | } 23 | return true; 24 | } 25 | 26 | const input = ["10", "2", "2", "#", "1", "1", "#"]; 27 | //const input = ["4", "3", "4"]; 28 | 29 | console.log(SymmetricTree(input)); 30 | -------------------------------------------------------------------------------- /medium/ThreeFiveMultiples.js: -------------------------------------------------------------------------------- 1 | /* 2 | Have the function ThreeFiveMultiples(num) return the sum of all the multiples of 3 and 5 that are below num. 3 | For example: if num is 10, the multiples of 3 and 5 that are below 10 are 3, 5, 6, and 9, and adding them up you get 23, 4 | so your program should return 23. The integer being passed will be between 1 and 100. 5 | */ 6 | function ThreeFiveMultiples(num) { 7 | const sumArr = []; 8 | let sum = 0; 9 | for (let i = 3; i < num; i ++) { 10 | if (i % 5 === 0) sum += i; 11 | else if (i % 3 === 0) sum += i; 12 | } 13 | return sum; 14 | } 15 | 16 | console.log(ThreeFiveMultiples(process.argv[2])); -------------------------------------------------------------------------------- /medium/TreeConstructor.js: -------------------------------------------------------------------------------- 1 | /* 2 | Challenge 3 | Have the function TreeConstructor(strArr) take the array of strings stored in strArr, 4 | which will contain pairs of integers in the following format: (i1,i2), 5 | where i1 represents a child node in a tree and the second integer i2 signifies that it is the parent of i1. 6 | For example: if strArr is ["(1,2)", "(2,4)", "(7,2)"], then this forms the following tree: 7 | 8 | 9 | 10 | which you can see forms a proper binary tree. Your program should, in this case, return the 11 | string true because a valid binary tree can be formed. If a proper binary tree cannot be 12 | formed with the integer pairs, then return the string false. All of the integers within 13 | the tree will be unique, which means there can only be one node in the tree with the 14 | given integer value. 15 | Sample Test Cases 16 | Input:"(1,2)", "(2,4)", "(5,7)", "(7,2)", "(9,5)" 17 | 18 | Output:"true" 19 | 20 | 21 | Input:"(1,2)", "(3,2)", "(2,12)", "(5,2)" 22 | 23 | Output:"false" 24 | */ 25 | 26 | function TreeConstructor(strArr) { 27 | const l = strArr.length; 28 | const binaryTree = [{}]; 29 | for (let i in strArr) { 30 | const pair = getPair(strArr[i]); 31 | const parent = pair[1]; 32 | const child = pair[0]; 33 | 34 | // if the current child has two parents, return false, since it's an invalid binary tree 35 | const treeParent = getParentOfChild(binaryTree, child); 36 | if ((treeParent !== "") && (treeParent !== parent)) return false; 37 | 38 | const idx = getIdxOfNode(binaryTree, parent); 39 | if(idx < 0) { 40 | binaryTree.push({ parent : parent, child1 : child }); 41 | } else { 42 | if (binaryTree[idx].child2) return false; 43 | else binaryTree[idx].child2 = child; 44 | } 45 | } 46 | return true; 47 | } 48 | 49 | function getParentOfChild(binaryTree, child) { 50 | for (let i in binaryTree) { 51 | if ((binaryTree[i].child1 === child) || (binaryTree[i].child2 === child)) return binaryTree[i].parent; 52 | } 53 | return ""; 54 | } 55 | 56 | function getIdxOfNode(binaryTree, parent) { 57 | for (let i in binaryTree) { 58 | if (binaryTree[i].parent === parent) return i; 59 | } 60 | return -1; 61 | } 62 | 63 | function getPair(str) { 64 | return str.replace("(", "").replace(")", "").split(",").map(Number); 65 | } 66 | 67 | // sample test inputs 68 | const input = ["(1,2)", "(2,4)", "(5,7)", "(7,2)", "(9,5)"]; 69 | //const input = ["(1,2)", "(2,4)", "(7,2)"]; 70 | 71 | 72 | console.log(TreeConstructor(input)); 73 | -------------------------------------------------------------------------------- /medium/TripleDouble.js: -------------------------------------------------------------------------------- 1 | function TripleDouble(num1, num2) { 2 | snum1 = String(num1); 3 | snum2 = String(num2); 4 | const l = snum1.length; 5 | for (let i = 0; i < l - 2; i++) { 6 | if ((snum1[i] === snum1[i + 1]) && (snum1[i] === snum1[i + 2])) { 7 | const searchString = snum1[i] + snum1[i + 1]; 8 | if (snum2.indexOf(searchString) > -1) return 1; 9 | } 10 | } 11 | return 0; 12 | } 13 | 14 | console.log(TripleDouble(22267844 , 6624374422)); 15 | --------------------------------------------------------------------------------