├── .gitignore ├── README.md ├── arrays ├── LC#11 - Container With Most Water.js ├── LC#128 - Longest Consecutive Sequence.js ├── LC#136 - Single Number.js ├── LC#152 - Maximum Product Subarray.js ├── LC#153 - Find Minimum in Rotated Sorted Array.js ├── LC#167 - Two Sum II - Input Array Is Sorted.js ├── LC#1679 - Max Number of K-Sum Pairs.js ├── LC#189 - Rotate Array.js ├── LC#217 - Contains Duplicate.js ├── LC#2428 - Maximum Sum of an Hourglass.js ├── LC#268 - Missing Number.js ├── LC#283 - Move Zeroes.js ├── LC#33 - Search in Rotated Sorted Array.js ├── LC#334 - Increasing Triplet Subsequence.js ├── LC#36 - Valid Sudoku.js ├── LC#49 - Group Anagrams.js ├── LC#53 - Maximum Subarray.js ├── LC#57 - Insert Interval.js ├── LC#59 - Spiral Matrix II.js ├── LC#605 - Can Place Flowers.js ├── LC#643 - Maximum Average Subarray I.js ├── LC#73 - Set Matrix Zeroes.js ├── LC#88 - Merge Sorted Array.js ├── leftRotation.js ├── minimumSwaps.js ├── productSum.js ├── removeElement.js └── threeNumberSum.js ├── cracking ├── linkedlists │ ├── removeDups.js │ └── returnKthToLast.js ├── recursion&dp │ └── tripleStep.js └── stringsarrays │ ├── checkPermutation.js │ ├── isUnique.js │ ├── oneAway.js │ ├── palindromePermutation.js │ ├── rotateMatrix.js │ ├── stringCompression.js │ ├── stringRotation.js │ ├── urlify.js │ └── zeroMatrix.js ├── dfs └── LC#200 - Number of Islands.js ├── dictionaries:hashmaps ├── LC#17 - Letter Combinations of a Phone Number.js ├── sockMerchant.js └── twoStrings.js ├── dp ├── LC#303 - Range Sum Query - Immutable.js ├── LC#70 - Climbing Stairs.js └── maxSubsetSumNoAdj.js ├── graphs └── LC#133 - Clone Graph.js ├── greedyAlg ├── LC#121 - Best Time to Buy and Sell Stock.js └── tandemBicycle.js ├── idk ├── fib.js └── jewelsAndStones.js ├── linkedLists ├── LC#141 - Linked List Cycle.js ├── LC#143 - Reorder List.js ├── LC#160 - Intersection of Two Linked Lists.js ├── LC#19 - Remove Nth Node from End of List.js ├── LC#2 - Add Two Numbers.js ├── LC#206 - Reverse Linked List.js ├── LC#21 - Merge Two Sorted Lists.js ├── LC#328 - Odd Even Linked List.js └── removeDuplicates.js ├── sorting └── markAndToys.js ├── strings ├── LC#1071 - Greatest Common Divisor of Strings.js ├── LC#1249 - Minimum Remove to Make Valid Parentheses.js ├── LC#125 - Valid Palindrome.js ├── LC#1456 - Maximum Number of Vowels in a Substring of Given Length.js ├── LC#151 - Reverse Words in a String.js ├── LC#1768 - Merge Strings Alternatively.js ├── LC#20 - Valid Parentheses.js ├── LC#242 - Valid Anagram.js ├── LC#3 - Longest Substring Without Repeating Characters.js ├── LC#38 - Count and Say.js ├── LC#392 - Is Subsequence.js ├── LC#424 - Longest Repeating Character Replacement.js ├── countingValleys.js ├── repeatedString.js ├── reverseString.js └── vacummCleanerRoute.js └── trees ├── LC#100 - Same Tree.js ├── LC#102 - Binary Tree Level Order Traversal.js ├── LC#226 - Invert Binary Tree.js ├── LC#230 - Kth Smallest Element in a BST.js ├── LC#572 - Subtree of Another Tree.js ├── LC#94 - Binary Tree Inorder Traversal.js └── LC#98 - Validate Binary Search Tree.js /.gitignore: -------------------------------------------------------------------------------- 1 | test.js 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dsa-problems 2 | 3 | In this repo I'll be uploading some data structures & algorithms problems with their solution and analysis (time and space) in JS. 4 | 5 | The sources of the problems are mainly Leetcode, Hackerrank, AlgoExpert and Cracking the Coding Interview. 6 | 7 | This repo is *highly* inspired by my friends' repos, [Brian](https://github.com/brianr482/coding-interview-problems) and [Roberto](https://github.com/rmacuna/cracking-interviews-js). 8 | -------------------------------------------------------------------------------- /arrays/LC#11 - Container With Most Water.js: -------------------------------------------------------------------------------- 1 | // Leetcode medium 2 | 3 | // You are given an integer array height of length n. There are n vertical lines drawn such that the two endpoints of 4 | // the ith line are (i, 0) and (i, height[i]). 5 | 6 | // Find two lines that together with the x-axis form a container, such that the container contains the most water. 7 | 8 | // Return the maximum amount of water a container can store. 9 | 10 | // Notice that you may not slant the container. 11 | 12 | function maxArea(height) { 13 | let left = 0; 14 | let right = height.length - 1; 15 | 16 | let maxArea = 0; 17 | 18 | while (left < right) { 19 | let area = Math.min(height[left], height[right]) * (right - left); 20 | if (area > maxArea) maxArea = area; 21 | 22 | if (height[left] < height[right]) { 23 | left++; 24 | } else { 25 | right--; 26 | } 27 | } 28 | 29 | return maxArea; 30 | } 31 | 32 | height = [1,8,6,2,5,4,8,3,7]; 33 | console.log(maxArea(height)); // 49 34 | 35 | /* 36 | This solution uses two pointers, one starts at the beginning and the other starts at the end of the array. The area is calculated as the difference between 37 | pointers (right - left) times the lower of the heights of the pointers (Math.min(height[left], height[right])) and we compare each area with the maxArea 38 | variable. If that area is greater then we save it, and then depending on which pointer has the lower height, we move the left pointer or the right pointer, 39 | and this will go on until the pointers cross each other. 40 | 41 | The time complexity is O(n) since the array is only traversed once, and the space complexity is O(1) since there are only a couple of extra variables used 42 | and these do not change depending on the input. No extra data structures were used 43 | */ -------------------------------------------------------------------------------- /arrays/LC#128 - Longest Consecutive Sequence.js: -------------------------------------------------------------------------------- 1 | // Leetcode medium - solution using set 2 | 3 | /* 4 | Given an unsorted array of integers nums, return the length of the longest consecutive elements sequence. 5 | 6 | You must write an algorithm that runs in O(n) time. 7 | */ 8 | 9 | var longestConsecutive = function(nums) { 10 | let set = new Set(); 11 | 12 | for (const num of nums) set.add(num); 13 | 14 | let longest = 0; 15 | for (const num of set.values()) { 16 | if (set.has(num+1)) continue; 17 | 18 | let currLong = 1; 19 | let cursor = num - 1; 20 | while (set.has(cursor)) { 21 | cursor--; 22 | currLong++; 23 | } 24 | 25 | longest = Math.max(longest, currLong); 26 | } 27 | 28 | return longest; 29 | }; 30 | 31 | /* 32 | This solution has a time complexity of O(n), since we do a single pass through the input array, and do a pass 33 | through the Set, ignoring all the elements that have an element +1 bigger than them. This gives us a worst case 34 | of O(2n) and since we ignore the constants it ends up being O(n) 35 | 36 | This solution has a space complexity of O(n), since we have an auxiliary set that can be the same size as the 37 | input array. The set is used for the complexity of the search operation (O(1)) 38 | */ -------------------------------------------------------------------------------- /arrays/LC#136 - Single Number.js: -------------------------------------------------------------------------------- 1 | // Leetcode easy - solution using XOR operation / bit manipulation 2 | 3 | // Given a non-empty array of integers nums, every element appears twice except for one. Find that single one. 4 | 5 | // You must implement a solution with a linear runtime complexity and use only constant extra space. 6 | 7 | function singleNumber(nums) { 8 | let res = nums[0]; 9 | for (let i = 1; i < nums.length; i++) { 10 | res ^= nums[i]; 11 | } 12 | return res; 13 | } 14 | 15 | // For this solution, we use the XOR operation to manipulate the bits of the numbers. 16 | // if you do 2 ^ 2 it will give you zero, so in this case we start with the first position of the array 17 | // and start doing the XOR operation with the rest of the array. Since the numbers appear twice, the 18 | // XOR operation will cancel them and only leave the one number that appears once. 19 | 20 | // This solution has a time complexity of O(n) since the array is passed through once, and space complexity 21 | // of O(1) since only a single extra variable is used, and is the answer. -------------------------------------------------------------------------------- /arrays/LC#152 - Maximum Product Subarray.js: -------------------------------------------------------------------------------- 1 | // Leetcode medium - solution using dynamic programming, similar to maximumSubArray 2 | 3 | // Given an integer array nums, find a subarray that has the largest product, and return the product. 4 | 5 | function maximumProductSubArray(nums) { 6 | let max = nums[0]; 7 | nums[0] = {pos: nums[0], neg: nums[0]}; 8 | for (let i = 1; i < nums.length; i++) { 9 | let curr = nums[i] 10 | nums[i] = {} 11 | let prev = nums[i-1]; 12 | 13 | let pos = Math.max(curr, curr * prev.pos, curr * prev.neg); 14 | let neg = Math.min(curr, curr * prev.neg, curr * prev.pos); 15 | 16 | nums[i].pos = pos; 17 | nums[i].neg = neg; 18 | if (pos > max) max = pos; 19 | } 20 | return max; 21 | } 22 | 23 | /* 24 | This solution is very similar to the one found in maximumSubArray, the difference is that here we also have to save the most 25 | negative number because if that number is multiplied with another negative number then it can become a positive one. 26 | This solution has a time complexity of O(n) because we only pass through the array once. 27 | This solution has a space complexity of O(1) since we only use a couple of extra variables. 28 | */ -------------------------------------------------------------------------------- /arrays/LC#153 - Find Minimum in Rotated Sorted Array.js: -------------------------------------------------------------------------------- 1 | // Leetcode medium - solution using Binary Search 2 | 3 | /* 4 | Suppose an array of length n sorted in ascending order is rotated between 1 and n times. For example, the array nums = [0,1,2,4,5,6,7] might become: 5 | 6 | [4,5,6,7,0,1,2] if it was rotated 4 times. 7 | [0,1,2,4,5,6,7] if it was rotated 7 times. 8 | Notice that rotating an array [a[0], a[1], a[2], ..., a[n-1]] 1 time results in the array [a[n-1], a[0], a[1], a[2], ..., a[n-2]]. 9 | 10 | Given the sorted rotated array nums of unique elements, return the minimum element of this array. 11 | 12 | You must write an algorithm that runs in O(log n) time. 13 | */ 14 | 15 | function findMin(nums) { 16 | while (nums.length > 1) { 17 | let div = Math.ceil(nums.length / 2); 18 | let firstHalf = nums.slice(0, div); 19 | let secondHalf = nums.slice(div); 20 | if (firstHalf[firstHalf.length-1] > secondHalf[secondHalf.length-1]) { 21 | nums = secondHalf; 22 | } else { 23 | nums = firstHalf; 24 | } 25 | } 26 | return nums[0] 27 | } 28 | 29 | nums = [4,5,6,7,0,1,2]; 30 | console.log(findMin(nums)) // 0 31 | 32 | // We could use binary search in this case since the array is sorted (rotated, but sorted) 33 | // This solution has a time complexity of O(log n) since we never go through the entire array, we divide by two in every iteration. 34 | // This solution has a space complexity of O(n) since at the beginning we basically have a copy of the array, but we could also just use the last elements of 35 | // both arrays of every iteration and keep the reduced copy. -------------------------------------------------------------------------------- /arrays/LC#167 - Two Sum II - Input Array Is Sorted.js: -------------------------------------------------------------------------------- 1 | // Leetcode medium - solution using two pointers (and logic leveraged from the fact that the array is sorted) 2 | 3 | /* 4 | Given a 1-indexed array of integers numbers that is already sorted in non-decreasing order, find two numbers such that they add up 5 | to a specific target number. Let these two numbers be numbers[index1] and numbers[index2] where 1 <= index1 < index2 <= numbers.length. 6 | 7 | Return the indices of the two numbers, index1 and index2, added by one as an integer array [index1, index2] of length 2. 8 | 9 | The tests are generated such that there is exactly one solution. You may not use the same element twice. 10 | 11 | Your solution must use only constant extra space. 12 | */ 13 | 14 | var twoSum = function(numbers, target) { 15 | let left = 0; 16 | let right = numbers.length; 17 | 18 | while (left < right) { 19 | let total = numbers[left] + numbers[right]; 20 | 21 | if (total == target) { 22 | return [left + 1, right + 1]; 23 | } else if (total < target) { 24 | left++; 25 | } else { 26 | right--; 27 | } 28 | } 29 | }; 30 | 31 | // This solution has a time complexity of O(n) since in the worst case we will go through every number in the array 32 | // This solution has a space complexity of O(1) since no additional data structure is used -------------------------------------------------------------------------------- /arrays/LC#1679 - Max Number of K-Sum Pairs.js: -------------------------------------------------------------------------------- 1 | // Leetcode medium - solution with Hashmaps 2 | 3 | // You are given an integer array nums and an integer k. 4 | 5 | // In one operation, you can pick two numbers from the array whose sum equals k and remove 6 | // them from the array. 7 | 8 | // Return the maximum number of operations you can perform on the array. 9 | 10 | function maxOperations(nums, k) { 11 | let map = new Map(); 12 | let ops = 0; 13 | 14 | for (let i = 0; i < nums.length; i++) { 15 | let complement = k - nums[i]; 16 | if (map.has(complement)) { 17 | if (map.get(complement) == 1) { 18 | map.delete(complement); 19 | } else { 20 | map.set(complement, map.get(complement) - 1); 21 | } 22 | ops++; 23 | } else { 24 | if (map.has(nums[i])) { 25 | map.set(nums[i], map.get(nums[i]) + 1) 26 | } else { 27 | map.set(nums[i], 1) 28 | } 29 | } 30 | } 31 | 32 | return ops; 33 | } 34 | 35 | nums = [1,2,3,4]; 36 | k = 5; 37 | console.log(maxOperations) //2 38 | 39 | /* 40 | In this solution we use a hashmap and the numbers complement. If the hashmap has the complement of 41 | k - currentNumber, then that complement is erased from the hashmap. If it is not found then we store 42 | the current number and update its ocurrences. 43 | This solution has time complexity O(n) since the array is only passed through once, and because the 44 | operations with hashmaps are also O(1). 45 | The space complexity of this solution is O(n) since we use a map whose size depends on the input array. 46 | */ -------------------------------------------------------------------------------- /arrays/LC#189 - Rotate Array.js: -------------------------------------------------------------------------------- 1 | // Leetcode - Medium 2 | 3 | // Given an integer array nums, rotate the array to the right by k steps, where k is non-negative. 4 | 5 | 6 | function rotateArray(nums, k) { 7 | let len = nums.length; 8 | for (let i = 0; i < k; i++) { 9 | let first = nums[len-1]; 10 | for (let j = len - 1; j > 0; j--) { 11 | nums[j] = nums[j-1]; 12 | } 13 | nums[0] = first; 14 | } 15 | } 16 | 17 | let arr = [1,2,3,4,5,6,7] 18 | let k = 3 19 | // expected result: [5,6,7,1,2,3,4] 20 | rotateArray(arr, k); 21 | console.log(arr) 22 | 23 | // this solution is O(1) in space since the change is done in place but it is O(k*n) in space, since the whole array (length n) is being ran through k times 24 | // this solution works but with a very big input it will get Time Limit Exceeded -------------------------------------------------------------------------------- /arrays/LC#217 - Contains Duplicate.js: -------------------------------------------------------------------------------- 1 | // Leetcode easy - solution using a set 2 | 3 | // Given an integer array nums, return true if any value appears at least twice in the array, 4 | // and return false if every element is distinct. 5 | 6 | function containsDuplicate(nums) { 7 | let unique = new Set(); 8 | 9 | for (let i = 0; i < nums.length; i++) { 10 | if (unique.has(nums[i])) { 11 | return true; 12 | } else { 13 | unique.add(nums[i]); 14 | } 15 | } 16 | 17 | return false; 18 | } 19 | 20 | nums = [1,2,3,1] 21 | console.log(containsDuplicate(nums)); // true 22 | 23 | nums = [1,2,3,4] 24 | console.log(containsDuplicate(nums)); // false 25 | 26 | /* 27 | This solution uses a set to store unique values, and stores each number if they are not present. If 28 | a number is present, then it is a duplicate. 29 | This solution has a time complexity of O(n) since the array is run through once in the worst case. 30 | This solution has a space complexity of O(n) because of the created set. 31 | */ -------------------------------------------------------------------------------- /arrays/LC#2428 - Maximum Sum of an Hourglass.js: -------------------------------------------------------------------------------- 1 | // Leetcode medium 2 | 3 | /* Given a 2D Array, arr: 4 | An hourglass in A is a subset of values with indices falling 5 | in this pattern in arr's graphical representation: 6 | 7 | a b c 8 | d 9 | e f g 10 | 11 | There are 16 hourglasses in arr. An hourglass sum is the 12 | sum of an hourglass' values. Calculate the hourglass 13 | sum for every hourglass in arr, then print the maximum hourglass sum. 14 | The array will always be 6x6. 15 | */ 16 | 17 | function hourglassSum(arr) { 18 | let max = 0; 19 | let top = arr.length - 2; 20 | for (let i = 0; i < top; i++) { 21 | for (let j = 0; j < top; j++) { 22 | let currSum = findHourglassSum(arr, i, j); 23 | if (currSum > max) max = currSum; 24 | } 25 | } 26 | return max; 27 | } 28 | 29 | function findHourglassSum(arr, startRow, startCol) { 30 | let acum = 0; 31 | for (let i = startRow; i < startRow + 3; i++) { 32 | for (let j = startCol; j < startCol + 3; j++) { 33 | if (i == startRow + 1 && (j == startCol || j == startCol + 2)) continue; 34 | acum += arr[i][j]; 35 | } 36 | } 37 | return acum; 38 | } 39 | 40 | // Time comp: O(1) -- if it's always 6x6, if it isn't then it's O(n^2), n being the side of the matrix 41 | // Space comp: O(1) -------------------------------------------------------------------------------- /arrays/LC#268 - Missing Number.js: -------------------------------------------------------------------------------- 1 | // Leetcode easy - solution using sum of 0...n and comparing it to the sum of array 2 | 3 | // Given an array nums containing n distinct numbers in the range [0, n], return the only 4 | // number in the range that is missing from the array. 5 | 6 | function missingNumber(nums) { 7 | let expectedSum = 0; 8 | let actualSum = 0; 9 | for (let i = 0; i < nums.length; i++) { 10 | expectedSum += i+1; 11 | actualSum += nums[i]; 12 | } 13 | 14 | return expectedSum - actualSum; 15 | } 16 | 17 | nums = [3,0,1] 18 | console.log(missingNumber(nums)) // 2 19 | 20 | // This solution has a time complexity of O(n) since the array is passed through once and a space 21 | // complexity of O(1) since we only use two extra variables only for the solution. 22 | 23 | 24 | // there is also a solution that uses bit manipulation to solve it 25 | 26 | function missingNumberAlt(nums) { 27 | const n = nums.length; 28 | let ans = 0; 29 | for (let i = 1; i <= n; i++) { 30 | ans ^= i; 31 | } 32 | for (let i = 0; i < nums.length; i++) { 33 | ans ^= nums[i]; 34 | } 35 | return ans; 36 | } -------------------------------------------------------------------------------- /arrays/LC#283 - Move Zeroes.js: -------------------------------------------------------------------------------- 1 | // Given an integer array nums, move all 0's to the end of it while maintaining the relative order 2 | // of the non-zero elements. 3 | 4 | // Note that you must do this in-place without making a copy of the array. 5 | 6 | 7 | function moveZeroes(nums) { 8 | let left = 0; 9 | for(let i=0; i= nums[i]) a=nums[i]; 10 | else if(b>= nums[i]) b =nums[i]; 11 | else if(c>= nums[i]) return true; 12 | } 13 | return false 14 | } 15 | 16 | 17 | nums = [5,4,3,2,1] 18 | console.log(increasingTriplet(nums)) // false 19 | 20 | nums = [1,2,3,4,5] 21 | console.log(increasingTriplet(nums)) // true 22 | 23 | // This solution only has 3 extra variables, each one set initially to infinity and then comparing from that in a reverse way. 24 | 25 | // This solution has a time complexity of O(n) and a space complexity of O(1) -------------------------------------------------------------------------------- /arrays/LC#36 - Valid Sudoku.js: -------------------------------------------------------------------------------- 1 | // Leetcode medium - solution using two for loops and calculating the three conditions under the same loops 2 | 3 | /* 4 | Determine if a 9 x 9 Sudoku board is valid. Only the filled cells need to be validated according to the following rules: 5 | 6 | Each row must contain the digits 1-9 without repetition. 7 | Each column must contain the digits 1-9 without repetition. 8 | Each of the nine 3 x 3 sub-boxes of the grid must contain the digits 1-9 without repetition. 9 | Note: 10 | 11 | A Sudoku board (partially filled) could be valid but is not necessarily solvable. 12 | Only the filled cells need to be validated according to the mentioned rules. 13 | */ 14 | 15 | var isValidSudoku = function(board) { 16 | for (let i = 0; i < 9; i++) { 17 | let rowSet = new Set(); 18 | let colSet = new Set(); 19 | let boxSet = new Set(); 20 | for (let j = 0; j < 9; j++) { 21 | let currRow = board[i][j]; 22 | let currCol = board[j][i]; 23 | let currBox = board[3*Math.floor(i/3)+Math.floor(j/3)][3*(i%3)+(j%3)] 24 | 25 | if (currRow != '.') { 26 | if (rowSet.has(currRow)) return false; 27 | rowSet.add(currRow); 28 | } 29 | 30 | if (currCol != '.') { 31 | if (colSet.has(currCol)) return false; 32 | colSet.add(currCol); 33 | } 34 | 35 | if (currBox != '.') { 36 | if (boxSet.has(currBox)) return false; 37 | boxSet.add(currBox); 38 | } 39 | } 40 | } 41 | 42 | return true; 43 | }; 44 | 45 | // This solution has a time complexity of O(n*n) since we go through every cell of the sudoku board, which is 9x9 46 | // This solution has a space complexity of O(n) since we use exactly three sets that can be at most of size n -------------------------------------------------------------------------------- /arrays/LC#49 - Group Anagrams.js: -------------------------------------------------------------------------------- 1 | // Leetcode medium - solved using hashmaps and string/char manipulation 2 | 3 | /* 4 | Given an array of strings strs, group the anagrams together. You can return the answer in any order. 5 | 6 | An Anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once. 7 | */ 8 | 9 | var groupAnagrams = function(strs) { 10 | let map = new Map(); 11 | 12 | for (str of strs) { 13 | const signature = createSignature(str); 14 | if (!map.has(signature)) { 15 | map.set(signature, []) 16 | } 17 | map.get(signature).push(str); 18 | } 19 | 20 | const result = []; 21 | map.forEach(value => result.push(value)); 22 | 23 | return result; 24 | }; 25 | 26 | 27 | function createSignature(s) { 28 | const arr = Array(26).fill(0); 29 | 30 | for (const c of s) { 31 | arr[c.charCodeAt(0) - 'a'.charCodeAt(0)]++; 32 | } 33 | 34 | const result = []; 35 | for (let i = 0; i < 26; i++) { 36 | if (arr[i] != 0) { 37 | result.push(String.fromCharCode(i + 'a'.charCodeAt(0), arr[i].toString())); 38 | } 39 | } 40 | 41 | return result.join(''); 42 | } 43 | 44 | // This solution has a time complexity of O(n*m), being n the length of the strings array and m the length of the longest string. 45 | // This solution has a space complexity of O(n*m), being n the length of the strings array and m the length of the longes string with the least repeated characters. -------------------------------------------------------------------------------- /arrays/LC#53 - Maximum Subarray.js: -------------------------------------------------------------------------------- 1 | // Leetcode medium - solution using Dynamic Programming 2 | 3 | // Given an integer array nums, find the subarray with the largest sum, and return its sum. 4 | 5 | function maximumSubArray(nums) { 6 | let max = nums[0]; 7 | for (let i = 1; i < nums.length; i++) { 8 | nums[i] = 0 > nums[i-1] ? nums[i] : nums[i] + nums[i-1]; 9 | if (nums[i] > max) max = nums[i]; 10 | } 11 | return max; 12 | } 13 | 14 | nums = [-2,1,-3,4,-1,2,1,-5,4] 15 | console.log(maximumSubArray(nums)) // 6 16 | 17 | 18 | /* 19 | This problem is a example of what can be solved using dynamic programming. Since we are looking for the subarray that gives us the MAXIMUM 20 | sum, we can use each position of the input array to store the largest sum of all subarrays ending with index i. Having that, we can subtract 21 | whatever is left from what we consider would give the maximum sum of all subarrays. 22 | This solution has a time complexity O(n) since we go through the input array only once. 23 | This solution has as space complexity of O(1) since we do not use any other additional data structure. 24 | */ -------------------------------------------------------------------------------- /arrays/LC#57 - Insert Interval.js: -------------------------------------------------------------------------------- 1 | // Leetcode medium - 2 | 3 | /* 4 | You are given an array of non-overlapping intervals intervals where intervals[i] = [starti, endi] represent the 5 | start and the end of the ith interval and intervals is sorted in ascending order by starti. 6 | You are also given an interval newInterval = [start, end] that represents the start and end of another interval. 7 | 8 | Insert newInterval into intervals such that intervals is still sorted in ascending order by starti and intervals 9 | still does not have any overlapping intervals (merge overlapping intervals if necessary). 10 | 11 | Return intervals after the insertion. 12 | 13 | Note that you don't need to modify intervals in-place. You can make a new array and return it. 14 | 15 | Example 1: 16 | 17 | Input: intervals = [[1,3],[6,9]], newInterval = [2,5] 18 | Output: [[1,5],[6,9]] 19 | 20 | Example 2: 21 | 22 | Input: intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8] 23 | Output: [[1,2],[3,10],[12,16]] 24 | Explanation: Because the new interval [4,8] overlaps with [3,5],[6,7],[8,10]. 25 | */ 26 | 27 | function insertInterval(intervals, newInterval) { 28 | let left = []; 29 | let right = []; 30 | 31 | let start = newInterval[0] 32 | let end = newInterval[1] 33 | 34 | for (const interval of intervals) { 35 | if (interval[1] < newInterval[0]) { 36 | left.push(interval); 37 | continue; 38 | } 39 | if (interval[0] > newInterval[1]) { 40 | right.push(interval); 41 | continue; 42 | } 43 | 44 | let first = interval[0]; 45 | let second = interval[1]; 46 | 47 | start = Math.min(start, first); 48 | end = Math.max(end, second); 49 | } 50 | 51 | return [...left, [start, end], ...right] 52 | } 53 | 54 | 55 | intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]] 56 | newInterval = [4,8] 57 | console.log(insertInterval(intervals, newInterval)) // Output: [[1,2],[3,10],[12,16]] 58 | 59 | // This solution has a time complexity of O(n) since we go through the entire array 60 | // This solution has a space complexity of O(n) since the spread operator generates a whole copy of the array. 61 | -------------------------------------------------------------------------------- /arrays/LC#59 - Spiral Matrix II.js: -------------------------------------------------------------------------------- 1 | // Leetcode medium - Solution using multiple pointers to set matrix boundaries 2 | 3 | /* 4 | Given a positive integer n, generate an n x n matrix filled with elements from 1 to n2 in spiral order. 5 | */ 6 | 7 | var generateMatrix = function(n) { 8 | let mat = new Array(n).fill(0).map(() => new Array(n).fill(0)) 9 | let count = 0; 10 | let size = n*n; 11 | let left = 0; 12 | let right = n-1; 13 | let top = 0; 14 | let bottom = n-1; 15 | 16 | while (count < size) { 17 | for (let i = left; i <= right; i++) { 18 | count++; 19 | mat[top][i] = count; 20 | } 21 | top++; 22 | 23 | for (let i = top; i <= bottom; i++) { 24 | count++; 25 | mat[i][right] = count; 26 | } 27 | right--; 28 | 29 | for (let i = right; i >= left; i--) { 30 | count++; 31 | mat[bottom][i] = count; 32 | } 33 | bottom--; 34 | 35 | for (let i = bottom; i >= top; i--) { 36 | count++; 37 | mat[i][left] = count; 38 | } 39 | left++; 40 | } 41 | return mat; 42 | }; 43 | 44 | // This solution has a time complexity of O(n*n) since we populate all the cells of the n*n matrix 45 | // This solution has a space complexity of O(n*n) since we store a new n*n matrix (or O(1) if we ignore the result matrix) -------------------------------------------------------------------------------- /arrays/LC#605 - Can Place Flowers.js: -------------------------------------------------------------------------------- 1 | // Leetcode easy 2 | 3 | // You have a long flowerbed in which some of the plots are planted, and some are not. However, flowers cannot be planted in adjacent plots. 4 | 5 | // Given an integer array flowerbed containing 0's and 1's, where 0 means empty and 1 means not empty, and an integer n, return true if 6 | // n new flowers can be planted in the flowerbed without violating the no-adjacent-flowers rule and false otherwise. 7 | 8 | function canPlaceFlowers(flowerbed, n) { 9 | idx = 0; 10 | plants = 0; 11 | len = flowerbed.length; 12 | while (plants < n && idx < len) { 13 | if (flowerbed[idx] == 0 && 14 | (idx-1 < 0 || flowerbed[idx-1] == 0) && 15 | (idx+1 == len || flowerbed[idx+1] == 0)) { 16 | flowerbed[idx] = 1; 17 | plants++ 18 | } 19 | idx++; 20 | } 21 | 22 | return plants == n; 23 | } 24 | 25 | flowerbed = [1,0,0,0,1] 26 | n = 1 27 | console.log(canPlaceFlowers(flowerbed, n)); 28 | 29 | // This algorithm has O(n) time complexity since it goes through the array once and it has O(1) space complexity since only some extra variables are used 30 | // and this amount does not change depending on the input -------------------------------------------------------------------------------- /arrays/LC#643 - Maximum Average Subarray I.js: -------------------------------------------------------------------------------- 1 | // Leetcode easy - solution with sliding window 2 | 3 | //You are given an integer array nums consisting of n elements, and an integer k. 4 | 5 | // Find a contiguous subarray whose length is equal to k that has the maximum average value and 6 | // return this value. Any answer with a calculation error less than 10**(-5) will be accepted. 7 | 8 | function findMaxAverage(nums, k) { 9 | let maxSum = 0; 10 | 11 | for (let i = 0; i < k; i++) { 12 | maxSum += nums[i]; 13 | } 14 | 15 | let curSum = maxSum 16 | 17 | for (let i = k; i < nums.length; i++) { 18 | curSum = curSum - nums[i-k] + nums[i]; 19 | if (curSum > maxSum) maxSum = curSum; 20 | } 21 | 22 | return maxSum / k; 23 | } 24 | 25 | nums = [1,12,-5,-6,50,3]; 26 | k = 4; 27 | console.log(findMaxAverage(nums, k)) //12.75 28 | 29 | /* 30 | This solution first obtains the sum of the first k elements of the array, and then uses a sliding 31 | window to move a number in each iteration, substracting the element that goes out the window 32 | (the leftmost one) and adding the new element to the sum. After getting the biggest sum then it 33 | is divided by k and returned. 34 | This solution has a time complexity of O(n) since we get the first k elements and then we move n-k 35 | times more to get to the end of it, making a single pass. 36 | This solution has a space complexity of O(1) since we do not use any additional data structure, 37 | just a couple of variables. 38 | */ -------------------------------------------------------------------------------- /arrays/LC#73 - Set Matrix Zeroes.js: -------------------------------------------------------------------------------- 1 | // Leetcode medium - solution iterating over the matrix and using two sets 2 | 3 | /* 4 | Given an m x n integer matrix matrix, if an element is 0, set its entire row and column to 0's. 5 | 6 | You must do it in place. 7 | */ 8 | 9 | var setZeroes = function(matrix) { 10 | let zeroRows = new Set(); 11 | let zeroCols = new Set(); 12 | 13 | for (let i = 0; i < matrix.length; i++) { 14 | for (let j = 0; j < matrix[0].length; j++) { 15 | if (matrix[i][j] == 0) { 16 | zeroRows.add(i); 17 | zeroCols.add(j); 18 | } 19 | } 20 | } 21 | 22 | for (const row of zeroRows) { 23 | for (let i = 0; i < matrix[0].length; i++) { 24 | matrix[row][i] = 0; 25 | } 26 | } 27 | 28 | for (const col of zeroCols) { 29 | for (let i = 0; i < matrix.length; i++) { 30 | matrix[i][col] = 0; 31 | } 32 | } 33 | }; 34 | 35 | // This solution has a time complexity of O(n*m), n being the number of rows and m being the number of columns 36 | // since we do a full pass through the entire matrix 37 | // This solution has a space complexity of O(n+m) since we have two sets, one containing the rows that must be 38 | // set to zero and the other containing the columns that must be set to zero. -------------------------------------------------------------------------------- /arrays/LC#88 - Merge Sorted Array.js: -------------------------------------------------------------------------------- 1 | // From Leetcode 2 | // You are given two integer arrays nums1 and nums2, sorted in non-decreasing order, 3 | // and two integers m and n, representing the number of elements in nums1 and nums2 respectively. 4 | 5 | // Merge nums1 and nums2 into a single array sorted in non-decreasing order. 6 | 7 | // The final sorted array should not be returned by the function, but instead be stored inside the array nums1. 8 | // To accommodate this, nums1 has a length of m + n, where the first m elements denote the elements that 9 | // should be merged, and the last n elements are set to 0 and should be ignored. nums2 has a length of n. 10 | 11 | function merge(nums1, m, nums2, n) { 12 | i = m - 1; 13 | j = n - 1; 14 | k = m + n - 1; 15 | 16 | while (j >= 0) { 17 | if (nums1[i] > nums2[j]) { 18 | nums1[k] = nums1[i]; 19 | i--; 20 | } else { 21 | nums1[k] = nums2[j]; 22 | j--; 23 | } 24 | k--; 25 | } 26 | 27 | return nums1; 28 | } 29 | 30 | nums1 = [0]; 31 | m = 0; 32 | nums2 = [1]; 33 | n = 1; 34 | nums1 = merge(nums1, m, nums2, n); 35 | console.log(nums1); 36 | 37 | // For this we can use three pointers, to keep the solution at O(m+n). 38 | // One of the pointers is at m-1, where the end of the actual values of nums1 is located 39 | // The other pointer is at n-1, where the end of the values of nums2 is located 40 | // The other pointer at m+n-1, where the end of the nums1 array is located, and where the greater value 41 | // of the comparison will be put 42 | 43 | // Since there is only a pass of the nums1 array, the solution is O(m+n) -------------------------------------------------------------------------------- /arrays/leftRotation.js: -------------------------------------------------------------------------------- 1 | /* 2 | A left rotation operation on an array of size n shifts each of 3 | the array's elements 1 unit to the left. Given an integer, d, rotate 4 | the array that many steps left and return the result. 5 | */ 6 | 7 | function rotLeft(a, d) { 8 | const len = a.length; 9 | const mod = d % len; 10 | let arr = []; 11 | for (let i = 0; i < len; i++) { 12 | arr[i] = a[(mod+i)%len]; 13 | } 14 | return arr; 15 | } 16 | 17 | 18 | arr = [1,2,3,4,5,6,7,8,9]; 19 | d = 3; 20 | 21 | console.log(rotLeft(arr, d)); 22 | 23 | // Time comp: O(n); 24 | // Space comp: O(n); Would be O(1) space with in-place swapping -------------------------------------------------------------------------------- /arrays/minimumSwaps.js: -------------------------------------------------------------------------------- 1 | // You are given an unordered array consisting of 2 | // consecutive integers [1, 2, 3, ..., n] without any 3 | // duplicates. You are allowed to swap any two elements. 4 | // Find the minimum number of swaps required to sort the 5 | // array in ascending order. 6 | 7 | function minimumSwaps(arr) { 8 | let accum = 0; 9 | for (let i = 0; i < arr.length; i++) { 10 | if (arr[i] != i+1) { 11 | let idx = -1; 12 | for (let j = i; j < arr.length; j++) { 13 | if (arr[j] == i+1) { 14 | idx = j; 15 | break; 16 | } 17 | } 18 | arr[idx] ^= arr[i]; 19 | arr[i] ^= arr[idx]; 20 | arr[idx] ^= arr[i]; 21 | accum++; 22 | } 23 | } 24 | return accum; 25 | } 26 | 27 | // Time comp: O(n^2) -- n^2 because we iterate over the array and when a number is not in 28 | // place, we search the index of the corresponding number, which takes another O(n) in the worst case 29 | // Space comp: O(1) -- because the only added variable is the accumulator 30 | 31 | // There is also a solution in O(n) time 32 | // https://github.com/brianr482/coding-interview-problems/blob/master/arrays-strings/min-swaps-2.js -------------------------------------------------------------------------------- /arrays/productSum.js: -------------------------------------------------------------------------------- 1 | /* 2 | Write a function that takes in a "special" array and returns its product sum. 3 | 4 | A "special" array is a non-empty array that contains either integers or other 5 | "special" arrays. The product sum of a "special" array is the sum of its elements, 6 | where "special" arrays inside it are summed themselves and then multiplied by 7 | their level of depth. 8 | 9 | The depth of a "special" array is how far nested it is. For instance, the depth 10 | of [] is 1; the depth of the inner array in [[]] is 2; the depth of the innermost 11 | array in [[[]]] is 3. 12 | 13 | Therefore, the product sum of [x, y] is x + y; the product sum of [x, [y, z]] is 14 | x + 2 * (y + z); the product sum of [x, [y, [z]]] is x + 2 * (y + 3z). 15 | */ 16 | 17 | function productSum(array) { 18 | return getSum(array, 1); 19 | } 20 | 21 | function getSum(array, multiplier) { 22 | let sum = 0; 23 | for (let i = 0; i < array.length; i++) { 24 | if (Array.isArray(array[i])) { 25 | sum += getSum(array[i], multiplier + 1); 26 | } else { 27 | sum += array[i]; 28 | } 29 | } 30 | return sum * multiplier 31 | } 32 | 33 | // Time comp: O(n) -- n being the elements in the array (including sub-elements) 34 | // Space comp: O(d) -- d being the multiplier of the innermost special array -------------------------------------------------------------------------------- /arrays/removeElement.js: -------------------------------------------------------------------------------- 1 | // Given an integer array nums and an integer val, remove all occurrences of val in nums in-place. 2 | // The order of the elements may be changed. Then return the number of elements in nums which are not 3 | // equal to val. 4 | 5 | // Consider the number of elements in nums which are not equal to val be k, to get accepted, you need 6 | // to do the following things: 7 | 8 | // - Change the array nums such that the first k elements of nums contain the elements which are not equal to val. 9 | // - The remaining elements of nums are not important as well as the size of nums. 10 | // - Return k. 11 | 12 | function removeElement(nums, val) { 13 | let len = nums.length; 14 | let lastIdx = len-1; 15 | let set = new Set(); 16 | 17 | if (nums[lastIdx] == val) { 18 | while (nums[lastIdx] == val) { 19 | nums[lastIdx] = '_'; 20 | lastIdx--; 21 | } 22 | } 23 | 24 | for (let i = 0; i < len; i++) { 25 | if (nums[i] == val) { 26 | let temp = nums[lastIdx]; 27 | nums[lastIdx] = '_'; 28 | nums[i] = temp; 29 | lastIdx--; 30 | } else { 31 | if (!set.has(nums[i])) { 32 | set.add(nums[i]); 33 | } 34 | } 35 | } 36 | 37 | return set.size; 38 | } 39 | 40 | // This solution only does a single pass through the whole array, and since the search in a set is O(1), 41 | // the solution is O(n) -------------------------------------------------------------------------------- /arrays/threeNumberSum.js: -------------------------------------------------------------------------------- 1 | /* 2 | Write a function that takes in a non-empty array of distinct integers and an integer 3 | representing a target sum. The function should find all triplets in the array that sum 4 | up to the target sum and return a two-dimensional array of all these triplets. The 5 | numbers in each triplet should be ordered in ascending order, and the triplets themselves 6 | should be ordered in ascending order with respect to the numbers they hold. 7 | 8 | If no three numbers sum up to the target sum, the function should return an empty array. 9 | */ 10 | 11 | function threeNumberSum() { 12 | if (array.length < 3) return []; 13 | 14 | array.sort((a,b) => a - b); 15 | 16 | const result = []; 17 | 18 | for (let i = 0; i < array.length - 2; i++) { 19 | let leftIndex = i + 1; 20 | let rightIndex = array.length - 1; 21 | while (leftIndex < rightIndex) { 22 | const current = array[i]+array[leftIndex]+array[rightIndex]; 23 | if (current == targetSum) { 24 | result.push([array[i], array[leftIndex], array[rightIndex]]); 25 | leftIndex++; 26 | rightIndex++; 27 | } else if (current < targetSum) { 28 | leftIndex++; 29 | } else { 30 | rightIndex--; 31 | } 32 | } 33 | 34 | } 35 | return result; 36 | } 37 | 38 | //Time comp: O(n^2) -- n being the length of the input array 39 | //Space comp: O(n) -- n being the length of the input array 40 | 41 | /* 42 | - the first thing that comes to my mind is using three 43 | for loops, and storing the indices in some aux array and 44 | sort them later, that would give O(n^3) time O(m) space 45 | (m being the amount of triplets that fulfill the condition) 46 | - another option is to sort the array and then traverse over 47 | each element, use three pointers(one starting next to the current index 48 | and one starting at the end of the array) and sum them, if it's 49 | greater than the target, decrease the right index, if it's lower 50 | than the target, increase the left index. Once a triplet is 51 | found then it is stored in an array 52 | */ -------------------------------------------------------------------------------- /cracking/linkedlists/removeDups.js: -------------------------------------------------------------------------------- 1 | class Node { 2 | constructor(data) { 3 | this.data = data; 4 | this.next = null; 5 | } 6 | } 7 | 8 | function removeDups(node) { 9 | const present = []; 10 | let prev; 11 | let current = node; 12 | while(current) { 13 | if (present.includes(current.data)) { 14 | prev.next = current.next; 15 | current.next = null; 16 | current = prev.next; 17 | } else { 18 | present.push(current.data); 19 | prev = current; 20 | current = current.next; 21 | } 22 | } 23 | return node; 24 | } 25 | 26 | //Time comp: O(n) - n being the length of the linked list 27 | //Space comp: O(n) - n being the length of the linked list 28 | 29 | let node = new Node(2); 30 | node.next = new Node(3); 31 | node.next.next = new Node(2); 32 | node.next.next.next = new Node(4); 33 | node.next.next.next.next = new Node(5); 34 | 35 | removeDups(node); 36 | 37 | while(node) { 38 | console.log(node.data); 39 | node = node.next; 40 | } -------------------------------------------------------------------------------- /cracking/linkedlists/returnKthToLast.js: -------------------------------------------------------------------------------- 1 | /* 2 | Implement an algorithm to find the kth to last element of a singly linked list. 3 | */ 4 | 5 | class Node { 6 | constructor(data) { 7 | this.data = data; 8 | this.next = null; 9 | } 10 | } 11 | 12 | //Recursive solution 13 | function returnKthToLast(head, k) { 14 | let counter = [0]; 15 | let result = solve(head, k, counter); 16 | return result; 17 | } 18 | 19 | function solve(node, k, counter) { 20 | if (!node) { 21 | return null; 22 | } 23 | 24 | let nextNode = solve(node.next, k, counter); 25 | counter[0] = counter[0] + 1; 26 | 27 | if (counter[0] == k) { 28 | return node; 29 | } 30 | return nextNode; 31 | } 32 | 33 | //Time comp: O(n) 34 | //Space comp: O(n) 35 | 36 | //Iterative solution 37 | function returnKthToLast(head, k) { 38 | let p1 = head; 39 | for (let i = 0; i < k; i++) { 40 | p1 = p1.next; 41 | } 42 | let p2 = head; 43 | while(p1) { 44 | p2 = p2.next; 45 | p1 = p1.next; 46 | } 47 | return p2; 48 | } 49 | 50 | //Time comp: O(n) 51 | //Space comp: O(1) 52 | 53 | /* 54 | - One way to do it is to traverse the whole list 55 | to know how long is it, then traverse it until 56 | length - k and return that node 57 | */ -------------------------------------------------------------------------------- /cracking/recursion&dp/tripleStep.js: -------------------------------------------------------------------------------- 1 | /* 2 | A child is running up a staircase with n steps and can hop either 1 step, 2 steps, 3 | or 3 steps at a time. Implement a method to count how many possible ways the child 4 | can run up the stairs. 5 | */ 6 | 7 | function tripleStep(n) { 8 | memo = [] 9 | return solve(n, memo); 10 | } 11 | 12 | function solve(n, memo) { 13 | if (n < 0) { 14 | return 0; 15 | } else if (n == 0) { 16 | return 1; 17 | } else if (memo[n]) { 18 | return memo[n] 19 | } else { 20 | memo[n] = solve(n-1, memo) + solve(n-2, memo) + solve(n-3, memo); 21 | return memo[n]; 22 | } 23 | } 24 | 25 | //Time comp: O(n) 26 | //Space comp: O(n) 27 | -------------------------------------------------------------------------------- /cracking/stringsarrays/checkPermutation.js: -------------------------------------------------------------------------------- 1 | /* 2 | Given two strings, write a method to decide if one is a permutation of the other. 3 | */ 4 | 5 | function checkPermutation(str1, str2) { 6 | const str1Map = new Map(); 7 | for (let i = 0; i < str1.length; i++) { 8 | if (str1Map.has(str1[i])) { 9 | str1Map.set(str1[i], str1Map.get(str1[i]) + 1); 10 | } else { 11 | str1Map.set(str1[i], 1); 12 | } 13 | } 14 | const str2Map = new Map(); 15 | for (let i = 0; i < str2.length; i++) { 16 | if (str2Map.has(str2[i])) { 17 | str2Map.set(str2[i], str2Map.get(str2[i]) + 1); 18 | } else { 19 | str2Map.set(str2[i], 1); 20 | } 21 | } 22 | 23 | for (const key of str1Map.keys()) { 24 | if (str2Map.has(key)) { 25 | if (str2Map.get(key) != str1Map.get(key)) { 26 | return false; 27 | } 28 | } else { 29 | return false; 30 | } 31 | } 32 | 33 | return true; 34 | } 35 | 36 | // Time comp: O(n + m) - n and m being the strings 37 | // Space comp: O(n + m) - n and m being the strings 38 | 39 | /* 40 | - populate a hashmap with the first string, using the letters as keys 41 | and the values as the amount of times they appear in the string 42 | - do the same with the second string 43 | - check if the hashmaps have the same keys and values 44 | */ -------------------------------------------------------------------------------- /cracking/stringsarrays/isUnique.js: -------------------------------------------------------------------------------- 1 | /* 2 | Implement an algorithm to determine if a string has all unique characters. 3 | What if you cannot use additional data structures? 4 | */ 5 | 6 | function isUnique(str) { 7 | for (let i = 0; i < str.length; i++) { 8 | for (let j = i-1; j >= 0; j--) { 9 | if (str[j] == str[i]) { 10 | return false; 11 | } 12 | } 13 | } 14 | return true; 15 | } 16 | 17 | // If not using any other data structure 18 | // Time comp: O(n^2) 19 | // Space comp: O(1) 20 | 21 | // If using other data structures 22 | // Time comp: O(n) 23 | // Space comp: O(n) 24 | 25 | // can also be done using the ascii values of the chars 26 | // and using an 128-space array for validating if a 27 | // char has appeared more than once, with a time comp 28 | // of O(n) and a space comp of O(1) -------------------------------------------------------------------------------- /cracking/stringsarrays/oneAway.js: -------------------------------------------------------------------------------- 1 | /* 2 | There are three types of edits that can be performed on strings: insert a character, 3 | remove a character, or replace a character. Given two strings, write a function to 4 | check if they are one edit (or zero edits) away. 5 | */ 6 | 7 | function oneAway(str1, str2) { 8 | const map1 = new Map(); 9 | const map2 = new Map(); 10 | 11 | for (let i = 0; i < str1.length; i++) { 12 | if (map1.has(str1[i])) { 13 | map1.set(str1[i], map1.get(str1[i]) + 1); 14 | } else { 15 | map1.set(str1[i], 1); 16 | } 17 | } 18 | 19 | for (let i = 0; i < str2.length; i++) { 20 | if (map2.has(str2[i])) { 21 | map2.set(str2[i], map2.get(str2[i]) + 1); 22 | } else { 23 | map2.set(str2[i], 1); 24 | } 25 | } 26 | 27 | let checkMap; 28 | let toCheckMap; 29 | if (map1.keys().length > map2.keys().length) { 30 | checkMap = map1; 31 | toCheckMap = map2; 32 | checkStr = str2; 33 | } else { 34 | checkMap = map2; 35 | toCheckMap = map1; 36 | checkStr = str1; 37 | } 38 | 39 | let change = false; 40 | for (const key of checkMap.keys()) { 41 | if (toCheckMap.has(key)) { 42 | if (Math.abs(checkMap.get(key) - toCheckMap.get(key)) >= 1 && change) return false; 43 | if (Math.abs(checkMap.get(key) - toCheckMap.get(key)) == 1) change = true; 44 | } else { 45 | if (change) return false; 46 | if (checkMap.get(key) > 1) return false; 47 | change = true; 48 | } 49 | } 50 | return true; 51 | } 52 | 53 | //Time comp: O(n + m) - n and m being the length of both strings 54 | //Space comp: O(n + m) - n and m being the length of both strings 55 | 56 | /* 57 | - to know if a string is just a change away from other, 58 | we have to store the amount of letters each string has 59 | in two maps, then compare each key of the map and if a key 60 | with more than one occurence is missing or if the value of a 61 | key is different by more than one, then it is not a change away 62 | */ 63 | 64 | /* 65 | - map each string into a map, using the letters as keys and 66 | the number of appearances in the string as the value 67 | - iterate over the keys of the first map and check whether 68 | the key exists on the other map and if said key differs by 69 | more than one unit 70 | */ -------------------------------------------------------------------------------- /cracking/stringsarrays/palindromePermutation.js: -------------------------------------------------------------------------------- 1 | /* 2 | Given a string, write a function to check if it is a permutation of a palindrome. 3 | A palindrome is a word or phrase that is the same forwards and backwards. 4 | A permutation is a rearrangement of letters.The palindrome does not need to 5 | be limited to just dictionary words. 6 | */ 7 | 8 | function palindromePermutation(str) { 9 | const map = new Map(); 10 | for (let i = 0; i < str.length; i++) { 11 | if (map.has(str[i])) { 12 | map.set(str[i], map.get(str[i]) + 1); 13 | } else { 14 | map.set(str[i], 1); 15 | } 16 | } 17 | 18 | let odd = false; 19 | for (const key of map.keys()) { 20 | if (map.get(key) % 2 != 0 && odd) return false; 21 | if (map.get(key) % 2 != 0 && !odd) odd = true; 22 | } 23 | return true; 24 | } 25 | 26 | // Time comp: O(n) - n being the length of the string; 27 | // Space comp: O(m) - m being the amount of different letters of the string 28 | 29 | /* 30 | I can know if a word is palindrome if 31 | each letter appears an even number of times 32 | and only one letter can appear an odd number 33 | of times 34 | */ 35 | 36 | /* 37 | - iterate over each letter, storing them in a hashmap 38 | where the key will be the letter and the value will 39 | be the number of times it appears in the string 40 | - check if every occurence of the letters are even 41 | (only one can be odd) 42 | */ -------------------------------------------------------------------------------- /cracking/stringsarrays/rotateMatrix.js: -------------------------------------------------------------------------------- 1 | //TODO 2 | 3 | function rotateMatrix(mat) { 4 | const n = mat.length; 5 | for (let layer = 0; layer < n / 2; layer++) { 6 | let first = layer; 7 | let last = n - 1 - layer; 8 | for (let i = first; i < last; i++) { 9 | let offset = i - first; 10 | const top = mat[first][i]; 11 | mat[first][i] = mat[last-offset][first]; 12 | mat[last-offset][first] = [last][last-offset]; 13 | mat[last][last-offset] = mat[i][last] 14 | mat[i][last] = top; 15 | // console.log(mat) 16 | } 17 | } 18 | return true 19 | } 20 | 21 | const mat = [ 22 | [1,2,3,4], 23 | [5,6,7,8], 24 | [9,10,11,12], 25 | [13,14,15,16] 26 | ] 27 | 28 | /* 29 | - to rotate a matrix, we can rotate by layers 30 | */ -------------------------------------------------------------------------------- /cracking/stringsarrays/stringCompression.js: -------------------------------------------------------------------------------- 1 | /* 2 | Implement a method to perform basic string compression using the counts 3 | of repeated characters. For example, the string aabcccccaaa would become 4 | a2b1c5a3. If the "compressed" string would not become smaller than the original 5 | string, your method should return the original string. You can assume the string 6 | has only uppercase and lowercase letters (a - z). 7 | */ 8 | 9 | function stringCompression(str) { 10 | let count = 1; 11 | let prev; 12 | let newStr = ''; 13 | for (let i = 0; i < str.length; i++) { 14 | if (prev) { 15 | if (str[i] == prev) { 16 | count++; 17 | } else { 18 | newStr = newStr + prev + count; 19 | count = 1; 20 | } 21 | } 22 | prev = str[i]; 23 | } 24 | newStr = newStr + prev + count; 25 | return newStr; 26 | } 27 | 28 | //Time comp: O(n) - n being the length of the string 29 | //Space comp: O(n) - n being the length of the string 30 | 31 | /* 32 | - I can compress a string by retaining the last letter used 33 | and compare with the current letter, if it's the same then 34 | a counter will increase and if it's not then the counter 35 | will be appended to the new string and return to 1 36 | */ -------------------------------------------------------------------------------- /cracking/stringsarrays/stringRotation.js: -------------------------------------------------------------------------------- 1 | /* 2 | Assume you have amethod isSubstring which checks if one word is asubstring of another. 3 | Given two strings, S1 and S2, write code to check if S2 is a rotation of S1 using only 4 | one call to isSubstring (e.g.,"waterbottle"is a rotation of"erbottlewat"). 5 | */ 6 | 7 | function stringRotation(s1, s2) { 8 | if (s1.length != s2.length) return false; 9 | const newStr = s1+s1; 10 | if (newStr.includes(s2)) return true; 11 | return false; 12 | } 13 | 14 | //Time comp: O(1) - assuming javascript implementation appends in constant time 15 | //Space comp: O(n) - n being the size of the first string 16 | 17 | /* 18 | - we can stick the first string together so it would include any rotation of the word 19 | */ -------------------------------------------------------------------------------- /cracking/stringsarrays/urlify.js: -------------------------------------------------------------------------------- 1 | function urlify(str, realLength) { 2 | const len = str.length; 3 | const split = str.split(' '); 4 | let join = ''; 5 | console.log(split) 6 | for (let i = 0; i < split.length; i++) { 7 | if (split[i] != '') { 8 | join += join.length == 0 ? split[i] : '%20'+split[i] 9 | } 10 | } 11 | console.log(join) 12 | if (join.length > len) return false; 13 | return join; 14 | } 15 | 16 | // Time comp: O(n) - n being the length of the string 17 | // Space comp: O(n) - n being the length of the string 18 | 19 | 20 | /* 21 | - get the length of the input string 22 | - split the input string into an array 23 | - between the spaces, concat a %20 24 | - remove trailing spaces 25 | - join array 26 | - check if length is the same 27 | */ -------------------------------------------------------------------------------- /cracking/stringsarrays/zeroMatrix.js: -------------------------------------------------------------------------------- 1 | /* 2 | Write an algorithm such that if an element in an MxN matrix is 0, its entire row and column are set to O. 3 | */ 4 | 5 | function zeroMatrix(mat) { 6 | const indices = []; 7 | for (let i = 0; i < mat.length; i++) { 8 | for (let j = 0; j < mat[0].length; j++) { 9 | if (mat[i][j] == 0) indices.push([i,j]); 10 | } 11 | } 12 | 13 | for (const index of indices) { 14 | transformToZero(mat, index); 15 | } 16 | 17 | return mat; 18 | } 19 | 20 | function transformToZero(mat, index) { 21 | const [row, col] = index; 22 | const rowEnd = mat.length; 23 | const colEnd = mat[0].length; 24 | for (let i = row; i >= 0; i--) { 25 | mat[i][col] = 0; 26 | } 27 | for (let i = row; i < rowEnd; i++) { 28 | mat[i][col] = 0; 29 | } 30 | for (let i = col; i >= 0; i--) { 31 | mat[row][i] = 0; 32 | } 33 | for (let i = col; i < colEnd; i++) { 34 | mat[row][i] = 0; 35 | } 36 | } 37 | 38 | let mat = [ 39 | [1, 2, 3, 0], 40 | [5,78,3,1], 41 | [1,0,4,6], 42 | [1,9,7,4] 43 | ] 44 | 45 | //Time comp: O(n * m) -- n and m being the width and the height of the matrix 46 | //Space comp: O(m) -- m being the number of zeroes in the matrix 47 | 48 | /* 49 | - one way to solve this is to use a copy matrix where the 50 | operations of converting the row and column in 0 will be 51 | executed. Don't currently know how to do it in place. 52 | - Well, a first pass might be done to store where the indices 53 | of the 0 cells are located and then another pass to convert 54 | the rows and columns into 0 55 | */ -------------------------------------------------------------------------------- /dfs/LC#200 - Number of Islands.js: -------------------------------------------------------------------------------- 1 | /* 2 | Given an m x n 2D binary grid grid which represents a map of '1's (land) 3 | and '0's (water), return the number of islands. 4 | 5 | An island is surrounded by water and is formed by connecting adjacent 6 | lands horizontally or vertically. You may assume all four edges of the 7 | grid are all surrounded by water. 8 | */ 9 | 10 | function numberOfIslands(grid) { 11 | const height = grid.length; 12 | const width = grid[0].length; 13 | let accum = 0; 14 | for (let i = 0; i < height; i++) { 15 | for (let j = 0; j < width; j++) { 16 | if (grid[i][j] === '1') { 17 | accum++; 18 | removeIsland(grid, i, j); 19 | } 20 | } 21 | } 22 | return accum; 23 | } 24 | 25 | function removeIsland(grid, x, y) { 26 | grid[x][y] = '0'; 27 | if (x > 0 && grid[x-1][y] === '1') removeIsland(grid, x - 1, y); 28 | if (x < grid.length - 1 && grid[x+1][y] === '1') removeIsland(grid, x + 1, y); 29 | if (y > 0 && grid[x][y-1] === '1') removeIsland(grid, x, y - 1); 30 | if (y < grid[0].length - 1 && grid[x][y+1] === '1') removeIsland(grid, x, y + 1); 31 | } 32 | 33 | // Time comp: O(n*m) -- n and m being the height and the width of the matrix 34 | // Space comp: O(n*m) -- n and m being the height and the width of the matrix 35 | -------------------------------------------------------------------------------- /dictionaries:hashmaps/LC#17 - Letter Combinations of a Phone Number.js: -------------------------------------------------------------------------------- 1 | /* 2 | Given a string containing digits from 2-9 inclusive, return all possible letter combinations 3 | that the number could represent. Return the answer in any order. 4 | 5 | A mapping of digit to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters. 6 | 2 = abc 7 | 3 = def 8 | 4 = ghi 9 | 5 = jkl 10 | 6 = mno 11 | 7 = pqrs 12 | 8 = tuv 13 | 9 = wxyz 14 | 15 | Example: 16 | input: "23" 17 | output: ["ad","ae","af","bd","be","bf","cd","ce","cf"] 18 | */ 19 | 20 | function letterCombinations(digits) { 21 | if (digits === "") return []; 22 | let map = new Map(); 23 | map.set('2', ['a', 'b', 'c']); 24 | map.set('3', ['d', 'e', 'f']); 25 | map.set('4', ['g', 'h', 'i']); 26 | map.set('5', ['j', 'k', 'l']); 27 | map.set('6', ['m', 'n', 'o']); 28 | map.set('7', ['p', 'q', 'r', 's']); 29 | map.set('8', ['t', 'u', 'v']); 30 | map.set('9', ['w', 'x', 'y', 'z']); 31 | let solutions = []; 32 | 33 | findCombinations(digits, 0, '', solutions, map); 34 | return solutions; 35 | } 36 | 37 | function findCombinations(digits, currentIdx, string, solutions, map) { 38 | const chars = map.get(digits[currentIdx]); 39 | if (currentIdx === digits.length - 1) { 40 | for (char of chars) { 41 | solutions.push(string + char); 42 | } 43 | } else { 44 | for (char of chars) { 45 | findCombinations(digits, currentIdx + 1, string + char, solutions, map); 46 | } 47 | } 48 | } 49 | 50 | // Time comp: O(2^n) -- n being the amount of digits in the input 51 | // Space comp: O(m) -- m being the amount of digits in the input -------------------------------------------------------------------------------- /dictionaries:hashmaps/sockMerchant.js: -------------------------------------------------------------------------------- 1 | /* 2 | Sales by Match. 3 | 4 | There is a large pile of socks that must be paired by color. 5 | Given an array of integers representing the color of each sock, 6 | determine how many pairs of socks with matching colors there are. 7 | */ 8 | 9 | function sockMerchant(n, ar) { 10 | let socks = new Set(); 11 | let acum = 0; 12 | ar.forEach(value => { 13 | if (!socks.has(value)) { 14 | socks.add(value); 15 | } else { 16 | socks.delete(value); 17 | acum++; 18 | } 19 | }); 20 | return acum; 21 | } 22 | 23 | // Time comp: O(n) --n being the size of ar 24 | // Space comp: O(m) --m being the size of socks -------------------------------------------------------------------------------- /dictionaries:hashmaps/twoStrings.js: -------------------------------------------------------------------------------- 1 | /* 2 | Given two strings, determine if they share a common substring. 3 | A substring may be as small as one character. 4 | */ 5 | 6 | function twoStrings(s1, s2) { 7 | let set = new Set(); 8 | s1.split('').forEach(value => { 9 | set.add(value); 10 | }); 11 | let strArr = s2.split(''); 12 | for (let i = 0; i < strArr.length; i++) { 13 | if (set.has(strArr[i])) return 'YES'; 14 | } 15 | return 'NO' 16 | } 17 | 18 | /* 19 | Time comp: 20 | - split comp: O(n) -- n being the s1 string length; 21 | - forEach comp: O(n) -- n being the s1 array length; 22 | - for comp: O(m) -- m being the s2 string length; 23 | overall this gives a complexity of O(n+m) 24 | 25 | Space comp: O(n+m) -- n being the s1 string set length and m being the s2 string array length 26 | */ -------------------------------------------------------------------------------- /dp/LC#303 - Range Sum Query - Immutable.js: -------------------------------------------------------------------------------- 1 | // Leetcode easy - solution using dynamic programming 2 | 3 | // Given an integer array nums, handle multiple queries of the following type: 4 | 5 | // Calculate the sum of the elements of nums between indices left and right inclusive where left <= right. 6 | // Implement the NumArray class: 7 | 8 | // NumArray(int[] nums) Initializes the object with the integer array nums. 9 | // int sumRange(int left, int right) Returns the sum of the elements of nums between indices left and right inclusive (i.e. nums[left] + nums[left + 1] + ... + nums[right]). 10 | 11 | var NumArray = function(nums) { 12 | this.nums = nums; 13 | this.memoizedSums = [nums[0]]; 14 | for (let i = 1; i < nums.length; i++) { 15 | this.memoizedSums[i] = this.memoizedSums[i-1] + nums[i]; 16 | } 17 | }; 18 | 19 | NumArray.prototype.sumRange = function(left, right) { 20 | return this.memoizedSums[right] - this.memoizedSums[left] + this.nums[left]; 21 | }; 22 | 23 | 24 | numArray = new NumArray([-2, 0, 3, -5, 2, -1]); 25 | numArray.sumRange(0, 2); // return (-2) + 0 + 3 = 1 26 | numArray.sumRange(2, 5); // return 3 + (-5) + 2 + (-1) = -1 27 | numArray.sumRange(0, 5); // return (-2) + 0 + 3 + (-5) + 2 + (-1) = -3 28 | 29 | // This is an example of dynamic programming, where the ith result can be built upon previous results (i-1th). 30 | // This solution has a time complexity of O(n) since the nums array is passed through only once and the results are stored in the class 31 | // This solution has a space complexity of O(n) since an additional array is created to store the acumulative sums of the input -------------------------------------------------------------------------------- /dp/LC#70 - Climbing Stairs.js: -------------------------------------------------------------------------------- 1 | // Leetcode easy - solution using dynamic programming with memoization 2 | 3 | // You are climbing a staircase. It takes n steps to reach the top. 4 | 5 | // Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top? 6 | 7 | function climbingStairs(n) { 8 | let memo = []; 9 | for (let i = 1; i <= n; i++) { 10 | if (i == 1) { 11 | memo[i] = 1; 12 | } else if (i == 2) { 13 | memo[i] = 2; 14 | } else { 15 | memo[i] = memo[i-1] + memo[i-2]; 16 | } 17 | } 18 | return memo[memo.length-1]; 19 | } 20 | 21 | n = 3; 22 | console.log(climbingStairs(n)); 23 | 24 | // This solution uses dynamic programming, in the sense that the solution for the nth step is built 25 | // upon the solution for n-1th step and n-2th step. 26 | // This solution has a time complexity of O(n) since the solutions for the steps are calculated n times 27 | // This solution has a space complexity of O(n) since an extra array is used for storing the solutions 28 | // for each step. 29 | 30 | // There is also a solution that uses recursion. 31 | 32 | function climbingStairsRecursion(num) { 33 | if (num < 1) return 0; 34 | if (num == 1) { 35 | return 1 36 | } 37 | if (num == 2) { 38 | return 2 39 | } 40 | return climbingStairsRecursion(num-1) + climbingStairsRecursion(num-2); 41 | } -------------------------------------------------------------------------------- /dp/maxSubsetSumNoAdj.js: -------------------------------------------------------------------------------- 1 | /* 2 | Write a function that takes in an array of positive integers and returns 3 | the maximum sum of non-adjacent elements in the array. 4 | 5 | If the input array is empty, the function should return 0. 6 | */ 7 | 8 | function maxSubsetSum(arr) { 9 | if (arr.length === 0) return 0; 10 | if (arr.length === 1) return arr[0]; 11 | if (arr.length === 2) return Math.max(arr[0], arr[1]); 12 | 13 | let second = arr[0]; 14 | let first = Math.max(arr[0], arr[1]); 15 | let curr; 16 | 17 | for (let i = 0; i < arr.length; i++) { 18 | curr = Math.max(first, second + arr[i]); 19 | second = first; 20 | first = curr; 21 | } 22 | 23 | return curr; 24 | } 25 | 26 | // Time comp: O(n) -- n being the size of the input array 27 | // Space comp: O(1) -------------------------------------------------------------------------------- /graphs/LC#133 - Clone Graph.js: -------------------------------------------------------------------------------- 1 | // Leetcode medium - solution using recursion and map 2 | 3 | /* 4 | Given a reference of a node in a connected undirected graph. 5 | 6 | Return a deep copy (clone) of the graph. 7 | 8 | Each node in the graph contains a value (int) and a list (List[Node]) of its neighbors. 9 | 10 | class Node { 11 | public int val; 12 | public List neighbors; 13 | } 14 | 15 | 16 | Test case format: 17 | 18 | For simplicity, each node's value is the same as the node's index (1-indexed). For example, the first node with val == 1, the second node with val == 2, and so on. The graph is represented in the test case using an adjacency list. 19 | 20 | An adjacency list is a collection of unordered lists used to represent a finite graph. Each list describes the set of neighbors of a node in the graph. 21 | 22 | The given node will always be the first node with val = 1. You must return the copy of the given node as a reference to the cloned graph. 23 | */ 24 | 25 | var cloneGraph = function(node) { 26 | let map = new Map(); 27 | return helper(node, map); 28 | }; 29 | 30 | function helper(node, map) { 31 | if (!node) return null; 32 | 33 | if (map.has(node)) return map.get(node); 34 | 35 | let newNode = new Node(node.val); 36 | map.set(node, newNode); 37 | 38 | for (const neighbor of node.neighbors) { 39 | newNode.neighbors.push(helper(neighbor, map)); 40 | } 41 | 42 | return newNode; 43 | } 44 | 45 | // This solution has a time complexity of O(n), n being the amount of nodes present 46 | // This solution has a space complexity of O(n), n being the size of the map (which will contain all nodes) -------------------------------------------------------------------------------- /greedyAlg/LC#121 - Best Time to Buy and Sell Stock.js: -------------------------------------------------------------------------------- 1 | // Leetcode easy - solution using Greedy method, can also be solved using two pointers 2 | 3 | // You are given an array prices where prices[i] is the price of a given stock on the ith day. 4 | 5 | // You want to maximize your profit by choosing a single day to buy one stock and choosing a 6 | // different day in the future to sell that stock. 7 | 8 | //Return the maximum profit you can achieve from this transaction. If you cannot achieve any profit, return 0. 9 | 10 | function maxProfit(prices) { 11 | let minimumStock = prices[0]; 12 | let maxProfit = 0; 13 | 14 | for (let i = 1; i < prices.length;i++) { 15 | if (prices[i] < minimumStock) minimumStock = prices[i]; 16 | if (prices[i] - minimumStock > maxProfit) maxProfit = prices[i] - minimumStock; 17 | } 18 | return maxProfit; 19 | } 20 | 21 | prices = [7,1,5,3,6,4] 22 | console.log(maxProfit(prices)) // 5 23 | 24 | // This solution uses a greedy approach to optimize the solution, we save the lowest stock evaluated 25 | // and from there try to find a higher stock that gives the maximum profit. 26 | // This solution has a time complexity of O(n) since the array is passed through only once. 27 | // This solution has a space complexity of O(1) since no additional data structures are used. 28 | 29 | // This can also be solved using two pointers 30 | 31 | function maxProfitPointers(prices) { 32 | let left = 0; // Buy 33 | let right = 1; // sell 34 | let max_profit = 0; 35 | while (right < prices.length) { 36 | if (prices[left] < prices[right]) { 37 | let profit = prices[right] - prices[left]; // our current profit 38 | 39 | max_profit = Math.max(max_profit, profit); 40 | } else { 41 | left = right; 42 | } 43 | right++; 44 | } 45 | return max_profit; 46 | } -------------------------------------------------------------------------------- /greedyAlg/tandemBicycle.js: -------------------------------------------------------------------------------- 1 | /* 2 | A tandem bicycle is a bicycle that's operated by two people: person A and person B. 3 | Both people pedal the bicycle, but the person that pedals faster dictates the speed of the bicycle. 4 | So if person A pedals at a speed of 5, and person B pedals at a speed of 4, the tandem bicycle 5 | moves at a speed of 5 (i.e., tandemSpeed=max(speedA, speedB) ). 6 | 7 | You're given two lists of positive integers: one that contains the speeds of riders wearing red shirts 8 | and one that contains the speeds of riders wearing blue shirts. Each rider is represented by a single 9 | positive integer, which is the speed that they pedal a tandem bicycle at. Both lists have the same length, 10 | meaning that there are as many red-shirt riders as there are blue-shirt riders. Your goal is to pair every 11 | rider wearing a red shirt with a rider wearing a blue shirt to operate a tandem bicycle. 12 | 13 | Write a function that returns the maximum possible total speed or the minimum possible total speed of all 14 | of the tandem bicycles being ridden based on an input parameter, fastest. If fastest = true, your function 15 | should return the maximum possible total speed; otherwise it should return the minimum total speed. 16 | 17 | "Total speed" is defined as the sum of the speeds of all the tandem bicycles being ridden. For example, 18 | if there are 4 riders (2 red-shirt riders and 2 blue-shirt riders) who have speeds of 1, 3, 4, , and if 19 | paired on tandem bicyc as follows: 20 | 21 | [1, 4], [5, 3], then the total speed of these tandem bicycles is 4 + 5 = 9. 22 | */ 23 | 24 | function tandemBicycle(redShirtSpeeds, blueShirtSpeeds, fastest) { 25 | let sum = 0; 26 | redShirtSpeeds.sort((a, b) => a - b); 27 | blueShirtSpeeds.sort((a, b) => a - b); 28 | const len = redShirtSpeeds.length; 29 | if (fastest) { 30 | for (let i = 0; i < len; i++) { 31 | sum += Math.max(redShirtSpeeds[i], blueShirtSpeeds[len - 1 - i]); 32 | } 33 | } else { 34 | for (let i = len - 1; i >= 0 ; i--) { 35 | sum += Math.max(redShirtSpeeds[i], blueShirtSpeeds[i]); 36 | } 37 | } 38 | return sum; 39 | } 40 | 41 | // Time comp: O(n log n) -- because of sorting using javascript's quicksort implementation 42 | // Space comp: O(1) 43 | -------------------------------------------------------------------------------- /idk/fib.js: -------------------------------------------------------------------------------- 1 | /* 2 | The Fibonacci sequence is defined as follows: the first number of 3 | the sequence is 0, the second number is 1, and the nth number is 4 | the sum of the (n - 1)th and (n - 2)th numbers. Write a function 5 | that takes in an integer n and returns the nth Fibonacci number. 6 | 7 | Important note: the Fibonacci sequence is often defined with its 8 | first two numbers as F0 = 0 and F1 = 1. For the purpose of this 9 | question, the first Fibonacci number is F0; therefore, getNthFib(1) 10 | is equal to F0, getNthFib(2) is equal to F1, etc.. 11 | */ 12 | 13 | function getNthFib(n) { 14 | if (n < 2) return n; 15 | let prev1 = 1; 16 | let prev2 = 0; 17 | let sum; 18 | for (let i = 1; i < n; i++) { 19 | sum = prev1 + prev2; 20 | prev2 = prev1; 21 | prev1 = sum; 22 | } 23 | return sum; 24 | } 25 | 26 | // Time comp: O(n) 27 | // Space comp: O(1) -------------------------------------------------------------------------------- /idk/jewelsAndStones.js: -------------------------------------------------------------------------------- 1 | /* 2 | This question is asked by Amazon. Given a string representing your stones and another 3 | string representing a list of jewels, return the number of stones that you have that are also jewels. 4 | */ 5 | 6 | function jewelsStones(stones, jewels) { 7 | let set = new Set(); 8 | let jewelArray = jewels.split(''); 9 | let count = 0; 10 | for (let i = 0; i < jewelArray.length; i++) { 11 | if (stones.includes(jewelArray[i]) && !set.has(jewelArray[i])) { 12 | count++; 13 | set.add(jewelArray[i]); 14 | } 15 | } 16 | return count; 17 | } 18 | 19 | // Time comp: O(n + m) --n and m being the sizes of the stones and jewels strings 20 | // Space comp: O(m) --m being the size of the jewels string -------------------------------------------------------------------------------- /linkedLists/LC#141 - Linked List Cycle.js: -------------------------------------------------------------------------------- 1 | // Leetcode easy - solution using two pointers (fast/slow) 2 | 3 | /* 4 | Given head, the head of a linked list, determine if the linked list has a cycle in it. 5 | 6 | There is a cycle in a linked list if there is some node in the list that can be reached again by continuously following the next pointer. 7 | Internally, pos is used to denote the index of the node that tail's next pointer is connected to. Note that pos is not passed as a parameter. 8 | 9 | Return true if there is a cycle in the linked list. Otherwise, return false. 10 | */ 11 | 12 | 13 | //Definition for singly-linked list. 14 | function ListNode(val) { 15 | this.val = val; 16 | this.next = null; 17 | } 18 | 19 | var hasCycle = function(head) { 20 | if (!head || !head.next) return false; 21 | let slow = head; 22 | let fast = head.next; 23 | while (slow != fast) { 24 | if (fast == null || fast.next == null) return false; 25 | slow = slow.next; 26 | fast = fast.next.next; 27 | } 28 | 29 | return true; 30 | }; 31 | 32 | // This solution has a time complexity of O(n) since we do a single pass through the linked list. 33 | // This solution has a space complexity of O(1) since we use only two extra helper pointers. -------------------------------------------------------------------------------- /linkedLists/LC#143 - Reorder List.js: -------------------------------------------------------------------------------- 1 | // Leetcode medium - Solved using two pointers (fast/slow) and using the solution for reversing a linked list 2 | 3 | /* 4 | You are given the head of a singly linked-list. The list can be represented as: 5 | 6 | L0 → L1 → … → Ln-1 → Ln 7 | Reorder the list to be on the following form: 8 | 9 | L0 → Ln → L1 → Ln-1 → L2 → Ln-2 → … 10 | You may not modify the values in the list's nodes. Only nodes themselves may be changed. 11 | 12 | Example: 13 | Input: head = [1,2,3,4,5] 14 | Output: [1,5,2,4,3] 15 | */ 16 | 17 | 18 | // Definition for singly-linked list. 19 | function ListNode(val, next) { 20 | this.val = (val===undefined ? 0 : val) 21 | this.next = (next===undefined ? null : next) 22 | } 23 | 24 | var reorderList = function(head) { 25 | let slow = head; 26 | let fast = head; 27 | while (fast.next && fast.next.next) { 28 | slow = slow.next; 29 | fast = fast.next.next; 30 | } 31 | 32 | let prev = null 33 | let curr = slow.next 34 | let next = null 35 | while (curr) { 36 | next = curr.next; 37 | curr.next = prev; 38 | prev = curr; 39 | curr = next; 40 | } 41 | slow.next = null 42 | 43 | let head1 = head; 44 | let head2 = prev; 45 | while (head2) { 46 | let temp = head1.next; 47 | head1.next = head2; 48 | head1 = head2; 49 | head2 = temp; 50 | } 51 | }; 52 | 53 | // This solution has a time complexity of O(n) since we do a full pass only two times of the linked list 54 | // This solution has a space complexity of O(1) since we do not use any additional data structures, only 55 | // a couple of pointers -------------------------------------------------------------------------------- /linkedLists/LC#160 - Intersection of Two Linked Lists.js: -------------------------------------------------------------------------------- 1 | // Leetcode easy - Solution using Set or adding the two lists. 2 | 3 | /* 4 | Given the heads of two singly linked-lists headA and headB, return the node at which the two lists intersect. 5 | If the two linked lists have no intersection at all, return null. 6 | */ 7 | 8 | 9 | //Definition for singly-linked list. 10 | function ListNode(val) { 11 | this.val = val; 12 | this.next = null; 13 | } 14 | 15 | var getIntersectionNode = function(headA, headB) { 16 | let set = new Set(); 17 | 18 | while (headA) { 19 | set.add(headA); 20 | headA = headA.next; 21 | } 22 | 23 | while (headB) { 24 | if (set.has(headB)) return headB; 25 | headB = headB.next; 26 | } 27 | 28 | return null; 29 | }; 30 | 31 | // This solution has a time complexity of O(m+n), m being the length of the first list and n being the length of the second list. 32 | // This solution has a space complexity of O(n), n being the length of the set which contains the node of the first list. 33 | 34 | // There is also another solution which has a time complexity of O(m+n) and a space complexity of O(1): 35 | 36 | var getIntersectionNode = function(headA, headB) { 37 | let a = headA; 38 | let b = headB; 39 | 40 | while(a != b) { 41 | a = !a ? headB : a.next; 42 | b = !b ? headA : b.next; 43 | } 44 | 45 | return a; 46 | }; 47 | 48 | // This solution adds A to B and also B to A, forming a list where inevitably the two pointers will be the same in the second pass 49 | // They will point to the intersection or they will both be null -------------------------------------------------------------------------------- /linkedLists/LC#19 - Remove Nth Node from End of List.js: -------------------------------------------------------------------------------- 1 | // Leetcode medium - solution using two pointers (delayed) 2 | 3 | /* 4 | Given the head of a linked list, remove the nth node from the end of the list and return its head. 5 | */ 6 | 7 | 8 | //Definition for singly-linked list. 9 | function ListNode(val, next) { 10 | this.val = (val===undefined ? 0 : val) 11 | this.next = (next===undefined ? null : next) 12 | } 13 | 14 | var removeNthFromEnd = function(head, n) { 15 | let slow = head; 16 | let fast = head; 17 | for (let i = 0; i < n; i++) fast = fast.next; 18 | if (!fast) return head.next 19 | while(fast.next) { 20 | slow = slow.next; 21 | fast = fast.next; 22 | } 23 | 24 | slow.next = slow.next.next; 25 | return head; 26 | } 27 | 28 | // This solution has a time complexity of O(n) since only a single pass is done through the list 29 | // This solution has a space complexity of O(1) since only two extra pointers are used and it does not change 30 | // with the input 31 | 32 | //////// Other solutions 33 | 34 | // brute force, do a single pass through the linked list, know how many nodes are there 35 | // get the index of the node to be eliminated via size - n, do the pass and remove the node 36 | // time comp: O(2n), space comp: O(1); 37 | 38 | // improved method, do a recursive pass through the linked list, and keep a counter 39 | // initialized in 0, when that counter reaches n, do the removal of the node 40 | 41 | // iterative method, use a stack to get all the nodes, once reached the end then pop every 42 | // node and keep a counter to know which one should be deleted, and then delete it 43 | 44 | // best solution, use two pointers and separate them by n, move the rightmost until the end 45 | // and that would leave the left one just before the node to be removed. set left.next to 46 | // left.next.next and that is it. -------------------------------------------------------------------------------- /linkedLists/LC#2 - Add Two Numbers.js: -------------------------------------------------------------------------------- 1 | // Leetcode medium - solution iterating over the linked lists 2 | 3 | /* 4 | You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order, and each of their nodes contains a single digit. Add the two numbers and return the sum as a linked list. 5 | 6 | You may assume the two numbers do not contain any leading zero, except the number 0 itself. 7 | */ 8 | 9 | // Definition for singly-linked list. 10 | function ListNode(val, next) { 11 | this.val = (val===undefined ? 0 : val) 12 | this.next = (next===undefined ? null : next) 13 | } 14 | 15 | var addTwoNumbers = function(l1, l2) { 16 | let head = new ListNode(null, null); 17 | let curr = head; 18 | 19 | let remainder = 0; 20 | while (l1 || l2) { 21 | let sum = remainder; 22 | if (l1) { 23 | sum += l1.val; 24 | l1 = l1.next; 25 | } 26 | if (l2) { 27 | sum += l2.val; 28 | l2 = l2.next; 29 | } 30 | if (sum > 9) { 31 | curr.next = new ListNode(sum%10); 32 | remainder = 1; 33 | } else { 34 | curr.next = new ListNode(sum); 35 | remainder = 0; 36 | } 37 | curr = curr.next; 38 | } 39 | 40 | if (remainder) curr.next = new ListNode(1); 41 | 42 | return head.next; 43 | }; 44 | 45 | // This solution has a time complexity of O(n), n being the length of the longest linked list 46 | // This solution has a time complexity of O(n), n being the length of the resulting linked list -------------------------------------------------------------------------------- /linkedLists/LC#206 - Reverse Linked List.js: -------------------------------------------------------------------------------- 1 | // Leetcode easy - solved using three pointers and manipulating them 2 | 3 | /* 4 | Given the head of a singly linked list, reverse the list, and return the reversed list. 5 | */ 6 | 7 | //Definition for singly-linked list. 8 | function ListNode(val, next) { 9 | this.val = (val===undefined ? 0 : val) 10 | this.next = (next===undefined ? null : next) 11 | } 12 | 13 | var reverseList = function(head) { 14 | let prev = null; 15 | let curr = head; 16 | let next = null; 17 | 18 | while (curr) { 19 | next = curr.next; 20 | curr.next = prev; 21 | prev = curr; 22 | curr = next; 23 | } 24 | 25 | return prev; 26 | }; 27 | 28 | // This solution has a time complexity of O(n) since we only do a single pass through the linked list 29 | // This solution has a space complexity of O(1) since we only use three aditional extra pointers, no matter the input -------------------------------------------------------------------------------- /linkedLists/LC#21 - Merge Two Sorted Lists.js: -------------------------------------------------------------------------------- 1 | // Leetcode easy - solved using pointer manipulation 2 | 3 | /* 4 | You are given the heads of two sorted linked lists list1 and list2. 5 | 6 | Merge the two lists into one sorted list. The list should be made by splicing together the nodes of the first two lists. 7 | 8 | Return the head of the merged linked list. 9 | */ 10 | 11 | // Definition for singly-linked list. 12 | function ListNode(val, next) { 13 | this.val = (val===undefined ? 0 : val) 14 | this.next = (next===undefined ? null : next) 15 | } 16 | 17 | var mergeTwoLists = function(list1, list2) { 18 | let prev = new ListNode(-1, null) 19 | let curr = prev; 20 | while (list1 && list2) { 21 | if (list1.val < list2.val) { 22 | curr.next = list1; 23 | list1 = list1.next; 24 | } else { 25 | curr.next = list2; 26 | list2 = list2.next; 27 | } 28 | curr = curr.next; 29 | } 30 | curr.next = list1 || list2; 31 | 32 | return prev.next; 33 | }; 34 | 35 | // This solution has a time complexity of O(n+m) n being the length of the list 1 and m being the length of the list 2 36 | // since we only do a single pass through each of the lists 37 | // This solution has a time complexity of O(1) since we only use a single extra dummy ListNode to return the solution -------------------------------------------------------------------------------- /linkedLists/LC#328 - Odd Even Linked List.js: -------------------------------------------------------------------------------- 1 | // Leetcode medium - solved using two pointers (one for odd, one for even) 2 | 3 | /* 4 | Given the head of a singly linked list, group all the nodes with odd indices together followed by the nodes with even indices, and return the reordered list. 5 | 6 | The first node is considered odd, and the second node is even, and so on. 7 | 8 | Note that the relative order inside both the even and odd groups should remain as it was in the input. 9 | 10 | You must solve the problem in O(1) extra space complexity and O(n) time complexity. 11 | 12 | Example 1: 13 | Input: head = [1,2,3,4,5] 14 | Output: [1,3,5,2,4] 15 | 16 | Example 2: 17 | Input: head = [2,1,3,5,6,4,7] 18 | Output: [2,3,6,7,1,5,4] 19 | */ 20 | 21 | //Definition for singly-linked list. 22 | function ListNode(val, next) { 23 | this.val = (val===undefined ? 0 : val) 24 | this.next = (next===undefined ? null : next) 25 | } 26 | 27 | var oddEvenList = function(head) { 28 | if (!head) return head 29 | let odd = head; 30 | let even = head.next; 31 | let evenBackup = even; 32 | 33 | while (even && even.next != null) { 34 | odd.next = even.next; 35 | odd = odd.next; 36 | even.next = odd.next; 37 | even = even.next; 38 | } 39 | 40 | odd.next = evenBackup; 41 | 42 | return head; 43 | }; 44 | 45 | // This solution has a time complexity of O(n), n being the length of the linked list 46 | // This solution has a space complexity of O(1) since only three extra pointers are used, no matter the input -------------------------------------------------------------------------------- /linkedLists/removeDuplicates.js: -------------------------------------------------------------------------------- 1 | /* 2 | You're given the head of a Singly Linked List whose nodes are in sorted order with 3 | respect to their values. Write a function that returns a modified version of the 4 | Linked List that doesn't contain any nodes with duplicate values. The Linked List 5 | should be modified in place (i.e., you shouldn't create a brand new list), and the 6 | modified Linked List should still have its nodes sorted with respect to their values. 7 | 8 | Each LinkedList node has an integer value as well as a next node pointing to the next 9 | node in the list or to None/null if it's the tail of the list. 10 | */ 11 | 12 | class LinkedList { 13 | constructor(value) { 14 | this.value = value; 15 | this.next = null; 16 | } 17 | } 18 | 19 | function removeDuplicates(linkedList) { 20 | let head = linkedList; 21 | let prev = null; 22 | while (head) { 23 | if (!prev || prev.value != head.value) { 24 | prev = head; 25 | head = head.next; 26 | } else { 27 | prev.next = head.next; 28 | head.next = null; 29 | head = prev.next; 30 | } 31 | } 32 | return linkedList; 33 | } 34 | 35 | // Time comp: O(n) -- because we traverse the linked list just once 36 | // Space comp: O(1) -- we only instantiate two extra LinkedList nodes, no matter the input -------------------------------------------------------------------------------- /sorting/markAndToys.js: -------------------------------------------------------------------------------- 1 | /* 2 | Mark and Jane are very happy after having their first child. 3 | Their son loves toys, so Mark wants to buy some. There are a 4 | number of different toys lying in front of him, tagged with 5 | their prices. Mark has only a certain amount to spend, and he 6 | wants to maximize the number of toys he buys with this money. 7 | Given a list of toy prices and an amount to spend, determine 8 | the maximum number of gifts he can buy. 9 | 10 | Note Each toy can be purchased only once. 11 | */ 12 | 13 | 14 | function markAndToys(prices, k) { 15 | prices.sort((a,b) => a - b); 16 | 17 | let money = k; 18 | let cant = 0; 19 | for (let price of prices) { 20 | if (money - price >= 0) { 21 | money -= price; 22 | cant++; 23 | } 24 | } 25 | return cant; 26 | } 27 | 28 | 29 | // Time comp: O(n log n) -- n being the size of the prices array 30 | // Space comp: O(1) -------------------------------------------------------------------------------- /strings/LC#1071 - Greatest Common Divisor of Strings.js: -------------------------------------------------------------------------------- 1 | // For two strings s and t, we say "t divides s" if and only if s = t + t + t + ... + t + t (i.e., t is concatenated with itself one or more times). 2 | 3 | // Given two strings str1 and str2, return the largest string x such that x divides both str1 and str2. 4 | 5 | function greatestCommonDivisor(str1, str2) { 6 | if (str1 + str2 != str2 + str1) return ''; 7 | 8 | let len1 = str1.length; 9 | let len2 = str2.length; 10 | 11 | let gdc = euclidean(len1, len2); 12 | 13 | return str1.substring(0, gdc); 14 | } 15 | 16 | function euclidean(num1, num2) { 17 | if (!num2) { 18 | return num1 19 | } 20 | 21 | return euclidean (num2, num1 % num2) 22 | } 23 | 24 | str1 = "ABCABCABC" 25 | str2 = "ABC" 26 | console.log(greatestCommonDivisor(str1, str2)); 27 | 28 | // This algorithm makes use of the Euclidean algorithm, which is used to obtain the greatest common divisor between two numbers. 29 | // First, we check if str1 + str2 is equal to str2 + str1, because if they are not equal that means that there is no common prefix between the two strings. 30 | // If they are equal, the euclidean algorithm is used to recursively find the greatest common divisor between the two numbers. 31 | 32 | // The space complexity is O(m), m being the amount of divisions done in the euclidean algorithm -------------------------------------------------------------------------------- /strings/LC#1249 - Minimum Remove to Make Valid Parentheses.js: -------------------------------------------------------------------------------- 1 | // Given a string s of '(' , ')' and lowercase English characters. 2 | 3 | // Your task is to remove the minimum number of parentheses ( '(' or ')', in any positions ) so 4 | // that the resulting parentheses string is valid and return any valid string. 5 | 6 | // Formally, a parentheses string is valid if and only if: 7 | 8 | // It is the empty string, contains only lowercase characters, or 9 | // It can be written as AB (A concatenated with B), where A and B are valid strings, or 10 | // It can be written as (A), where A is a valid string. 11 | 12 | 13 | function minRemoveToMakeValid(s) { 14 | let stack = []; 15 | let len = s.length; 16 | let res = ''; 17 | 18 | for (let i = 0; i < len; i++) { 19 | if (s[i] == '(') { 20 | stack.push(i); 21 | } else if (s[i] == ')') { 22 | if (stack.length && s[stack[stack.length -1]] == '(') { 23 | stack.pop() 24 | } else { 25 | stack.push(i) 26 | } 27 | } 28 | } 29 | 30 | for (let i = 0; i < len; i++) { 31 | if (stack.length && i == stack[0]) { 32 | stack.shift() 33 | continue 34 | } 35 | res += s[i]; 36 | } 37 | 38 | return res; 39 | } 40 | 41 | s = "lee(t(c)o)de)" 42 | console.log(minRemoveToMakeValid(s)); 43 | 44 | // The time complexity of this solution is O(2n), since we traverse the string twice, but we remove the 45 | // constant so the time complexity is O(n) 46 | // The space complexity is O(n) since we create another string where the result ends up being 47 | -------------------------------------------------------------------------------- /strings/LC#125 - Valid Palindrome.js: -------------------------------------------------------------------------------- 1 | // Leetcode easy -- solution using charCodes 2 | 3 | /* 4 | A phrase is a palindrome if, after converting all uppercase letters into lowercase letters and removing all non-alphanumeric characters, it reads the same forward and backward. Alphanumeric characters include letters and numbers. 5 | 6 | Given a string s, return true if it is a palindrome, or false otherwise. 7 | */ 8 | 9 | function validPalindrome(s) { 10 | str = []; 11 | for (const char of s) { 12 | const charCode = char.toLowerCase().charCodeAt(); 13 | if ((charCode >= 48 && charCode <= 57) || (charCode >= 97 && charCode <= 122)) { 14 | str.push(char.toLowerCase()); 15 | } 16 | } 17 | 18 | for (let i = 0; i < Math.floor(str.length / 2); i++) { 19 | if (str[i] != str[str.length-1-i]) return false; 20 | } 21 | return true; 22 | } 23 | 24 | // Time comp: O(n) 25 | // Space comp: O(n) -------------------------------------------------------------------------------- /strings/LC#1456 - Maximum Number of Vowels in a Substring of Given Length.js: -------------------------------------------------------------------------------- 1 | // Leetcode medium - solution using sliding window 2 | 3 | // Given a string s and an integer k, return the maximum number of vowel letters in any substring of s with length k. 4 | 5 | // Vowel letters in English are 'a', 'e', 'i', 'o', and 'u'. 6 | 7 | function maxVowels(s, k) { 8 | let maxNum = 0; 9 | 10 | for (let i = 0; i < k; i++) { 11 | maxNum += checkIfVowel(s[i]) ? 1 : 0; 12 | } 13 | 14 | let currNum = maxNum; 15 | for (let i = k; i < s.length; i++) { 16 | let first = s[i-k]; 17 | if (checkIfVowel(first)) currNum--; 18 | if (checkIfVowel(s[i])) currNum++; 19 | if (currNum > maxNum) maxNum = currNum; 20 | } 21 | 22 | return maxNum; 23 | } 24 | 25 | function checkIfVowel(string) { 26 | switch (string) { 27 | case 'a': 28 | return true; 29 | case 'e': 30 | return true; 31 | case 'i': 32 | return true; 33 | case 'o': 34 | return true; 35 | case 'u': 36 | return true; 37 | default: 38 | return false; 39 | } 40 | } 41 | 42 | s = "abciiidef" 43 | k = 3 44 | console.log(maxVowels(s, k)) // 3 45 | 46 | /* 47 | This solution uses a sliding window approach, first we take the first k chars of the string and evaluate if there are vowels in it and store the sum. 48 | Then we check the rest of the string, and substract from the sum if the char that left the window was a vowel, and add to the sum if the char that 49 | entered the window was a vowel. 50 | This solution has a time complexity of O(n) since we only go through the array once, and the vowel array is constant. 51 | This solution has a space complexity of O(1) since the only extra data structure we use is the vowel array, but it always has a constant number of 52 | items so it is considered constant. 53 | */ -------------------------------------------------------------------------------- /strings/LC#151 - Reverse Words in a String.js: -------------------------------------------------------------------------------- 1 | // Leetcode medium 2 | 3 | // Given an input string s, reverse the order of the words. 4 | // A word is defined as a sequence of non-space characters. The words in s will be separated by at least one space. 5 | // Return a string of the words in reverse order concatenated by a single space. 6 | // Note that s may contain leading or trailing spaces or multiple spaces between two words. 7 | // The returned string should only have a single space separating the words. Do not include any extra spaces. 8 | 9 | function reverseWords(s) { 10 | let len = s.length; 11 | let res = '' 12 | let current = '' 13 | 14 | for (let i = 0; i < len; i++) { 15 | if (s[i] == ' ' && current == '') continue; 16 | if (s[i] == ' ' && current != '') { 17 | res = res == '' ? current : current + ' ' + res 18 | current = ''; 19 | } else { 20 | current = current+s[i]; 21 | } 22 | } 23 | 24 | if (current != '') { 25 | res = res == '' ? current : current + ' ' + res 26 | } 27 | return res; 28 | } 29 | 30 | // This solution does not use any javascript array function for splitting or joining. A single pass through the string is done so it has O(n) time complexity. 31 | // The space complexity is O(n) since a new string is used for reversing the original one. -------------------------------------------------------------------------------- /strings/LC#1768 - Merge Strings Alternatively.js: -------------------------------------------------------------------------------- 1 | // You are given two strings word1 and word2. Merge the strings by adding letters in alternating order, starting with word1. 2 | // If a string is longer than the other, append the additional letters onto the end of the merged string. 3 | 4 | // Return the merged string. 5 | 6 | function mergeAlternatively(word1, word2) { 7 | let res = ''; 8 | let idx1 = 0; 9 | let idx2 = 0; 10 | while (idx1 < word1.length || idx2 < word2.length) { 11 | if (idx1 < word1.length) { 12 | res += word1[idx1]; 13 | idx1++; 14 | } 15 | 16 | if (idx2 < word2.length) { 17 | res += word2[idx2]; 18 | idx2++; 19 | } 20 | } 21 | 22 | return res; 23 | } 24 | 25 | // This solution is O(n+m) in time complexity since it runs over both strings a single time. In space complexity this would also be O(n+m) since there is a 26 | // new variable which will contain the both strings merged. -------------------------------------------------------------------------------- /strings/LC#20 - Valid Parentheses.js: -------------------------------------------------------------------------------- 1 | // Leetcode easy - solution using stack 2 | 3 | /* 4 | Given a string s containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid. 5 | 6 | An input string is valid if: 7 | 8 | 1. Open brackets must be closed by the same type of brackets. 9 | 2. Open brackets must be closed in the correct order. 10 | 3. Every close bracket has a corresponding open bracket of the same type. 11 | */ 12 | 13 | function isValid(s) { 14 | let stack = []; 15 | 16 | for (const char of s) { 17 | if (char == '[' || char == '{' || char == '(') { 18 | stack.push(char); 19 | } else { 20 | if (!stack.length) return false; 21 | const pop = stack.pop(); 22 | if (char == ']' && pop != '[') return false; 23 | if (char == '}' && pop != '{') return false; 24 | if (char == ')' && pop != '(') return false; 25 | } 26 | } 27 | 28 | if (stack.length) return false; 29 | 30 | return true; 31 | } 32 | 33 | // This solution has a time complexity of O(n) since we do a single pass through all the chars of the string 34 | // This solution has a space complexity of O(n) since we store a stack that can have the entire string in the worst case -------------------------------------------------------------------------------- /strings/LC#242 - Valid Anagram.js: -------------------------------------------------------------------------------- 1 | // Leetcode easy - solved using hashmaps 2 | 3 | /* 4 | Given two strings s and t, return true if t is an anagram of s, and false otherwise. 5 | 6 | An Anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once. 7 | */ 8 | 9 | var isAnagram = function(s, t) { 10 | const len = s.length; 11 | if (len != t.length) return false; 12 | 13 | let dict1 = new Map() 14 | let dict2 = new Map() 15 | 16 | for (let i = 0; i < len; i++) { 17 | if (dict1.has(s[i])) { 18 | dict1.set(s[i], dict1.get(s[i]) + 1); 19 | } else { 20 | dict1.set(s[i], 1); 21 | } 22 | 23 | if (dict2.has(t[i])) { 24 | dict2.set(t[i], dict2.get(t[i]) + 1); 25 | } else { 26 | dict2.set(t[i], 1); 27 | } 28 | } 29 | 30 | let keys = dict1.keys(); 31 | 32 | for (const key of keys) { 33 | if (dict1.get(key) != dict2.get(key)) return false; 34 | } 35 | 36 | return true; 37 | }; 38 | 39 | s = 'anagram' 40 | t = 'nagaram' 41 | console.log(isAnagram(s, t)); 42 | 43 | // This solution has a time complexity of O(n), being n the length of any of the two strings 44 | // This solution has a space complexity of O(n) in the worst case (if there are no repeated chars in any of the strings) -------------------------------------------------------------------------------- /strings/LC#3 - Longest Substring Without Repeating Characters.js: -------------------------------------------------------------------------------- 1 | // Leetcode medium - solution using a set, two pointers to manage a sliding window 2 | 3 | /* 4 | Given a string s, find the length of the longest substring without repeating characters. 5 | */ 6 | 7 | function lengthOfLongestSubstring(s) { 8 | let left = 0; 9 | let right = 0; 10 | let set = new Set(); 11 | let max = 0; 12 | 13 | while (right < s.length) { 14 | while (set.has(s[right])) { 15 | set.delete(s[left]); 16 | left++; 17 | } 18 | set.add(s[right]); 19 | right++; 20 | if (right - left > max) max = right - left 21 | } 22 | 23 | return max; 24 | } 25 | 26 | s = "zxyzxyz" 27 | console.log(lengthOfLongestSubstring(s)) // 3 28 | 29 | // This solution has a time complexity of O(n), since we only do a single pass through every char of the string 30 | // This solution has a space complexity of O(n), since we use two pointers and a set that can change depending 31 | // on the input, and in the worst case can be the size of the input string -------------------------------------------------------------------------------- /strings/LC#38 - Count and Say.js: -------------------------------------------------------------------------------- 1 | // Leetcode medium - solution using iteration and string manipulation; 2 | 3 | /* 4 | The count-and-say sequence is a sequence of digit strings defined by the recursive formula: 5 | 6 | countAndSay(1) = "1" 7 | countAndSay(n) is the run-length encoding of countAndSay(n - 1). 8 | Run-length encoding (RLE) is a string compression method that works by replacing consecutive identical 9 | characters (repeated 2 or more times) with the concatenation of the character 10 | and the number marking the count of the characters (length of the run). 11 | For example, to compress the string "3322251" we replace "33" with "23", replace "222" with "32", 12 | replace "5" with "15" and replace "1" with "11". Thus the compressed string becomes "23321511". 13 | 14 | Given a positive integer n, return the nth element of the count-and-say sequence. 15 | */ 16 | 17 | var countAndSay = function(n) { 18 | if (n == 1) return "1" 19 | let start = '1'; 20 | 21 | for (let i = 0; i < n-1; i++) { 22 | start = RLE(start); 23 | } 24 | 25 | return start; 26 | }; 27 | 28 | function RLE (str) { 29 | let res = '' 30 | let curr = ''; 31 | let amount = 0; 32 | for (const char of str) { 33 | if (char == curr) { 34 | amount++; 35 | } else { 36 | res += amount+curr; 37 | curr = char; 38 | amount = 1; 39 | } 40 | } 41 | 42 | res += amount+curr; 43 | 44 | return res.substring(1); 45 | } 46 | 47 | // This solution has a time complexity of O(n*m), n being the amount of times the RLE must be done and m being the length of the RLE of every past iteration. 48 | // This solution has a space complexity of O(n), n being the length of the resulting string of the RLE -------------------------------------------------------------------------------- /strings/LC#392 - Is Subsequence.js: -------------------------------------------------------------------------------- 1 | // Leetcode easy 2 | 3 | // Given two strings s and t, return true if s is a subsequence of t, or false otherwise. 4 | // A subsequence of a string is a new string that is formed from the original string by deleting 5 | // some (can be none) of the characters without disturbing the relative positions of the remaining characters. 6 | // (i.e., "ace" is a subsequence of "abcde" while "aec" is not). 7 | 8 | function isSubsequence(s, t) { 9 | if (s && !t) return false; 10 | if (!s && t) return true; 11 | 12 | let sPointer = 0; 13 | let tPointer = 0; 14 | while (sPointer < s.length && tPointer < t.length) { 15 | if (t[tPointer] == s[sPointer]) { 16 | sPointer++; 17 | } 18 | tPointer++; 19 | } 20 | 21 | return sPointer === s.length; 22 | } 23 | 24 | // This solution uses two pointers to solve it, a pointer for each string, and then we compare each string. 25 | // If the pointer of the smaller string does not reach the end, that means that it is not a subsequence of 26 | // the bigger string. 27 | 28 | // Time complexity is O(n), n being the length of the bigger string since we need to check each character 29 | // Space complexity is O(1) since we only use a couple of variables and these do not change with the input. -------------------------------------------------------------------------------- /strings/LC#424 - Longest Repeating Character Replacement.js: -------------------------------------------------------------------------------- 1 | // Leetcode medium - solution using sliding window and hashmap 2 | 3 | /* 4 | You are given a string s and an integer k. You can choose any character of the string and change it to any other uppercase English character. 5 | You can perform this operation at most k times. 6 | 7 | Return the length of the longest substring containing the same letter you can get after performing the above operations. 8 | */ 9 | 10 | function characterReplacement(s, k) { 11 | let left = 0; 12 | let right = 0; 13 | 14 | let len = s.length; 15 | let map = new Map(); 16 | 17 | let mostRepeated = 0; 18 | let longest = 0; 19 | 20 | while (right < len) { 21 | while (right - left - mostRepeated > k) { 22 | let quantity = map.get(s[left]); 23 | if (quantity == 1) { 24 | map.delete(s[left]); 25 | } else { 26 | map.set(s[left], map.get(s[left]) - 1); 27 | } 28 | left++; 29 | } 30 | 31 | if (!map.has(s[right])) { 32 | map.set(s[right], 1); 33 | } else { 34 | map.set(s[right], map.get(s[right]) + 1); 35 | } 36 | 37 | mostRepeated = Math.max(mostRepeated, map.get(s[right])); 38 | right++; 39 | 40 | if (right - left - mostRepeated <= k) longest = Math.max(longest, right-left) 41 | } 42 | 43 | return longest; 44 | } 45 | 46 | // This solution has a time complexity of O(n), since it does a single pass through the string. There is a while loop inside another while loop, but the 47 | // logic of the loops dictate that the worst case scenario, the complexity would be O(2n), which is the same as O(n) 48 | // This solution has a space complexity of O(n) since we have a map that stores the frequencies of the chars. -------------------------------------------------------------------------------- /strings/countingValleys.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | An avid hiker keeps meticulous records of their hikes. During the last hike 4 | that took exactly n steps, for every step it was noted if it was an uphill, U, or a downhill, D step. 5 | Hikes always start and end at sea level, and each step up or down represents a unit change in altitude. 6 | We define the following terms: 7 | 8 | A mountain is a sequence of consecutive steps above sea level, starting with a step up from 9 | sea level and ending with a step down to sea level. 10 | A valley is a sequence of consecutive steps below sea level, starting with a step down from 11 | sea level and ending with a step up to sea level. 12 | Given the sequence of up and down steps during a hike, find and print the number of valleys walked through. 13 | */ 14 | 15 | function countingValleys(steps, path) { 16 | let acum = 0; 17 | let countValleys = 0; 18 | for (let i = 0; i < steps; i++){ 19 | if (path[i] == 'U') { 20 | acum++; 21 | if (acum == 0) { 22 | countValleys++ 23 | } 24 | } else { 25 | acum--; 26 | } 27 | } 28 | return countValleys; 29 | } 30 | 31 | 32 | // Time comp: O(n) -- n being the size of path 33 | // Space comp: O(1) -------------------------------------------------------------------------------- /strings/repeatedString.js: -------------------------------------------------------------------------------- 1 | /* 2 | There is a string, s, of lowercase English letters 3 | that is repeated infinitely many times. 4 | Given an integer, , find and print the number of 5 | letter a's in the first letters of the infinite string. 6 | */ 7 | 8 | function repeatedString(s, n) { 9 | const len = s.length; 10 | let accum = 0; 11 | let remainderAccum = 0; 12 | const remainder = n % len; 13 | for (let i = 0; i < len; i++) { 14 | if (s[i] == 'a') { 15 | if (i < remainder) remainderAccum++; 16 | accum++; 17 | } 18 | } 19 | accum = accum * (Math.floor(n/len)); 20 | return accum + remainderAccum; 21 | } 22 | 23 | // Time comp: O(s) -- s being the length of the string, we go through each character of the string 24 | // Space comp: O(1) -------------------------------------------------------------------------------- /strings/reverseString.js: -------------------------------------------------------------------------------- 1 | // Turing test 2 | 3 | /* 4 | Given a string S, return the "reversed" string where all characters that are not a letter stay in the same place, and 5 | all letter reverse their positions 6 | 7 | Example 1: 8 | Input: "ab-cd" 9 | Output: "dc-ba" 10 | 11 | Example 2: 12 | Input: "a-bC-dEf=ghlj!!" 13 | Output: "j-lh-gfE=dCba!!" 14 | */ 15 | 16 | function reverse(s) { 17 | let len = s.length; 18 | let nonLetterMap = new Map(); 19 | let charStack = []; 20 | 21 | for (let i = 0; i < len; i++) { 22 | let char = s[i] 23 | let charCode = char.charCodeAt(); 24 | if ((charCode >= 97 && charCode <= 122) || (charCode >= 65 && charCode <=90)) { // it is a letter 25 | charStack.push(char) 26 | } else { 27 | nonLetterMap.set(i, char) 28 | } 29 | } 30 | 31 | let newString = ''; 32 | for (let i = 0; i < len; i++) { 33 | if (nonLetterMap.has(i)) { 34 | newString += nonLetterMap.get(i); 35 | nonLetterMap.delete(i); 36 | } else { 37 | newString += charStack.pop(); 38 | } 39 | } 40 | 41 | return newString; 42 | } 43 | 44 | s = "a-bC-dEf=ghlj!!" 45 | console.log(reverse(s)); // "j-lh-gfE=dCba!!" -------------------------------------------------------------------------------- /strings/vacummCleanerRoute.js: -------------------------------------------------------------------------------- 1 | /* 2 | This question is asked by Amazon. Given a string representing the 3 | sequence of moves a robot vacuum makes, return whether or not it 4 | will return to its original position. The string will only contain 5 | L, R, U, and D characters, representing left, right, up, and down respectively. 6 | */ 7 | 8 | function vacuumCleaner(str) { 9 | let vertAccum = 0; 10 | let horAccum = 0; 11 | for (let i = 0; i < str.length; i++) { 12 | switch (str[i]) { 13 | case 'U': 14 | vertAccum++; 15 | break; 16 | case 'D': 17 | vertAccum--; 18 | break; 19 | case 'R': 20 | horAccum++; 21 | break; 22 | default: 23 | horAccum--; 24 | break; 25 | } 26 | } 27 | return (vertAccum == 0 && horAccum == 0); 28 | } 29 | 30 | //Time comp: O(n) -- n being the length of the string 31 | //Space comp: O(1) -------------------------------------------------------------------------------- /trees/LC#100 - Same Tree.js: -------------------------------------------------------------------------------- 1 | // Leetcode easy - solution using recursion 2 | 3 | /* 4 | Given the roots of two binary trees p and q, write a function to check if they are the same or not. 5 | 6 | Two binary trees are considered the same if they are structurally identical, and the nodes have the same value. 7 | */ 8 | 9 | 10 | //Definition for a binary tree node. 11 | function TreeNode(val, left, right) { 12 | this.val = (val===undefined ? 0 : val) 13 | this.left = (left===undefined ? null : left) 14 | this.right = (right===undefined ? null : right) 15 | } 16 | 17 | var isSameTree = function(p, q) { 18 | if (!p && !q) return true; 19 | if (!p || !q || p.val != q.val) return false; 20 | 21 | return isSameTree(p.left, q.left) && isSameTree(p.right, q.right) 22 | }; 23 | 24 | // This solution has a time complexity of O(n), n being the size of the tree/s 25 | // This solution has a space complexity of O(n), n being the farthest node of the tree/s -------------------------------------------------------------------------------- /trees/LC#102 - Binary Tree Level Order Traversal.js: -------------------------------------------------------------------------------- 1 | // Leetcode medium - solution using queue and breadth first search 2 | 3 | /* 4 | Given the root of a binary tree, return the level order traversal of its nodes' values. 5 | (i.e., from left to right, level by level). 6 | */ 7 | 8 | 9 | // Definition for a binary tree node. 10 | function TreeNode(val, left, right) { 11 | this.val = (val===undefined ? 0 : val) 12 | this.left = (left===undefined ? null : left) 13 | this.right = (right===undefined ? null : right) 14 | } 15 | 16 | var levelOrder = function(root) { 17 | if (root == null) return [] 18 | let queue = [root] 19 | let res = [] 20 | while (queue.length) { 21 | let len = queue.length; 22 | let currRes = []; 23 | for (let i = 0; i < len; i++) { 24 | let curr = queue.shift() 25 | currRes.push(curr.val); 26 | if (curr.left) queue.push(curr.left); 27 | if (curr.right) queue.push(curr.right); 28 | } 29 | res.push(currRes); 30 | } 31 | return res; 32 | }; 33 | 34 | // This solution has a time complexity of O(n), n being the amount of elements of the tree since we do a pass 35 | // through all of them and we use the Array.shift operation which is also O(n) because it moves all elements 36 | // one index 37 | // This solution has a space complexity of O(n), since the answer array also contains all the elements present 38 | // in the tree. And if the answer array does not count, then it would be O(m), m being the amount of nodes 39 | // on the largest level of the tree. -------------------------------------------------------------------------------- /trees/LC#226 - Invert Binary Tree.js: -------------------------------------------------------------------------------- 1 | // Leetcode easy - solved using recursion 2 | 3 | // Given the root of a binary tree, invert the tree, and return its root. 4 | 5 | function TreeNode(val, left, right) { 6 | this.val = (val===undefined ? 0 : val) 7 | this.left = (left===undefined ? null : left) 8 | this.right = (right===undefined ? null : right) 9 | } 10 | function invertTree(root) { 11 | if (root == null) return root; 12 | 13 | root.left = invertTree(root.left); 14 | root.right = invertTree(root.right); 15 | 16 | [root.left, root.right] = [root.right, root.left]; 17 | return root; 18 | } 19 | 20 | root = new TreeNode(4) 21 | root.left = new TreeNode(2); root.right = new TreeNode(7); 22 | root.left.left = new TreeNode(1); root.left.right = new TreeNode(3) 23 | root.right.left = new TreeNode(6); root.right.right = new TreeNode(9) 24 | 25 | /* 26 | This algorithm uses recursion to solve the problem, by using recursion we go into each child node of every node and exchange their children. 27 | This algorithm has a time complexity of O(n) since we go through every node of the tree. 28 | This algorithm has a space complexity of O(m), m being the number of levels of the tree since that is the deepest level the call stack will go. 29 | */ 30 | 31 | 32 | 33 | // This can also be done using BFS or DFS 34 | 35 | // DFS 36 | function invertTreeDFS(root) { 37 | const stack = [root]; 38 | 39 | while (stack.length) { 40 | const n = stack.pop(); 41 | if (n != null) { 42 | [n.left, n.right] = [n.right, n.left]; 43 | stack.push(n.left, n.right); 44 | } 45 | } 46 | 47 | return root; 48 | } 49 | 50 | // BFS 51 | function invertTreeBFS(root) { 52 | const queue = [root]; 53 | 54 | while (queue.length) { 55 | const n = queue.shift(); 56 | if (n != null) { 57 | [n.left, n.right] = [n.right, n.left]; 58 | queue.push(n.left, n.right); 59 | } 60 | } 61 | 62 | return root; 63 | } -------------------------------------------------------------------------------- /trees/LC#230 - Kth Smallest Element in a BST.js: -------------------------------------------------------------------------------- 1 | // Leetcode medium - solution using recursion and traversing the tree first through its left nodes 2 | 3 | /* 4 | Given the root of a binary search tree, and an integer k, return the kth smallest value (1-indexed) 5 | of all the values of the nodes in the tree. 6 | */ 7 | 8 | // Definition for a binary tree node. 9 | function TreeNode(val, left, right) { 10 | this.val = (val===undefined ? 0 : val) 11 | this.left = (left===undefined ? null : left) 12 | this.right = (right===undefined ? null : right) 13 | } 14 | 15 | var kthSmallest = function(root, k) { 16 | let stack = []; 17 | 18 | helper(root, stack); 19 | 20 | return stack[k-1]; 21 | }; 22 | 23 | function helper(root, stack){ 24 | if (!root) return; 25 | 26 | helper(root.left, stack); 27 | 28 | stack.push(root.val) 29 | 30 | helper(root.right, stack); 31 | } 32 | 33 | // This solution has a time complexity of O(n) since it moves through all the nodes of the tree. 34 | // This solution has a space complexity of O(n) since the array will store the nodes of the tree. -------------------------------------------------------------------------------- /trees/LC#572 - Subtree of Another Tree.js: -------------------------------------------------------------------------------- 1 | // Leetcode easy - solution using a stack and then checking recursively 2 | 3 | /* 4 | Given the roots of two binary trees root and subRoot, return true if there is a subtree of root with the same structure 5 | and node values of subRoot and false otherwise. 6 | 7 | A subtree of a binary tree tree is a tree that consists of a node in tree and all of this node's descendants. 8 | The tree tree could also be considered as a subtree of itself. 9 | */ 10 | 11 | var isSubtree = function(root, subRoot) { 12 | let stack = [root]; 13 | let check = false; 14 | while(stack.length) { 15 | let curr = stack.pop(); 16 | curr.left && stack.push(curr.left); 17 | curr.right && stack.push(curr.right); 18 | 19 | if (curr.val == subRoot.val) { 20 | check = checkSubtrees(curr, subRoot); 21 | } 22 | if (check == true) return check; 23 | } 24 | 25 | return false; 26 | } 27 | 28 | function checkSubtrees(root, subroot) { 29 | if (!root && !subroot) return true; 30 | if ((!root && subroot) || root && !subroot) return false; 31 | 32 | if (root.val != subroot.val) return false; 33 | return checkSubtrees(root.left, subroot.left) && checkSubtrees(root.right, subroot.right); 34 | } 35 | 36 | // This solution has a time complexity of O(n+m) n being the nodes of the root tree and m being the nodes of the subroot tree 37 | // This solution has a space complexity of O(n+m) n being the nodes of the root tree that are saved in the stack and m being the depth 38 | // of the subroot tree once it is traversed recursively -------------------------------------------------------------------------------- /trees/LC#94 - Binary Tree Inorder Traversal.js: -------------------------------------------------------------------------------- 1 | // Leetcode easy - solution using recursion or stack 2 | 3 | /* 4 | Given the root of a binary tree, return the inorder traversal of its nodes' values. 5 | */ 6 | 7 | // Definition for a binary tree node. 8 | function TreeNode(val, left, right) { 9 | this.val = (val===undefined ? 0 : val) 10 | this.left = (left===undefined ? null : left) 11 | this.right = (right===undefined ? null : right) 12 | } 13 | 14 | var inorderTraversal = function(root) { 15 | let res = []; 16 | helper(root, res); 17 | return res; 18 | }; 19 | 20 | function helper(root, arr) { 21 | if (!root) return; 22 | helper(root.left, arr); 23 | arr.push(root.val); 24 | helper(root.right, arr); 25 | } 26 | 27 | // This solution is using recursion, and has a time complexity of O(n) since it goes through every node of the tree. 28 | // This solution has a space complexity of O(n), n being the deepest level of the tree. 29 | 30 | // This can also be solved iteratively, using a stack: 31 | 32 | var inorderTraversalIterative = function(root) { 33 | let stack = []; 34 | let res = []; 35 | 36 | while (root || stack.length > 0) { 37 | if (root) { 38 | stack.push(root) 39 | root = root.left; 40 | } else { 41 | root = stack.pop(); 42 | res.push(root.val); 43 | root = root.right; 44 | } 45 | } 46 | 47 | return res; 48 | }; 49 | 50 | // This solution has a time complexity of O(n), n being the amount of nodes the tree has 51 | // This solution has a space complexity of O(n), n being the deepest level of the tree -------------------------------------------------------------------------------- /trees/LC#98 - Validate Binary Search Tree.js: -------------------------------------------------------------------------------- 1 | // Leetcode medium - solution using recursion and depth first search 2 | 3 | /* 4 | Given the root of a binary tree, determine if it is a valid binary search tree (BST). 5 | 6 | A valid BST is defined as follows: 7 | 8 | - The left subtreeof a node contains only nodes with keys less than the node's key. 9 | - The right subtree of a node contains only nodes with keys greater than the node's key. 10 | - Both the left and right subtrees must also be binary search trees. 11 | */ 12 | 13 | 14 | //Definition for a binary tree node. 15 | function TreeNode(val, left, right) { 16 | this.val = (val===undefined ? 0 : val) 17 | this.left = (left===undefined ? null : left) 18 | this.right = (right===undefined ? null : right) 19 | } 20 | 21 | var isValidBST = function(root, min = -Infinity, max = Infinity) { 22 | if (!root) return true; 23 | if (root.val <= min || root.val >= max) return false; 24 | 25 | return isValidBST(root.left, min, root.val) && isValidBST(root.right, root.val, max) 26 | }; 27 | 28 | // This solution has a time complexity of O(n), n being the amount of nodes in the tree since we do a full pass 29 | // on every node 30 | // This solution has a space complexity of O(n), n being the amount of levels of the tree, since the 31 | // recursion stack call will be that size at most. --------------------------------------------------------------------------------