├── .gitignore ├── README.md ├── arrays-strings ├── 2d-spiral.js ├── arrays-left-rotation.js ├── contains-duplicate-iii.js ├── first-last-element-sorted-arr.js ├── hourglasses.js ├── merge-strings-alternately.js ├── min-swaps-2.js ├── non-constructible-change.js ├── pdf-viewer.js ├── permutation-in-string.js ├── search-2d-matrix.js ├── subarray-sum-equals-k.js ├── three-number-sum.js ├── tournament-winner.js ├── two-sum.js └── validate-subsequence.js ├── dynamic-programming └── longest-increasing-subsequence.js ├── graphs ├── bfs-shortest-reach.js └── snakes-ladders.js ├── hash-maps ├── colorful-number.js ├── ice-cream-parlor.js ├── longest-harmonius-subsequence.js ├── minimum-window-substring.js ├── mock-interview.js └── unique-number-occurrences.js ├── lists ├── detect-cycle-linked-list.js └── insert-node-linked-list.js ├── recursion ├── change-foreign-currency.js ├── fibonacci-with-dp.js └── minimum-diff-sum.js ├── sliding-window └── max-avg-subarray.js ├── sorting ├── insertion-sort-2.js └── quicksort-2.js ├── stacks-queues ├── balanced-bracket.js ├── number-recent-calls.js └── queue-2-stacks.js ├── trees ├── binary-tree-height.java ├── binary-tree-right-side-view.js ├── bst-insertion.java ├── max-depth-binary-tree.js ├── n-ary-tree-level-order-traversal.js ├── n-ary-tree-postorder-traversal.js ├── n-ary-tree-preorder-traversal.js ├── qheap1.js └── trim-bst.js └── two-pointers └── move-zeroes.js /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Coding Interview Problems 2 | This is a set of computer science problems and their solution using Javascript and Java 3 | 4 | ## Structure 5 | Problems were classified in differents computer science topics that you need to be clear about for a coding interview 6 | 7 | ## Source of the problems 8 | - Hackerrank 9 | - Leetcode 10 | - Facebook interview prep. 11 | - Google interview prep. 12 | 13 | ## Go beyond! 14 | Feel free to suggest new approaches for the solutions of the problems or even new challenges! 15 | -------------------------------------------------------------------------------- /arrays-strings/2d-spiral.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Facebook, prep: Question 1 - 2D Spiral array 4 | * Find the pattern and complete the function: 5 | * int[][] spiral(int n); 6 | * where n is the size of the 2D array. 7 | */ 8 | /** 9 | * @param {number} n Size of the array 10 | * @return {number[][]} Array populated in spiral way 11 | */ 12 | const spiral = n => { 13 | // Check edge case 14 | if (n <= 0) { 15 | return []; 16 | } 17 | 18 | // 0 horizontally, 1 vertically 19 | let axis = 0; 20 | // 0 right/down, 1 left/up 21 | let dir = 0 22 | const area = n * n; 23 | let i = 0; 24 | let j = 0; 25 | let counter = 1; 26 | const arr = Array(n).fill().map(() => Array(n).fill()); 27 | arr[i][j] = counter; 28 | counter++; 29 | bounds = [0, n - 1]; 30 | // O(n^2) because the area is n * n and we loop the entire area 31 | while (counter <= area) { 32 | // Move in the current axis according to the current direction 33 | if (axis === 0) { 34 | j = dir === 0 ? j + 1 : j - 1; 35 | } else { 36 | i = dir === 0 ? i + 1 : i - 1; 37 | } 38 | /* 39 | * Check if the loop returned to the start. 40 | * In that case, narrow the boundaries 41 | */ 42 | if (arr[i][j]) { 43 | bounds[0]++; 44 | bounds[1]--; 45 | i = bounds[0]; 46 | j = bounds[0]; 47 | arr[i][j] = counter; 48 | axis = 0; 49 | dir = 0; 50 | } else { 51 | arr[i][j] = counter; 52 | /* 53 | * Check if the loop is at the limit of Y axis. 54 | * In that case, switch the direction and the axis 55 | */ 56 | if ((i === bounds[1] || i === bounds[0]) && axis === 1) { 57 | axis = 0; 58 | dir = i === 0 ? 0 : 1; 59 | 60 | /* 61 | * Check if the loop is at the limit of X axis. 62 | * In that case, switch the axis 63 | */ 64 | } else if ((j === bounds[1] || j === bounds[0]) && axis === 0) { 65 | axis = 1; 66 | } 67 | } 68 | counter++; 69 | } 70 | return arr; 71 | }; 72 | 73 | const n = 4; 74 | const a = spiral(n); 75 | for (row of a) { 76 | console.log( 77 | row.map(el => 78 | el <= 9 ? `${'0'.repeat((n * n + '').length - 1)}${el}` : el.toString() 79 | ) 80 | ); 81 | } -------------------------------------------------------------------------------- /arrays-strings/arrays-left-rotation.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A left rotation operation on an array shifts each of the array's elements 3 | * unit to the left. For example, if left rotations are performed on array 4 | * [1,2,3,4,5], then the array would become [3,4,5,1,2]. 5 | * Given an array a of n integers and a number, d, perform d left rotations on 6 | * the array. Return the updated array to be printed as a single line of 7 | * space-separated integers. 8 | * 9 | * Constraints 10 | * 1. 1 <= n <= 10^5 11 | * 2. 1 <= d <= n 12 | * 3. 1 <= a[i] <= 10^6 13 | */ 14 | 15 | function rotLeft(a, d) { 16 | const n = a.length; 17 | 18 | if (n === 1) { 19 | return a; 20 | } 21 | 22 | if (n - d === 0) { 23 | return a; 24 | } 25 | 26 | if (d > n) { 27 | d = d % n; 28 | } 29 | 30 | const res = a.slice(); 31 | for (let i = 0; i < n; i++) { 32 | let newI = d <= i ? i - d : n - (d - i); 33 | res[newI] = a[i]; 34 | } 35 | 36 | return res; 37 | } -------------------------------------------------------------------------------- /arrays-strings/contains-duplicate-iii.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Given an array of integers, find out whether there are two distinct indices 3 | * i and j in the array such that the absolute difference between nums[i] and 4 | * nums[j] is at most t and the absolute difference between i and j is at most 5 | * k. 6 | */ 7 | 8 | /** 9 | * @param {number[]} nums 10 | * @param {number} k 11 | * @param {number} t 12 | * @return {boolean} 13 | */ 14 | const containsNearbyAlmostDuplicate = function(nums, k, t) { 15 | if (!nums || k < 0 || t < 0) { 16 | return false; 17 | } 18 | 19 | let i = 0; 20 | let j = 0; 21 | while (i < nums.length - 1) { 22 | j = i + 1; 23 | while (j < nums.length) { 24 | if (Math.abs(nums[i] - nums[j]) <= t && Math.abs(i - j) <= k) { 25 | return true; 26 | } 27 | j++; 28 | } 29 | i++; 30 | } 31 | return false; 32 | } -------------------------------------------------------------------------------- /arrays-strings/first-last-element-sorted-arr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Leetcode, #34 3 | * 4 | * Given an array of integers nums sorted in ascending order, find the starting 5 | * and ending position of a given target value. 6 | * 7 | * Your algorithm's runtime complexity must be in the order of O(log n). 8 | * 9 | * If the target is not found in the array, return [-1, -1]. 10 | */ 11 | 12 | /** 13 | * @param {number[]} nums 14 | * @param {number} target 15 | * @return {number[]} 16 | */ 17 | function searchRange(nums, target) { 18 | let indices = [-1, -1]; 19 | if (nums.length > 0) { 20 | indices[0] = binaryFirst(0, nums.length - 1, target, nums); 21 | indices[1] = binaryLast(0, nums.length - 1, target, nums); 22 | } 23 | return indices; 24 | }; 25 | 26 | function binaryFirst(l,r,value, arr) { 27 | if (r >= l) { 28 | const mid = l + Math.floor((r - l) / 2); 29 | if (arr[mid] === value && (mid === 0 || arr[mid - 1] < value)) { 30 | return mid; 31 | } else if (value > arr[mid - 1] || mid === 0) { 32 | return binaryFirst(mid + 1, r, value, arr); 33 | } else { 34 | return binaryFirst(l, mid - 1, value, arr); 35 | } 36 | } else { 37 | return -1; 38 | } 39 | } 40 | 41 | function binaryLast(l,r,value, arr) { 42 | if (r >= l) { 43 | const mid = l + Math.floor((r - l) / 2); 44 | if (arr[mid] === value && (mid === arr.length - 1 || arr[mid + 1] > value)) { 45 | return mid; 46 | } 47 | else if (value < arr[mid + 1] || mid == arr.length - 1) { 48 | return binaryLast(l, mid - 1, value, arr); 49 | } else { 50 | return binaryLast(mid + 1, r, value, arr); 51 | } 52 | } else { 53 | return -1; 54 | } 55 | } -------------------------------------------------------------------------------- /arrays-strings/hourglasses.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Given a 2D Array, : 3 | * 1 1 1 0 0 0 4 | * 0 1 0 0 0 0 5 | * 1 1 1 0 0 0 6 | * 0 0 0 0 0 0 7 | * 0 0 0 0 0 0 8 | * 0 0 0 0 0 0 9 | * 10 | * We define an hourglass in to be a subset of values with indices falling in 11 | * this pattern in 's graphical representation: 12 | * a b c 13 | * d 14 | * e f g 15 | * There are hourglasses in , and an hourglass sum is the sum of an hourglass' 16 | * values. Calculate the hourglass sum for every hourglass in , then print the 17 | * maximum hourglass sum. 18 | * 19 | * Constraints 20 | * - -9 <= arr[i][j] <= 9 21 | * - 0 <= i, j <= 5 22 | */ 23 | 24 | function hourglassSum(arr) { 25 | let max = -63; 26 | let i = 0; 27 | let j = 0; 28 | let sum; 29 | while (i + 2 < arr.length && j + 2 < arr[i].length) { 30 | sum = calcHourglassSum(arr, i , j); 31 | max = Math.max(max, sum); 32 | j++; 33 | if (j + 2 >= arr[i].length) { 34 | j = 0; 35 | i++; 36 | } 37 | } 38 | return max; 39 | } 40 | 41 | function calcHourglassSum(arr, i, j) { 42 | return arr[i][j] + arr[i][j + 1] + arr[i][j + 2] 43 | + arr[i + 1][j + 1] 44 | + arr[i + 2][j] + arr[i + 2][j + 1] + arr[i + 2][j + 2] 45 | } -------------------------------------------------------------------------------- /arrays-strings/merge-strings-alternately.js: -------------------------------------------------------------------------------- 1 | /** 2 | * LeetCode | #1768 | Easy 3 | * 4 | * You are given two strings word1 and word2. Merge the strings by adding letters in alternating 5 | * order, starting with word1. If a string is longer than the other, append the additional 6 | * letters onto the end of the merged string. 7 | * Return the merged string. 8 | * 9 | * Constraints: 10 | * 1. 1 <= word1.length, word2.length <= 100 11 | * 2. word1 and word2 consist of lowercase English letters 12 | * 13 | */ 14 | 15 | /** 16 | * Time complexity: O(n) - Space complexity: O(1) 17 | * 18 | * @param {string} word1 19 | * @param {string} word2 20 | * @return {string} 21 | */ 22 | function mergeAlternately(word1, word2) { 23 | let mergedString = ''; 24 | let i = 0; 25 | 26 | while (i < word1.length && i < word2.length) { 27 | mergedString += `${word1[i]}${word2[i]}`; 28 | i++; 29 | } 30 | 31 | if (word1.length > word2.length) { 32 | mergedString += word1.substring(i); 33 | } else if (word2.length > word1.length) { 34 | mergedString += word2.substring(i); 35 | } 36 | 37 | return mergedString; 38 | }; 39 | -------------------------------------------------------------------------------- /arrays-strings/min-swaps-2.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Hackerrank 3 | * You are given an unordered array consisting of consecutive integers 4 | * [1, 2, 3, ..., n] without any duplicates. You are allowed to swap any two 5 | * elements. You need to find the minimum number of swaps required to sort the 6 | * array in ascending order. 7 | * 8 | * Constraints: 9 | * 1. 1 <= n <= 10^5 10 | * 2. 1 <= arr[i] <= n 11 | * 12 | * This solution got 40 points 13 | * Problem link: http://hr.gs/3apgt 14 | */ 15 | 16 | /** 17 | * @param {number[]} arr 18 | * @return {number} 19 | */ 20 | function minimumSwaps(arr) { 21 | let swaps = 0; 22 | if (arr.length === 1) { 23 | return swaps; 24 | } 25 | 26 | for (let i = 0; i < arr.length - 1; i++) { 27 | const element = arr[i]; 28 | if (element !== i + 1) { 29 | arr[i] = arr[element - 1]; 30 | arr[element - 1] = element; 31 | i--; 32 | swaps++; 33 | } 34 | } 35 | return swaps; 36 | } -------------------------------------------------------------------------------- /arrays-strings/non-constructible-change.js: -------------------------------------------------------------------------------- 1 | /** 2 | * AlgoExpert 3 | * Non-Constructible Change 4 | * 5 | * Given an array of positive integers representing the values of coins in your 6 | * possession, write a function that returns the minimum amount of change (the 7 | * minimum sum of money) that you cannot create. The given coins can have any 8 | * positive integer value and aren't necessarily unique (i.e., you can have 9 | * multiple coins of the same value). 10 | * 11 | * For example, if you're given coins = [1, 2, 5], the minimum amount of change 12 | * that you can't create is 4. If you're given no coins, the minimum amount of 13 | * change that you can't create is 1. 14 | */ 15 | 16 | /** 17 | * @param {number[]} coins 18 | * @returns {number} 19 | */ 20 | function nonConstructibleChange(coins) { 21 | // O(nlogn) Time - Sorting algorithm | O(1) Space 22 | let currentMaxChanges = 0; 23 | coins.sort((a, b) => a - b); 24 | 25 | for (const coin of coins) { 26 | const newPossibleChange = currentMaxChanges + 1; 27 | if (coin > newPossibleChange) { 28 | return newPossibleChange; 29 | } 30 | 31 | currentMaxChanges += coin; 32 | } 33 | 34 | return currentMaxChanges + 1; 35 | } -------------------------------------------------------------------------------- /arrays-strings/pdf-viewer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Hackerrank 3 | * Complete the designerPdfViewer function in the editor below. It should return an integer representing the size of the highlighted area. 4 | * designerPdfViewer has the following parameter(s): 5 | * - h: an array of integers representing the heights of each letter 6 | * - word: a string 7 | * 8 | * Constraints: 9 | * 1. 1 <= h[?] <= 7 where ? is an Englisher lowercase letter 10 | * 2. word contains no more thant 10 letters 11 | * 12 | * This solution got 20 points 13 | * Problem link: http://hr.gs/vnu 14 | */ 15 | 16 | /** 17 | * @param {number[]} h Height of each letter in [a-z] 18 | * @param {string} word The word to be evaluated to find the area to be highlighted 19 | * @return {number} Area to be highlighted 20 | */ 21 | function designerPdfViewer(h, word) { 22 | // Edge case 23 | if (!word || word.length === 0) { 24 | return 0; 25 | } 26 | const aCharCode = 'a'.charCodeAt(0); 27 | let maxHeight = -Infinity; 28 | for (let i = 0; i < word.length; i++) { 29 | const height = h[word.charCodeAt(i) % aCharCode]; 30 | if (height > maxHeight) { 31 | maxHeight = height; 32 | } 33 | } 34 | return maxHeight * word.length; 35 | } -------------------------------------------------------------------------------- /arrays-strings/permutation-in-string.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Leetcode, #567 3 | * Given two strings s1 and s2, write a function to return true if s2 contains 4 | * the permutation of s1. In other words, one of the first string's 5 | * permutations is the substring of the second string. 6 | * 7 | * Constraints: 8 | * 1. The input strings only contain lower case letters. 9 | * 2. The length of both given strings is in range [1, 10,000]. 10 | */ 11 | 12 | /** 13 | * @param {string} s1 14 | * @param {string} s2 15 | * @return {boolean} 16 | */ 17 | function checkInclusion(s1, s2) { 18 | const regex = new RegExp(`[${s1}]`); 19 | if (!s1 || !s2) { 20 | return false; 21 | } 22 | if (s1.length > s2.length) { 23 | return false; 24 | } 25 | if (!s2.match(regex)) { 26 | return false; 27 | } 28 | const map = new Map(); 29 | s1.split('').forEach(ch => { 30 | map.set(ch, map.has(ch) ? map.get(ch) + 1 : 1); 31 | }); 32 | const windowMap = new Map(); 33 | let matched = 0; 34 | let l = 0; 35 | let r = 0; 36 | while (r < s2.length && l <= r) { 37 | let lastLetter = s2.substr(r, 1); 38 | windowMap.set(lastLetter, windowMap.has(lastLetter) ? windowMap.get(lastLetter) + 1 : 1); 39 | if (map.has(lastLetter)) { 40 | if (map.get(lastLetter) === windowMap.get(lastLetter)) { 41 | matched++; 42 | if (matched === map.size) { 43 | return true; 44 | } 45 | } else if (windowMap.get(lastLetter) > map.get(lastLetter)) { 46 | let letter = s2.substr(l, 1); 47 | windowMap.set(letter, windowMap.get(letter) - 1); 48 | if (map.has(letter) && map.get(letter) - windowMap.get(letter) === 1) { 49 | matched--; 50 | } 51 | l++; 52 | } 53 | r++; 54 | } else { 55 | r++; 56 | l = r; 57 | matched = 0; 58 | windowMap.clear(); 59 | } 60 | } 61 | return false; 62 | }; -------------------------------------------------------------------------------- /arrays-strings/search-2d-matrix.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Leetcode, #240 3 | * Write an efficient algorithm that searches for a value in an m x n matrix. 4 | * This matrix has the following properties: 5 | * 1. Integers in each row are sorted in ascending from left to right. 6 | * 2. Integers in each column are sorted in ascending from top to bottom. 7 | */ 8 | /** 9 | * @param {number[][]} matrix 10 | * @param {number} target 11 | * @return {boolean} 12 | */ 13 | function searchMatrix(matrix, target) { 14 | if (matrix.length > 0 && matrix[0].length > 0) { 15 | let n = matrix[0].length - 1; 16 | let m = 0; 17 | while (n > -1 && m < matrix.length) { 18 | if (matrix[m][n] === target) { 19 | return true; 20 | } 21 | if (matrix[m][n] < target) { 22 | m++; 23 | } else { 24 | n--; 25 | } 26 | } 27 | } 28 | return false; 29 | }; -------------------------------------------------------------------------------- /arrays-strings/subarray-sum-equals-k.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Given an array of integers and an integer k, you need to find the total 3 | * number of continuous subarrays whose sum equals to k. 4 | * 5 | * Constraints: 6 | * 1. The length of the array is in range [1, 20,000]. 7 | * 2. The range of numbers in the array is [-1000, 1000] and the range of the 8 | * integer k is [-1e7, 1e7]. 9 | */ 10 | 11 | 12 | /** 13 | * @param {number[]} nums 14 | * @param {number} k 15 | * @return {number} 16 | */ 17 | const subarraySum = function(nums, k) { 18 | let result = 0; 19 | const n = nums.length; 20 | nums.forEach((num, index) => { 21 | if (num === k) { 22 | result++; 23 | } 24 | let j = index + 1; 25 | let accrued = num; 26 | while (j < n) { 27 | accrued += nums[j]; 28 | if (accrued === k) { 29 | result++; 30 | } 31 | j++; 32 | } 33 | }); 34 | return result; 35 | }; -------------------------------------------------------------------------------- /arrays-strings/three-number-sum.js: -------------------------------------------------------------------------------- 1 | /** 2 | * AlgoExpert 3 | * 4 | * Write a function that takes in a non-empty array of distinct integers and an 5 | * integer representing a target sum. The function should find all triplets in 6 | * the array that sum up to the target sum and return a two-dimensional array of 7 | * all these triplets. The numbers in each triplet should be ordered in ascending 8 | * order, and the triplets themselves should be ordered in ascending order with 9 | * respect to the numbers they hold. 10 | * 11 | * If no three numbers sum up to the target sum, the function should return an 12 | * empty array. 13 | */ 14 | 15 | /** 16 | * @param {number[]} array 17 | * @param {number} targetSum 18 | * @returns {array[][]} 19 | */ 20 | function threeNumberSum(array, targetSum) { 21 | // O(n^2) time | O(n) space 22 | 23 | // Edge case 24 | if (array.length < 3) { 25 | return []; 26 | } 27 | 28 | const triplets = []; 29 | array.sort((a, b) => a - b); 30 | 31 | const arrayLength = array.length; 32 | let i = 0; 33 | let l, r; 34 | while (i < arrayLength - 2) { 35 | const currentElement = array[i]; 36 | l = i + 1; 37 | r = arrayLength - 1; 38 | 39 | while (l < r) { 40 | const leftElement = array[l]; 41 | const rightElement = array[r]; 42 | const total = currentElement + leftElement + rightElement; 43 | if (total === targetSum) { 44 | triplets.push([currentElement, leftElement, rightElement]); 45 | l++; 46 | r--; 47 | } else if (total > targetSum) { 48 | r--; 49 | } else { 50 | l++; 51 | } 52 | } 53 | 54 | i++; 55 | } 56 | 57 | return triplets; 58 | } -------------------------------------------------------------------------------- /arrays-strings/tournament-winner.js: -------------------------------------------------------------------------------- 1 | /** 2 | * AlgoExpert 3 | * 4 | * Given an array of pairs representing the teams that have competed against each 5 | * other and an array containing the results of each competition, write a 6 | * function that returns the winner of the tournament. The input arrays are named 7 | * competitions and results, respectively. The competitions array has elements in 8 | * the form of [homeTeam, awayTeam], where each team is a string of at most 30 9 | * characters representing the name of the team. The results array contains information 10 | * about the winner of each corresponding competition in the competitions array. Specifically, 11 | * results[i] denotes the winner of competitions[i], where a 1 in the results array means 12 | * that the home team in the corresponding competition won and a 0 means that the 13 | * away team won. 14 | */ 15 | 16 | /** 17 | * @param {string[][]} competitions 18 | * @param {string[]} results 19 | * @returns {string} 20 | */ 21 | function tournamentWinner(competitions, results) { 22 | const pointsTable = new Map(); 23 | const winnerTable = { 24 | teamName: '', 25 | totalPoints: -Infinity 26 | }; 27 | 28 | // O(n) Extract the total points for every team 29 | competitions.forEach((competition, idx) => { 30 | const winnerTeam = competition[1 - results[idx]]; 31 | 32 | let newPoints = pointsTable.get(winnerTeam) || 0; 33 | newPoints += 3; 34 | pointsTable.set(winnerTeam, newPoints); 35 | 36 | if (newPoints > winnerTable.totalPoints) { 37 | winnerTable.teamName = winnerTeam; 38 | winnerTable.totalPoints = newPoints; 39 | } 40 | }); 41 | 42 | return winnerTable.teamName; 43 | } -------------------------------------------------------------------------------- /arrays-strings/two-sum.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Given an array of integers, return indices of the two numbers such that 3 | * they add up to a specific target. 4 | * 5 | * You may assume that each input would have exactly one solution, and you may 6 | * not use the same element twice. 7 | */ 8 | 9 | /** 10 | * @param {number[]} nums 11 | * @param {number} target 12 | * @return {number[]} 13 | */ 14 | const twoSum = function(nums, target) { 15 | let i = 0; 16 | const indices = [-1, -1]; 17 | while (nums[indices[0]] + nums[indices[1]] !== target && i < nums.length) { 18 | const currentVal = nums[i]; 19 | indices[0] = i; 20 | let done = false; 21 | const filteredNums = nums.slice(); 22 | filteredNums.splice(i, 1); 23 | let j = 0; 24 | while(!done && j < filteredNums.length) { 25 | if (currentVal + filteredNums[j] === target) { 26 | indices[1] = j >= i ? j + 1 : j; 27 | done = true; 28 | } else { 29 | j++; 30 | } 31 | } 32 | i++; 33 | } 34 | return indices; 35 | }; -------------------------------------------------------------------------------- /arrays-strings/validate-subsequence.js: -------------------------------------------------------------------------------- 1 | /** 2 | * AlgoExpert 3 | * 4 | * Given two non-empty arrays of integers, write a function that determines 5 | * whether the second array is a subsequence of the first one. 6 | * 7 | * A subsequence of an array is a set of numbers that aren't necessarily adjacent 8 | * in the array but that are in the same order as they appear in the array. For 9 | * instance, the numbers [1, 3, 4] form a subsequence of the array [1, 2, 3, 4], 10 | * and so do the numbers [2, 4]. Note that a single number in an array and the 11 | * array itself are both valid subsequences of the array. 12 | */ 13 | 14 | /** 15 | * @param {number[]} array 16 | * @param {number[]} sequence 17 | * @returns {boolean} 18 | */ 19 | function isValidSubsequence(array, sequence) { 20 | // Time: O(n), Space: O(1) 21 | let seqIdx = 0; 22 | let i = 0; 23 | 24 | while(i < array.length && seqIdx < sequence.length) { 25 | const arrElement = array[i]; 26 | const seqElement = sequence[seqIdx]; 27 | 28 | if (arrElement === seqElement) { 29 | seqIdx++; 30 | } 31 | 32 | i++; 33 | } 34 | 35 | return seqIdx === sequence.length; 36 | } 37 | -------------------------------------------------------------------------------- /dynamic-programming/longest-increasing-subsequence.js: -------------------------------------------------------------------------------- 1 | /** 2 | * LeetCode | #300 | Medium 3 | * 4 | * Given an integer array nums, return the length of the longest strictly increasing 5 | * subsequence. 6 | * 7 | * Constraints: 8 | * 1. 1 <= nums.length <= 2500 9 | * 2. -104 <= nums[i] <= 104 10 | * 11 | */ 12 | 13 | /** 14 | * Time complexity: O(n^2) - Space complexity: O(n) 15 | * 16 | * @param {number[]} nums 17 | * @return {number} 18 | */ 19 | function lengthOfLIS(nums) { 20 | const memo = []; 21 | 22 | for (let i = 0; i < nums.length; i++) { 23 | let longestSubSeq = 1; 24 | 25 | for (let j = 0; j < i; j++) { 26 | if (nums[i] > nums[j] && memo[j] + 1 > longestSubSeq) { 27 | longestSubSeq = memo[j] + 1; 28 | } 29 | } 30 | 31 | memo[i] = longestSubSeq; 32 | } 33 | 34 | return Math.max(...memo); 35 | } 36 | -------------------------------------------------------------------------------- /graphs/bfs-shortest-reach.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Hackerrank 3 | * Consider an undirected graph where each edge is the same weight. Each of the 4 | * nodes is labeled consecutively. You will be given a number of queries. For 5 | * each query, you will be given a list of edges describing an undirected graph. 6 | * After you create a representation of the graph, you must determine and report 7 | * the shortest distance to each of the other nodes from a given starting 8 | * position using the breadth-first search algorithm (BFS). Distances are to be 9 | * reported in node number order, ascending. If a node is unreachable, print -1 10 | * for that node. Each of the edges weighs 6 units of distance. 11 | * 12 | * Constraints: 13 | * 1. 1 <= Q <= 10 14 | * 2. 2 <= n <= 1000 15 | * 3. 1 <= m <= (n*(n-1)) / 2 16 | * 4. 1 <= u,v,s <= n 17 | * 18 | * This solution got 55 points 19 | * Problem link: http://hr.gs/fdaaad 20 | */ 21 | 22 | // Complete the bfs function below. 23 | function bfs(n, m, edges, s) { 24 | const EDGE_WEIGHT = 6; 25 | const graph = buildGraph(edges); 26 | const start = graph.get(s); 27 | const distances = Array(n).fill(-1); 28 | 29 | /* Edge case - Start node is not connected to any other node. 30 | * In that case, not perfom the BFS 31 | */ 32 | if (start) { 33 | const queue = new LinkedList(new LinkedListNode(start)); 34 | distances[start.id - 1] = 0; 35 | while (queue.size > 0) { 36 | const node = queue.poll().data; 37 | node.neighbors.forEach(neighbor => { 38 | if (distances[neighbor.id - 1] === -1) { 39 | distances[neighbor.id - 1] = distances[node.id - 1] + EDGE_WEIGHT; 40 | queue.insert(new LinkedListNode(neighbor)); 41 | } 42 | }); 43 | } 44 | } 45 | 46 | distances.splice(s - 1, 1); 47 | return distances; 48 | } 49 | 50 | /** 51 | * Build the graph based on the edges array representation 52 | * @param {number[][]} edges - Array of graph edges 53 | */ 54 | function buildGraph(edges) { 55 | const graph = new Map(); 56 | edges.forEach(edge => { 57 | const firstNodeId = edge[0]; 58 | const secondNodeId = edge[1]; 59 | 60 | let firstNode; 61 | if (!graph.has(firstNodeId)) { 62 | firstNode = new Node(firstNodeId); 63 | graph.set(firstNodeId, firstNode); 64 | } else { 65 | firstNode = graph.get(firstNodeId); 66 | } 67 | 68 | let secondNode; 69 | if (!graph.has(secondNodeId)) { 70 | secondNode = new Node(secondNodeId); 71 | graph.set(secondNodeId, secondNode); 72 | } else { 73 | secondNode = graph.get(secondNodeId); 74 | } 75 | 76 | firstNode.neighbors.add(secondNode); 77 | secondNode.neighbors.add(firstNode); 78 | }); 79 | return graph; 80 | } 81 | 82 | class Node { 83 | constructor(id) { 84 | this.id = id; 85 | this.neighbors = new Set(); 86 | } 87 | } 88 | 89 | class LinkedListNode { 90 | constructor(data, next = null) { 91 | this.data = data; 92 | this.next = next; 93 | } 94 | } 95 | 96 | class LinkedList { 97 | constructor(root = null) { 98 | this.root = root; 99 | this.rear = root; 100 | this.size = root ? 1 : 0; 101 | } 102 | 103 | /** 104 | * Remove the head/first node of the linked list 105 | */ 106 | poll() { 107 | if (this.root) { 108 | const node = this.root; 109 | this.root = this.root.next; 110 | if (this.rear === node) { 111 | this.rear = null; 112 | } 113 | this.size--; 114 | return node; 115 | } 116 | } 117 | 118 | /** 119 | * Insert a new node into the linked list 120 | * @param {LinkedListNode} node - Node to be inserted 121 | */ 122 | insert(node) { 123 | if (this.root) { 124 | this.rear.next = node; 125 | } else { 126 | this.root = node; 127 | } 128 | this.rear = node; 129 | this.size++; 130 | } 131 | } -------------------------------------------------------------------------------- /graphs/snakes-ladders.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Hackerrank 3 | * Markov takes out his Snakes and Ladders game, stares at the board and 4 | * wonders: "If I can always roll the die to whatever number I want, what would 5 | * be the least number of rolls to reach the destination?" 6 | * Rules The game is played with a cubic die of 6 faces numbered 1 to 6. 7 | * 8 | * Constraints: 9 | * 1. 1 <= t <= 10 10 | * 2. 2 <= n,m <= 15 11 | * 3. The board is always 10x10 with squares numbered 1 to 100. 12 | * 4. Neither square 1 nor square 100 will be the starting point of a ladder or snake. 13 | * 5. A square will have at most one endpoint from either a snake or a ladder. 14 | * 15 | * This solution got 50 points 16 | * Problem link: http://hr.gs/bbddc 17 | */ 18 | 19 | // Complete the quickestWayUp function below. 20 | function quickestWayUp(ladders, snakes) { 21 | const BOARD_SIZE = 100; 22 | const MAX_DIE = 6; 23 | 24 | // Build the first state of the graph 25 | const adjList = new Map(); 26 | for (let i = 1; i <= BOARD_SIZE; i++) { 27 | let neighbors = BOARD_SIZE - i >= 6 ? 6 : BOARD_SIZE - i; 28 | adjList.set( 29 | i, 30 | new Set(new Array(neighbors).fill(i + 1).map((val, idx) => val + idx)) 31 | ); 32 | } 33 | 34 | // Replace ladders vertexes 35 | ladders.forEach(ladder => { 36 | adjList.delete(ladder[0]); 37 | let i = ladder[0] - 1; 38 | let count = 0; 39 | while (i > 0 && count < MAX_DIE) { 40 | const neighbors = adjList.get(i); 41 | if (neighbors) { 42 | neighbors.delete(ladder[0]); 43 | neighbors.add(ladder[1]); 44 | } 45 | count++; 46 | i--; 47 | } 48 | }); 49 | 50 | // Replace snakes vertexes 51 | snakes.forEach(snake => { 52 | adjList.delete(snake[0]); 53 | let i = snake[0] - 1; 54 | let count = 0; 55 | while (i > 0 && count < MAX_DIE) { 56 | const neighbors = adjList.get(i); 57 | if (neighbors) { 58 | neighbors.delete(snake[0]); 59 | neighbors.add(snake[1]); 60 | } 61 | i--; 62 | count++; 63 | } 64 | }); 65 | 66 | // BFS 67 | const queue = new LinkedList(new LinkedListNode(1)); 68 | const distances = new Array(BOARD_SIZE + 1).fill(-1); 69 | distances[1] = 0; 70 | while (queue.size > 0) { 71 | const node = queue.poll().data; 72 | const neighbors = adjList.get(node); 73 | neighbors.forEach(neighbor => { 74 | if (distances[neighbor] === -1) { 75 | distances[neighbor] = distances[node] + 1; 76 | queue.insert(new LinkedListNode(neighbor)); 77 | } 78 | }) 79 | } 80 | 81 | return distances[100]; 82 | } 83 | 84 | class LinkedListNode { 85 | constructor(data, next = null) { 86 | this.data = data; 87 | this.next = next; 88 | } 89 | } 90 | 91 | class LinkedList { 92 | constructor(root = null) { 93 | this.root = root; 94 | this.rear = root; 95 | this.size = root ? 1 : 0; 96 | } 97 | 98 | /** 99 | * Remove the head/first node of the linked list 100 | */ 101 | poll() { 102 | if (this.root) { 103 | const node = this.root; 104 | this.root = this.root.next; 105 | if (this.rear === node) { 106 | this.rear = null; 107 | } 108 | this.size--; 109 | return node; 110 | } 111 | } 112 | 113 | /** 114 | * Insert a new node into the linked list 115 | * @param {LinkedListNode} node - Node to be inserted 116 | */ 117 | insert(node) { 118 | if (this.root) { 119 | this.rear.next = node; 120 | } else { 121 | this.root = node; 122 | } 123 | this.rear = node; 124 | this.size++; 125 | } 126 | } -------------------------------------------------------------------------------- /hash-maps/colorful-number.js: -------------------------------------------------------------------------------- 1 | /** 2 | * InterviewBit 3 | * For Given Number N find if its COLORFUL number or not 4 | * 5 | * This solution got 60 points 6 | * Problem link: https://www.interviewbit.com/problems/colorful-number 7 | */ 8 | 9 | /** 10 | * Check if a number is colorful 11 | * @param {number} A Number to be checked 12 | */ 13 | function colorful(A) { 14 | const digits = getDigits(A); 15 | const prods = new Set(); 16 | let chunkSize = 1; 17 | while (chunkSize <= digits.length) { 18 | let i = 0; 19 | while(i + chunkSize <= digits.length) { 20 | const getProd = digits.slice(i, i + chunkSize) 21 | .reduce((a, b) => a * b, 1); 22 | if (prods.has(getProd)) { 23 | return 0; 24 | } else { 25 | prods.add(getProd); 26 | } 27 | i++; 28 | } 29 | chunkSize++; 30 | } 31 | return 1; 32 | } 33 | 34 | /** 35 | * Get digits of a numnber 36 | * @param {number} n Number to be decomposed 37 | */ 38 | function getDigits(n) { 39 | const digits = []; 40 | while (n > 0) { 41 | digits.push(n % 10) 42 | n = parseInt(n / 10); 43 | } 44 | return digits; 45 | } -------------------------------------------------------------------------------- /hash-maps/ice-cream-parlor.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Hackerrank 3 | * Sunny and Johnny like to pool their money and go to the ice cream parlor. 4 | * Johnny never buys the same flavor that Sunny does. The only other rule they 5 | * have is that they spend all of their money. 6 | * Given a list of prices for the flavors of ice cream, select the two that 7 | * will cost all of the money they have. 8 | * 9 | * Constraints: 10 | * 1. 2 <= m <= 10^4 (The integer m, the amount of money they have pooled) 11 | * 2. 2 <= n <= 10^4 (The integer n, the number of flavors offered at the time) 12 | * 3. 1 <= cost[i] <= 10^4, i ∈ [1, n] 13 | * 14 | * This solution got 30 points 15 | * Problem link: http://hr.gs/eez 16 | */ 17 | 18 | // Complete the icecreamParlor function below. 19 | /** 20 | * 21 | * @param {number} m The total amount of money pooled 22 | * @param {number[]} arr The list of ice creams with their price 23 | */ 24 | function icecreamParlor(m, arr) { 25 | const icecreamIdx = new Map(); 26 | // Store the original indices 27 | arr.forEach((n, i) => { 28 | if (icecreamIdx.has(n)) { 29 | icecreamIdx.get(n).push(i + 1); 30 | } else { 31 | icecreamIdx.set(n, [i + 1]); 32 | } 33 | }); 34 | // Sort array in order to use binary search 35 | arr.sort((a, b) => a - b); 36 | let i = 0; 37 | let price = arr[0]; 38 | while (i < arr.length && price < m) { 39 | const slicedArray = arr.slice(i); 40 | // Use binary search to look for a value that meet the criteria 41 | const complementIndex = binarySearch( 42 | m - price, 0, slicedArray.length - 1, slicedArray 43 | ); 44 | if (complementIndex != null) { 45 | // Sort and return the response 46 | return [ 47 | icecreamIdx.get(price).pop(), 48 | icecreamIdx.get(slicedArray[complementIndex]).pop() 49 | ].sort((a, b) => a - b); 50 | } 51 | i++; 52 | price = arr[i]; 53 | } 54 | return []; 55 | } 56 | 57 | /** 58 | * Look for an element in array by binary search 59 | * @param {numner} val The value to look for 60 | * @param {number} l Left limit 61 | * @param {number} r Right limit 62 | * @param {number[]} arr The array where the search will be executed 63 | */ 64 | function binarySearch(val, l, r, arr) { 65 | if (l > r) { 66 | return null; 67 | } 68 | const mid = l + Math.floor((r - l) / 2); 69 | if (arr[mid] === val) { 70 | return mid; 71 | } 72 | if(arr[mid] > val) { 73 | return binarySearch(val, l, mid - 1, arr); 74 | } else { 75 | return binarySearch(val, mid + 1, r, arr); 76 | } 77 | } -------------------------------------------------------------------------------- /hash-maps/longest-harmonius-subsequence.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Leetcode, #594 3 | * 4 | * We define a harmounious array as an array where the difference between its 5 | * maximum value and its minimum value is exactly 1. 6 | * 7 | * Now, given an integer array, you need to find the length of its longest 8 | * harmonious subsequence among all its possible subsequences. 9 | * 10 | * Constraints: 11 | * 1. The length of the input array will not exceed 20,000. 12 | */ 13 | 14 | /** 15 | * @param {number[]} nums 16 | * @return {number} 17 | */ 18 | function findLHS(nums) { 19 | let longest = 0; 20 | if (nums.length > 1) { 21 | const map = new Map(); 22 | nums.forEach(number => { 23 | const cValue = map.has(number) ? map.get(number) + 1 : 1; 24 | map.set(number, cValue); 25 | if (map.has(number + 1)) { 26 | longest = Math.max(longest, cValue + map.get(number + 1)); 27 | } 28 | if (map.has(number - 1)) { 29 | longest = Math.max(longest, cValue + map.get(number - 1)); 30 | } 31 | }); 32 | } 33 | return longest; 34 | }; -------------------------------------------------------------------------------- /hash-maps/minimum-window-substring.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Given a string S and a string T, find the minimum window in S which will 3 | * contain all the characters in T in complexity O(n). 4 | * 5 | * Note: 6 | * 1. If there is no such window in S that covers all characters in T, return 7 | * the empty string "". 8 | * 2. If there is such window, you are guaranteed that there will always be 9 | * only one unique minimum window in S. 10 | */ 11 | 12 | /** 13 | * @param {string} s 14 | * @param {string} t 15 | * @return {string} 16 | */ 17 | const minWindow = function(s, t) { 18 | const regex = new RegExp(`[${t}]`, 'g'); 19 | if (!s || !t) { 20 | return ''; 21 | } 22 | 23 | if (t.length > s.length) { 24 | return ''; 25 | } 26 | 27 | if (s == t) { 28 | return s; 29 | } 30 | 31 | if (t.length === 1 && s.includes(t)) { 32 | return t; 33 | } 34 | 35 | if (!s.match(regex)) { 36 | return ''; 37 | } 38 | 39 | const tMap = new Map(); 40 | t.split('').forEach(ch => { 41 | if (!tMap.has(ch)) { 42 | tMap.set(ch, 0); 43 | } 44 | tMap.set(ch, tMap.get(ch) + 1); 45 | }); 46 | let window = ''; 47 | let l = 0; 48 | let r = 0; 49 | let sub = s.substr(l, r + 1); 50 | let letter = sub.substr(-1); 51 | const tmpMap = new Map(); 52 | tmpMap.set(letter, 1); 53 | let matched = 0; 54 | if (tMap.has(letter) && tmpMap.get(letter) === tMap.get(letter)) { 55 | matched++; 56 | } 57 | while (l < s.length && r < s.length) { 58 | if (matched === tMap.size) { 59 | if (!window || sub.length < window.length) { 60 | window = sub; 61 | } 62 | letter = sub.substr(0, 1); 63 | l++; 64 | sub = s.substr(l, r - l + 1); 65 | tmpMap.set(letter, tmpMap.get(letter) - 1); 66 | if (tMap.has(letter) && tmpMap.get(letter) < tMap.get(letter)) { 67 | matched--; 68 | } 69 | } else { 70 | r++; 71 | sub = s.substr(l, r - l + 1); 72 | letter = sub.substr(-1); 73 | if (!tmpMap.has(letter)) { 74 | tmpMap.set(letter, 0); 75 | } 76 | tmpMap.set(letter, tmpMap.get(letter) + 1); 77 | if (tMap.has(letter) && tmpMap.get(letter) === tMap.get(letter)) { 78 | matched++; 79 | } 80 | } 81 | } 82 | return window; 83 | }; -------------------------------------------------------------------------------- /hash-maps/mock-interview.js: -------------------------------------------------------------------------------- 1 | function findMissing(arr, arr2) { 2 | const set = new Set(arr); 3 | const missingValue = null; 4 | let i = 0; 5 | while (i < arr2.length && !missingValue) { 6 | if (!set.has(arr2[i])) { 7 | missingValue = arr2[i]; 8 | } 9 | } 10 | return missingValue; 11 | } 12 | 13 | console.log('findMissing', findMissing([1,3,5], [8,1,5,3])); -------------------------------------------------------------------------------- /hash-maps/unique-number-occurrences.js: -------------------------------------------------------------------------------- 1 | /** 2 | * LeetCode | #1207 | Easy 3 | * 4 | * Given an array of integers arr, return true if the number of occurrences of each 5 | * value in the array is unique or false otherwise. 6 | * 7 | * Constraints: 8 | * 1. 1 <= arr.length <= 1000 9 | * 2. -1000 <= arr[i] <= 1000 10 | * 11 | */ 12 | 13 | /** 14 | * Time complexity: O(n) - Space complexity: O(n)? 15 | * 16 | * @param {number[]} arr 17 | * @return {boolean} 18 | */ 19 | function uniqueOccurrences(arr) { 20 | if (arr.length === 1) { 21 | return true; 22 | } 23 | 24 | const occurrencesMap = new Map(); 25 | for (const num of arr) { 26 | const occurrences = occurrencesMap.has(num) 27 | ? occurrencesMap.get(num) + 1 28 | : 1; 29 | 30 | occurrencesMap.set(num, occurrences); 31 | } 32 | const occurrencesSet = new Set([...occurrencesMap.values()]); 33 | 34 | return occurrencesSet.size === occurrencesMap.size; 35 | }; 36 | -------------------------------------------------------------------------------- /lists/detect-cycle-linked-list.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Hackerrank 3 | * A linked list is said to contain a cycle if any node is visited more than 4 | * once while traversing the list. Complete the function provided for you in 5 | * your editor. It has one parameter: a pointer to a Node object named that 6 | * points to the head of a linked list. Your function must return a boolean 7 | * denoting whether or not there is a cycle in the list. If there is a cycle, 8 | * return true; otherwise, return false. 9 | * 10 | * Constraints: 11 | * 1. 0 <= list size <= 1000 12 | * 13 | * This solution got 5 points 14 | * Problem link: http://hr.gs/ffddcc 15 | */ 16 | 17 | /* 18 | * For your reference: 19 | * 20 | * SinglyLinkedListNode { 21 | * int data; 22 | * SinglyLinkedListNode next; 23 | * } 24 | * 25 | */ 26 | 27 | /** 28 | * @param {SinglyLinkedListNode} head The root of the linked list 29 | * @return {boolean} If there's a cycle in the linked list 30 | */ 31 | function hasCycle(head) { 32 | // Edge case 33 | if (!head) { 34 | return false; 35 | } 36 | const visited = new Set(); 37 | let node = head; 38 | while (node) { 39 | if (visited.has(node)) { 40 | return true; 41 | } else { 42 | visited.add(node); 43 | } 44 | node = node.next; 45 | } 46 | return false; 47 | } -------------------------------------------------------------------------------- /lists/insert-node-linked-list.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Hackerrank 3 | * You’re given the pointer to the head node of a linked list, an integer to 4 | * add to the list and the position at which the integer must be inserted. 5 | * Create a new node with the given integer, insert this node at the desired 6 | * position and return the head node. 7 | * 8 | * Constraints: 9 | * 1. 1 <= n <= 1000 10 | * 2. 1 <= SingleLinkedListNode[i].data <= 1000 11 | * 3. 0 <= position <= n 12 | * 13 | * This solution got 5 points 14 | * Problem link: http://hr.gs/vnu 15 | */ 16 | 17 | /* 18 | * For your reference: 19 | * 20 | * SinglyLinkedListNode { 21 | * int data; 22 | * SinglyLinkedListNode next; 23 | * } 24 | * 25 | */ 26 | 27 | /** 28 | * @param {SinglyLinkedListNode} head The root of the linked list 29 | * @param {number} data The new data to be added to the linked list 30 | * @param {number} position The index position in which the new data will be placed on 31 | * @return {SinglyLinkedListNode} The root of the linked list 32 | */ 33 | function insertNodeAtPosition(head, data, position) { 34 | // Edge case 35 | if (!head) { 36 | return { data }; 37 | } 38 | let node = head; 39 | let found = false; 40 | let i = 0; 41 | while (node.next && !found) { 42 | if (i + 1 === position && node.next) { 43 | const prev = node.next; 44 | node.next = { data, next: prev }; 45 | found = true; 46 | } 47 | node = node.next; 48 | i++; 49 | } 50 | return head; 51 | } -------------------------------------------------------------------------------- /recursion/change-foreign-currency.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Facebook prep: Change in a Foreign Currency 3 | * Given a list of the available denominations, determine if it's possible to 4 | * receive exact change for an amount of money targetMoney. Both the 5 | * denominations and target amount will be given in generic units of that 6 | * currency. 7 | * 8 | * Constraints: 9 | * 1. 1 <= |denominations| <= 100 10 | * 2. 1 <= denominations[i] <= 10000 11 | * 3. 1 <= targetMoney <= 1000000 12 | */ 13 | 14 | /** 15 | * 16 | * @param {number} targetMoney - The target money to check if there's an exact change for 17 | * @param {number[]} denominations - All possible denomination changes sorted in ascending order 18 | */ 19 | function canGetExactChange(targetMoney, denominations) { 20 | for (let i = 0; i < denominations.length; i++) { 21 | const denomination = denominations[i]; 22 | if (targetMoney < denomination) { 23 | return false; 24 | } 25 | 26 | const remaining = targetMoney % denomination; 27 | if (remaining === 0 || canGetExactChange(remaining, denominations)) { 28 | return true; 29 | } 30 | } 31 | return false; 32 | } -------------------------------------------------------------------------------- /recursion/fibonacci-with-dp.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This is the solution of Fibonnaci using DP 3 | */ 4 | 5 | /** 6 | * 7 | * @param {number} n 8 | * @param {number[]} dp 9 | * @return {number} 10 | */ 11 | function fibonacciDp(n) { 12 | const dp = [0, 1]; 13 | if (n < 2) { 14 | return dp[n + 1]; 15 | } 16 | 17 | if (n === 1) { 18 | return 1 19 | } 20 | 21 | for (let i = 2; i <= n; i++) { 22 | dp[i] = dp[i - 1] + dp[i - 2]; 23 | } 24 | 25 | return dp[n]; 26 | } -------------------------------------------------------------------------------- /recursion/minimum-diff-sum.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Problem description: 3 | * Partition a set into two subsets such that the difference of subset sums is 4 | * minimum. 5 | */ 6 | function findMinimumDiff(arr, remaining, accrued, size, maxSize) { 7 | if (size + 1 <= maxSize) { 8 | remaining.forEach((n, index) => { 9 | const cloneArr = remaining.slice(); 10 | cloneArr.splice(index, 1); 11 | findMinimumDiff([...arr, n], cloneArr, accrued + n, size + 1, maxSize); 12 | }); 13 | } 14 | if (arr.length > 0) { 15 | min = Math.min( 16 | Math.abs(accrued - remaining.reduce((a, b) => a + b, 0)), min 17 | ); 18 | } 19 | var min = Infinity; 20 | findMinimumDiff([], A, 0, 1, A.length - 1); 21 | console.log('r/', min); 22 | return min; 23 | } 24 | -------------------------------------------------------------------------------- /sliding-window/max-avg-subarray.js: -------------------------------------------------------------------------------- 1 | /** 2 | * LeetCode | #643 | Easy 3 | * 4 | * You are given an integer array nums consisting of n elements, and an integer k. 5 | * Find a contiguous subarray whose length is equal to k that has the maximum average value and return this value. 6 | * Any answer with a calculation error less than 10-5 will be accepted. 7 | * 8 | * Constraints: 9 | * 1. n == nums.length 10 | * 2. 1 <= k <= n <= 10^5 11 | * 3. -10^4 <= nums[i] <= 10^4 12 | * 13 | */ 14 | 15 | /** 16 | * Time complexity: O(n) - Space complexity: O(1) 17 | * 18 | * @param {number[]} nums 19 | * @param {number} k 20 | * @return {number} 21 | */ 22 | function findMaxAverage(nums, k) { 23 | let maxAvg; 24 | let subarraySum = 0; 25 | for (let i = 0; i < k; i++) { 26 | subarraySum += nums[i]; 27 | } 28 | maxAvg = subarraySum / k; 29 | 30 | for (let i = 1; i + k <= nums.length; i++) { 31 | subarraySum += nums[i - 1] * -1 + nums[i + k - 1]; 32 | const subarrayAvg = subarraySum / k; 33 | 34 | if (subarrayAvg > maxAvg) { 35 | maxAvg = subarrayAvg; 36 | } 37 | } 38 | 39 | return maxAvg; 40 | } 41 | -------------------------------------------------------------------------------- /sorting/insertion-sort-2.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Hackerrank 3 | * In this challenge, print the array after each iteration of the insertion 4 | * sort, i.e., whenever the next element has been inserted at its correct 5 | * position. Since the array composed of just the first element is already 6 | * sorted, begin printing after placing the second element. 7 | * 8 | * Constraints: 9 | * 1. 1 <= n <= 1000 10 | * 2. -10000 <= arr[i] <= 10000.0 <= i < n 11 | * 3. All the characters in the sequence: {, }, [, ], (, ) 12 | * 13 | * This solution got 30 points 14 | * Problem link: http://hr.gs/e4v 15 | */ 16 | 17 | // Complete the insertionSort2 function below. 18 | /** 19 | * 20 | * @param {number} n 21 | * @param {number[]} arr 22 | */ 23 | function insertionSort2(n, arr) { 24 | // Edge case 25 | if (n === 1) { 26 | return arr; 27 | } 28 | 29 | let i = 1; 30 | while (i < arr.length) { 31 | const element = arr[i]; 32 | let j = i - 1; 33 | while(j >= 0 && arr[j] > element) { 34 | arr[j + 1] = arr[j]; 35 | j--; 36 | } 37 | arr[j + 1] = element; 38 | i++; 39 | console.log(arr.join(' ')); 40 | } 41 | 42 | return arr; 43 | } -------------------------------------------------------------------------------- /sorting/quicksort-2.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Hackerrank 3 | * In this challenge, print your array every time your partitioning method 4 | * finishes, i.e. whenever two subarrays, along with the pivot, are merged 5 | * together. The first element in a sub-array should be used as a pivot. 6 | * Partition the left side before partitioning the right side. 7 | * The pivot should be placed between sub-arrays while merging them. 8 | * Array of length or less will be considered sorted, and there is no need to 9 | * sort or to print them. 10 | * 11 | * Constraints: 12 | * 1. 1 <= n <= 1000 13 | * 2. -1000 <= x <= 1000, x ∈ arr 14 | * 3. All the characters in the sequence: {, }, [, ], (, ) 15 | * 16 | * This solution got 30 points 17 | * Problem link: http://hr.gs/fffdff 18 | */ 19 | 20 | /** 21 | * 22 | * @param {string} input Custom input of Hackerrank 23 | */ 24 | function processData(input) { 25 | const arr = input.split('\n')[1] 26 | .split(' ') 27 | .map(el => +el); 28 | if (arr.length < 2) { 29 | return; 30 | } 31 | quickSort(arr); 32 | } 33 | 34 | /** 35 | * 36 | * @param {number[]} arr The array/subarray to be sorted 37 | */ 38 | function quickSort(arr) { 39 | if (arr.length > 1) { 40 | let left = []; 41 | let right = []; 42 | const pivot = arr[0]; 43 | partition(arr.slice(1), left, right, pivot); 44 | left = quickSort(left); 45 | right = quickSort(right); 46 | const merged = [...left, pivot, ...right] 47 | console.log(merged.join(' ')); 48 | return merged; 49 | } else { 50 | return arr; 51 | } 52 | } 53 | 54 | /** 55 | * 56 | * @param {number[]} arr Original array 57 | * @param {number[]} left All numbers lower than pivot will be placed here 58 | * @param {number[]} right All numbers greater or queal than pivot will be placed here 59 | * @param {number} pivot 60 | */ 61 | function partition(arr, left, right, pivot) { 62 | arr.forEach(el => { 63 | if (el >= pivot) { 64 | right.push(el); 65 | } else { 66 | left.push(el); 67 | } 68 | }); 69 | } 70 | 71 | /* In place 72 | function quickSort(arr, low, high) { 73 | if (low < high) { 74 | const sortedIdx = partition(arr, low, high); 75 | quickSort(arr, low, sortedIdx - 1); 76 | quickSort(arr, sortedIdx + 1, high); 77 | } 78 | } 79 | */ 80 | /* in place 81 | function partition(arr, low, high) { 82 | let i = low; 83 | let j = high; 84 | const pivot = low; 85 | while (i < j) { 86 | while(arr[i] <= arr[pivot]) { 87 | i++; 88 | } 89 | while(arr[j] > arr[pivot]) { 90 | j--; 91 | } 92 | if (i < j) { 93 | const iVal = arr[i]; 94 | arr[i] = arr[j]; 95 | arr[j] = iVal; 96 | } 97 | } 98 | const copy = arr[pivot]; 99 | arr[pivot] = arr[j]; 100 | arr[j] = copy; 101 | return j; 102 | } 103 | */ -------------------------------------------------------------------------------- /stacks-queues/balanced-bracket.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Hackerrank 3 | * A bracket is considered to be any one of the following characters: (, ), {, 4 | * }, [, or ]. Two brackets are considered to be a matched pair if the an 5 | * opening bracket (i.e., (, [, or {) occurs to the left of a closing bracket 6 | * (i.e., ), ], or }) of the exact same type. There are three types of matched 7 | * pairs of brackets: [], {}, and (). 8 | * Given strings of brackets, determine whether each sequence of brackets is 9 | * balanced. If a string is balanced, return YES. Otherwise, return NO. 10 | * 11 | * Constraints: 12 | * 1. 0 <= n <= 10000 13 | * 2. 1 <= |s| <= 10000 14 | * 3. All the characters in the sequence: {, }, [, ], (, ) 15 | * 16 | * This solution got 25 points 17 | * Problem link: http://hr.gs/babead 18 | */ 19 | 20 | /** 21 | * @param {string} s The string which will be checked 22 | * @return {string} 'YES' or 'NO' 23 | */ 24 | // Complete the isBalanced function below. 25 | function isBalanced(s) { 26 | // Edge cases 27 | if (s.length === 0 || s.length % 2 === 1) { 28 | return 'NO'; 29 | } 30 | const stack = [s.charAt(0)]; 31 | for (const ch of s.slice(1)) { 32 | if (isClose(ch)) { 33 | const last = stack.pop(); 34 | if (!isMatched(last, ch)) { 35 | return 'NO'; 36 | } 37 | } else { 38 | stack.push(ch); 39 | } 40 | } 41 | return stack.length === 0 ? 'YES' : 'NO'; 42 | } 43 | 44 | /** 45 | * @param {string} ch - Character to be compared with 46 | * @return {boolean} 47 | */ 48 | function isClose(ch) { 49 | return /\}|\)|\]/i.test(ch); 50 | } 51 | 52 | /** 53 | * @param {string} bracket - The first operator 54 | * @param {String} next - The next operator 55 | * @return {boolean} 56 | */ 57 | function isMatched(bracket, next) { 58 | switch (bracket) { 59 | case '(': 60 | return next === ')'; 61 | case '[': 62 | return next === ']'; 63 | case '{': 64 | return next === '}'; 65 | default: 66 | return false; 67 | } 68 | } -------------------------------------------------------------------------------- /stacks-queues/number-recent-calls.js: -------------------------------------------------------------------------------- 1 | /** 2 | * LeetCode | #933 | Easy 3 | * 4 | * You have a RecentCounter class which counts the number of recent requests within a certain time frame. 5 | * 6 | * Implement the RecentCounter class: 7 | * - RecentCounter() Initializes the counter with zero recent requests. 8 | * - int ping(int t) Adds a new request at time t, where t represents some time in milliseconds, and returns 9 | * the number of requests that has happened in the past 3000 milliseconds (including the new request). 10 | * Specifically, return the number of requests that have happened in the inclusive range [t - 3000, t]. 11 | * 12 | * It is guaranteed that every call to ping uses a strictly larger value of t than the previous call. 13 | * 14 | * Constraints: 15 | * - 1 <= t <= 10^9 16 | * - Each test case will call ping with strictly increasing values of t. 17 | * - At most 10^4 calls will be made to ping. 18 | * 19 | */ 20 | 21 | 22 | /** 23 | * Solution 1 (slowest -- resembling a queue with "shift" which is slow) 24 | * Time Complexity: O(n) - Space complexity: ? 25 | */ 26 | 27 | const RecentCounter = function () { 28 | this.recentReqsQueue = []; 29 | }; 30 | 31 | /** 32 | * @param {number} t 33 | * @return {number} 34 | */ 35 | RecentCounter.prototype.ping = function (t) { 36 | this.recentReqsQueue.push(t); 37 | const minRangeVal = Math.max(t - 3000, 0); 38 | 39 | while (this.recentReqsQueue.length > 0 && this.recentReqsQueue[0] < minRangeVal) { 40 | this.recentReqsQueue.shift(); 41 | } 42 | 43 | return this.recentReqsQueue.length; 44 | }; 45 | 46 | /** 47 | * Solution 2 (fastest -- resembling a queue behaviour by using a pointer) 48 | * Time Complexity: O(n) - Space complexity: O(n) 49 | */ 50 | 51 | const RecentCounter2 = function () { 52 | this.i = 0; 53 | this.recentReqsQueue = []; 54 | }; 55 | 56 | /** 57 | * @param {number} t 58 | * @return {number} 59 | */ 60 | RecentCounter2.prototype.ping = function (t) { 61 | this.recentReqsQueue.push(t); 62 | const minRangeVal = Math.max(t - 3000, 0); 63 | 64 | while (this.recentReqsQueue.length > 0 && this.recentReqsQueue[this.i] < minRangeVal) { 65 | this.i++; 66 | } 67 | 68 | return this.recentReqsQueue.length - this.i; 69 | }; 70 | 71 | /** 72 | * Your RecentCounter object will be instantiated and called as such: 73 | * var obj = new RecentCounter() 74 | * var param_1 = obj.ping(t) 75 | */ 76 | -------------------------------------------------------------------------------- /stacks-queues/queue-2-stacks.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Hackerrank 3 | * A queue is an abstract data type that maintains the order in which elements 4 | * were added to it, allowing the oldest elements to be removed from the front 5 | * and new elements to be added to the rear. This is called a First-In-First-Out 6 | * (FIFO) data structure because the first element added to the queue (i.e., the 7 | * one that has been waiting the longest) is always the first one to be removed. 8 | * 9 | * In this challenge, you must first implement a queue using two stacks. Then 10 | * process q queries, where each query is one of the following types: 11 | * 12 | * 1 x: Enqueue element x into the end of the queue. 13 | * 2: Dequeue the element at the front of the queue. 14 | * 3: Print the element at the front of the queue. 15 | * 16 | * Constraints: 17 | * 1. 1 <= q <= 10^5 18 | * 2. 1 <= type <= 3 19 | * 3. 1 <= |x| <= 10^9 20 | * 21 | * This solution got 25 points 22 | * Problem link: http://hr.gs/acbfeb 23 | */ 24 | class Queue { 25 | constructor() { 26 | this.principalStack = []; 27 | this.auxStack = []; 28 | } 29 | 30 | /** 31 | * Fill the auxiliar stack which is contains 32 | * a reversed list of the main stack elements 33 | */ 34 | fillAux() { 35 | if (this.auxStack.length === 0) { 36 | while(this.principalStack.length > 0) { 37 | this.auxStack.push(this.principalStack.pop()) 38 | } 39 | } 40 | } 41 | 42 | /** 43 | * Insert a new element in the rear of the queue 44 | */ 45 | enqueue(value) { 46 | this.principalStack.push(value); 47 | } 48 | 49 | /** 50 | * Remove the head element of the queue 51 | */ 52 | dequeue() { 53 | this.fillAux(); 54 | this.auxStack.pop(); 55 | } 56 | 57 | /** 58 | * Print the rear element of the queue 59 | */ 60 | printRear() { 61 | this.fillAux(); 62 | const head = this.auxStack.pop(); 63 | console.log(head); 64 | this.auxStack.push(head) 65 | } 66 | } 67 | /** 68 | * 69 | * @param {string} input - Queries to bo processed 70 | */ 71 | function processData(input) { 72 | const ACTIONS = { 73 | ENQEUE: '1', 74 | DEQUEUE: '2', 75 | PRINT: '3' 76 | }; 77 | const queue = new Queue(); 78 | input.split('\n').forEach(line => { 79 | const query = line.split(' '); 80 | switch (query[0]) { 81 | case ACTIONS.ENQEUE: 82 | queue.enqueue(query[1]); 83 | break; 84 | case ACTIONS.DEQUEUE: 85 | queue.dequeue(); 86 | break; 87 | case ACTIONS.PRINT: 88 | queue.printRear(); 89 | break; 90 | } 91 | }) 92 | } -------------------------------------------------------------------------------- /trees/binary-tree-height.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Hackerrank 3 | * The height of a binary tree is the number of edges between the tree's root 4 | * and its furthest leaf. Complete the getHeight or height function in the 5 | * editor. It must return the height of a binary tree as an integer. 6 | * Constraints: 7 | * 1. 1 <= node.data[i] <= 20 8 | * 2. 1 <= n <= 20 9 | * This solution got 10 points 10 | * Problem link: http://hr.gs/aeacfd 11 | */ 12 | 13 | /* 14 | class Node 15 | int data; 16 | Node left; 17 | Node right; 18 | */ 19 | public static int height(Node root) { 20 | return dfs(root, 0); 21 | } 22 | 23 | public static int dfs(Node node, int height) { 24 | if (node.left == null && node.right == null) { 25 | return height; 26 | } 27 | int leftHeight = height; 28 | int rightHeight = height; 29 | if (node.left != null) { 30 | leftHeight = dfs(node.left, height + 1); 31 | } 32 | if (node.right != null) { 33 | rightHeight = dfs(node.right, height + 1); 34 | } 35 | return Math.max(leftHeight, rightHeight); 36 | } -------------------------------------------------------------------------------- /trees/binary-tree-right-side-view.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Leetcode, #199 3 | * Given a binary tree, imagine yourself standing on the right side of it, 4 | * return the values of the nodes you can see ordered from top to bottom. 5 | */ 6 | 7 | /** 8 | * Definition for a binary tree node. 9 | * function TreeNode(val) { 10 | * this.val = val; 11 | * this.left = this.right = null; 12 | * } 13 | */ 14 | /** 15 | * @param {TreeNode} root 16 | * @return {number[]} 17 | */ 18 | function rightSideView(root) { 19 | if (!root) { 20 | return []; 21 | } 22 | const view = [root.val]; 23 | if (root.right || root.left) { 24 | bfs(root.right, view, 1); 25 | bfs(root.left, view, 1); 26 | } 27 | return view; 28 | }; 29 | 30 | /** 31 | * @param {TreeNode} node 32 | * @param {number[]} view 33 | * @param {number} level 34 | * @return {Void} 35 | */ 36 | function bfs(node, view, level) { 37 | if (!node) { 38 | return; 39 | } 40 | if (view[level] == null) { 41 | view[level] = node.val; 42 | } 43 | bfs(node.right, view, level + 1); 44 | bfs(node.left, view, level + 1); 45 | } 46 | -------------------------------------------------------------------------------- /trees/bst-insertion.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Hackerrank 3 | * You are given a pointer to the root of a binary search tree and values to be 4 | * inserted into the tree. Insert the values into their appropriate position in 5 | * the binary search tree and return the root of the updated binary tree. You 6 | * just have to complete the function. 7 | * Constraints: 8 | * 1. # Of nodes in the tree <= 500 9 | * This solution got 20 points 10 | * Problem link: http://hr.gs/cacecb 11 | */ 12 | 13 | /* Node is defined as : 14 | class Node 15 | int data; 16 | Node left; 17 | Node right; 18 | */ 19 | 20 | public static Node insert(Node root,int data) { 21 | if (root != null) { 22 | if (data >= root.data) { 23 | if (root.right == null) { 24 | root.right = new Node(data); 25 | } else { 26 | insert(root.right, data); 27 | } 28 | } else { 29 | if (root.left == null) { 30 | root.left = new Node(data); 31 | } else { 32 | insert(root.left, data); 33 | } 34 | } 35 | } else { 36 | root = new Node(data); 37 | } 38 | return root; 39 | } -------------------------------------------------------------------------------- /trees/max-depth-binary-tree.js: -------------------------------------------------------------------------------- 1 | /** 2 | * LeetCode | #104 | Easy 3 | * 4 | * Given the root of a binary tree, return its maximum depth. 5 | * 6 | * A binary tree's maximum depth is the number of nodes along the longest path 7 | * from the root node down to the farthest leaf node. 8 | * 9 | * Constraints: 10 | * 1. The number of nodes in the tree is in the range [0, 10^4]. 11 | * 2. -100 <= Node.val <= 100 12 | * 13 | */ 14 | 15 | /** 16 | * Definition for a binary tree node. 17 | * function TreeNode(val, left, right) { 18 | * this.val = (val===undefined ? 0 : val) 19 | * this.left = (left===undefined ? null : left) 20 | * this.right = (right===undefined ? null : right) 21 | * } 22 | * 23 | * @param {TreeNode} root 24 | * @return {number} 25 | * 26 | * Time complexity: O(n) 27 | */ 28 | const maxDepth = function(root) { 29 | const calcDepth = (root, n) => { 30 | if (!root) { 31 | return n; 32 | } 33 | 34 | return Math.max(calcDepth(root.left, n + 1), calcDepth(root.right, n + 1)); 35 | } 36 | 37 | return calcDepth(root, 0); 38 | }; -------------------------------------------------------------------------------- /trees/n-ary-tree-level-order-traversal.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Leetcode, #429 3 | * 4 | * Given an n-ary tree, return the level order traversal of its nodes' values. 5 | * 6 | * Constraints: 7 | * 1. The height of the n-ary tree is less than or equal to 1000 8 | * 2. The total number of nodes is between [0, 10^4] 9 | */ 10 | 11 | /** 12 | * // Definition for a Node. 13 | * function Node(val,children) { 14 | * this.val = val; 15 | * this.children = children; 16 | * }; 17 | */ 18 | /** 19 | * @param {Node} root 20 | * @return {number[][]} 21 | */ 22 | function levelOrder(root) { 23 | levels = []; 24 | if (root) { 25 | bfs(root, 0, levels) 26 | } 27 | return levels; 28 | }; 29 | 30 | /** 31 | * 32 | * @param {TreeNode} node 33 | * @param {number} level 34 | * @param {number[][]} levels 35 | */ 36 | function bfs(node, level, levels) { 37 | if (!levels[level]) { 38 | levels[level] = [node.val]; 39 | } else { 40 | levels[level].push(node.val); 41 | } 42 | node.children.forEach(child => { 43 | bfs(child, level + 1, levels); 44 | }); 45 | } -------------------------------------------------------------------------------- /trees/n-ary-tree-postorder-traversal.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Given an n-ary tree, return the postorder traversal of its nodes' values. 3 | * Nary-Tree input serialization is represented in their level order traversal, 4 | * each group of children is separated by the null value (See examples). 5 | * 6 | * Follow up: 7 | * Recursive solution is trivial, could you do it iteratively? 8 | */ 9 | 10 | 11 | /** 12 | * // Definition for a Node. 13 | * function Node(val,children) { 14 | * this.val = val; 15 | * this.children = children; 16 | * }; 17 | */ 18 | /** 19 | * @param {Node} root 20 | * @return {number[]} 21 | */ 22 | function postOrder(root) { 23 | const postOrder = []; 24 | if (root) { 25 | let node = root; 26 | const stack = [node]; 27 | while (stack.length > 0) { 28 | node = stack.pop(); 29 | postOrder.push(node.val); 30 | if (node.children.length > 0) { 31 | stack.push(...node.children); 32 | } 33 | } 34 | postOrder.reverse(); 35 | } 36 | return postOrder; 37 | }; -------------------------------------------------------------------------------- /trees/n-ary-tree-preorder-traversal.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Leetcode, 589 3 | * Given an n-ary tree, return the preorder traversal of its nodes' values. 4 | * Nary-Tree input serialization is represented in their level order traversal, 5 | * each group of children is separated by the null value (See examples). 6 | * 7 | * Follow up: 8 | * Recursive solution is trivial, could you do it iteratively? 9 | */ 10 | 11 | 12 | /** 13 | * // Definition for a Node. 14 | * function Node(val,children) { 15 | * this.val = val; 16 | * this.children = children; 17 | * }; 18 | */ 19 | /** 20 | * @param {Node} root 21 | * @return {number[]} 22 | */ 23 | function preorder(root) { 24 | const preOrder = []; 25 | if (root) { 26 | const stack = [root]; 27 | let node; 28 | while (stack.length > 0) { 29 | node = stack.pop(); 30 | preOrder.push(node.val); 31 | stack.push(...node.children.reverse()); 32 | } 33 | } 34 | return preOrder; 35 | }; -------------------------------------------------------------------------------- /trees/qheap1.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Hackerrank 3 | * This question is designed to help you get a better understanding of basic 4 | * heap operations. You will be given queries of types: 5 | * 1. '1 v' - Add an element v to the heap. 6 | * 2. '2 v' - Delete the element from the heap. 7 | * 3. '3' - Print the minimum of all the elements in the heap. 8 | * NOTE: It is guaranteed that the element to be deleted will be there in the 9 | * heap. Also, at any instant, only distinct elements will be in the heap. 10 | * 11 | * Constraints: 12 | * 1. 1 <= Q <= 10^5 - Q (number of queries) 13 | * 2. -10^9 <= v <= 10^9 14 | * 3. All the characters in the sequence: {, }, [, ], (, ) 15 | * 16 | * This solution got 25 points 17 | * Problem link: http://hr.gs/eceaeb 18 | */ 19 | 20 | /** 21 | * 22 | * @param {string} input 23 | */ 24 | function processData(input) { 25 | const queries = input.split('\n') 26 | .slice(1) 27 | .map(query => query.split(' ')); 28 | 29 | if (+queries[0][0] !== 1) { 30 | return; 31 | } 32 | 33 | const heap = new Heap(+queries[0][1]); 34 | queries.slice(1).forEach(query => { 35 | switch(+query[0]) { 36 | case 1: 37 | heap.insert(+query[1]); 38 | break; 39 | case 2: 40 | heap.delete(+query[1]); 41 | break; 42 | case 3: 43 | heap.peek(); 44 | break; 45 | } 46 | }); 47 | } 48 | 49 | class Heap { 50 | constructor(root) { 51 | this.priorityQueue = [null]; 52 | if (root != null) { 53 | this.priorityQueue.push(root); 54 | } 55 | } 56 | 57 | /** 58 | * Order the array in order to turn it into a min heap 59 | */ 60 | heapify() { 61 | for (let i = Math.floor((this.priorityQueue.length - 1) / 2); i > 0; i--) { 62 | this.minHeapify(i); 63 | } 64 | } 65 | 66 | /** 67 | * Check if a node meet the Min Heap criteria and perfom several swaps in case it doesn't 68 | * @param {number} i - Index of the node to be checked 69 | */ 70 | minHeapify(i) { 71 | const leftChild = i * 2; 72 | const rightChild = i * 2 + 1; 73 | 74 | if (leftChild < this.priorityQueue.length) { 75 | let lowestI = i; 76 | if (this.priorityQueue[leftChild] < this.priorityQueue[lowestI]) { 77 | lowestI = leftChild; 78 | } 79 | 80 | if (this.priorityQueue[rightChild] < this.priorityQueue[lowestI]) { 81 | lowestI = rightChild; 82 | } 83 | 84 | if (lowestI !== i) { 85 | swap(this.priorityQueue, i, lowestI); 86 | this.minHeapify(lowestI); 87 | } 88 | } 89 | } 90 | 91 | /** 92 | * Insert a new value on the heap and validate that queue meet the Min Heap 93 | * criteria 94 | * @param {number} val - Value to be inserted in the heap 95 | */ 96 | insert(val) { 97 | this.priorityQueue.push(val); 98 | this.heapify(); 99 | } 100 | 101 | /** 102 | * Delete the given value from the heap and validate that queue meet the Min Heap 103 | * criteria 104 | * @param {number} val - Value to be removed from the heap 105 | */ 106 | delete(val) { 107 | const i = this.priorityQueue.indexOf(val); 108 | if (i > -1) { 109 | const size = this.priorityQueue.length; 110 | const lastLeaf = this.priorityQueue.pop(); 111 | if (i < this.priorityQueue.length) { 112 | this.priorityQueue[i] = lastLeaf; 113 | this.minHeapify(i); 114 | } 115 | } 116 | } 117 | 118 | /** 119 | * Print the root of the Min Heap 120 | */ 121 | peek() { 122 | if (this.priorityQueue.length > 1) { 123 | console.log(this.priorityQueue[1]); 124 | } 125 | } 126 | } 127 | 128 | /** 129 | * Swap two elements in an given array 130 | * @param {number[]} arr - Array where changes will be perfomed 131 | * @param {number} org - Original index to be swapped 132 | * @param {number} next - New index to be swapped 133 | */ 134 | function swap(arr, org, next) { 135 | const prev = arr[org]; 136 | arr[org] = arr[next]; 137 | arr[next] = prev; 138 | } -------------------------------------------------------------------------------- /trees/trim-bst.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Leetcode, #669 3 | * Given a binary search tree and the lowest and highest boundaries as L and R, 4 | * trim the tree so that all its elements lies in [L, R] (R >= L). You might 5 | * need to change the root of the tree, so the result should return the new 6 | * root of the trimmed binary search tree. 7 | */ 8 | 9 | /** 10 | * Definition for a binary tree node. 11 | * function TreeNode(val) { 12 | * this.val = val; 13 | * this.left = this.right = null; 14 | * } 15 | */ 16 | /** 17 | * @param {TreeNode} root 18 | * @param {number} L 19 | * @param {number} R 20 | * @return {TreeNode} 21 | */ 22 | const trimBST = function(root, L, R) { 23 | return trimTree(root, null, L, R) 24 | }; 25 | 26 | const trimTree = function(node, parent, L, R) { 27 | if (!node) { 28 | return; 29 | } 30 | let followingP = node; 31 | if (node.val < L || node.val > R) { 32 | if (!node.left && !node.right) { 33 | if (!parent) { 34 | return null; 35 | } 36 | 37 | updateChild(parent, node, null); 38 | } else { 39 | let newN; 40 | if (node.val < L) { 41 | node.left = null; 42 | newN = node.right; 43 | } else if (node.val > R) { 44 | node.right = null; 45 | newN = node.left; 46 | } 47 | const ch = !node.left ? node.right : node.left; 48 | if (!parent) { 49 | return trimTree(newN, null, L, R); 50 | } else { 51 | updateChild(parent, node, ch); 52 | followingP = parent; 53 | } 54 | } 55 | } 56 | trimTree(node.right, followingP, L, R); 57 | trimTree(node.left, followingP, L, R); 58 | return node; 59 | } 60 | 61 | const updateChild = function(parent, oldChild, newChild) { 62 | if (oldChild.val >= parent.val) { 63 | parent.right = newChild; 64 | } else { 65 | parent.left = newChild; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /two-pointers/move-zeroes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * LeetCode | #283 | Easy 3 | * 4 | * Given an integer array nums, move all 0's to the end of it while maintaining the 5 | * relative order of the non-zero elements. 6 | * 7 | * Note that you must do this in-place without making a copy of the array. 8 | * 9 | * Constraints: 10 | * 1. 1 <= nums.length <= 10^4 11 | * 2. -2^31 <= nums[i] <= 2^31 - 1 12 | * 13 | */ 14 | 15 | /** 16 | * Time complexity: O(n) - Space complexity: O(1) 17 | * 18 | * @param {number[]} nums 19 | * @return {void} Do not return anything, modify nums in-place instead. 20 | */ 21 | function moveZeroes(nums) { 22 | if (nums.length < 2) { 23 | return; 24 | } 25 | 26 | let i = 0; 27 | let j = 0; 28 | while (j < nums.length) { 29 | if (nums[i] !== 0) { 30 | i++; 31 | 32 | if (j <= i) { 33 | j++; 34 | } 35 | } else if (nums[j] !== 0) { 36 | nums[i] = nums[j]; 37 | nums[j] = 0; 38 | } else { 39 | j++; 40 | } 41 | } 42 | } 43 | --------------------------------------------------------------------------------