├── .eslintrc ├── .gitignore ├── ArraysAndStrings ├── arrayQuadrupletSum │ ├── prompt.md │ ├── solution.js │ └── test.js ├── binarySearch │ ├── prompt.md │ ├── solution.go │ ├── solution.js │ └── test.js ├── budgetCuts │ ├── prompt.md │ ├── solution.js │ └── test.js ├── findAllPalindromeSubstrings │ ├── prompt.md │ ├── solution.js │ └── test.js ├── flattenDictionary │ ├── prompt.md │ └── solution.js ├── kEmptySlots │ └── prompt.md ├── longestIncreasingSubsequence │ ├── prompt.md │ └── solution.js ├── longestSubstringWithAtMostKDistinctCharacters │ ├── prompt.md │ └── solution.js ├── matchingBrackets │ ├── prompt.md │ ├── solution.go │ └── solution.js ├── maxSlidingWindow │ ├── prompt.md │ ├── solution.js │ └── test.js ├── minNumberOfJumps │ ├── prompt.md │ └── solution.js ├── moveZerosToLeft │ ├── prompt.md │ ├── solution.js │ └── test.js ├── pairSum │ ├── prompt.md │ ├── solution.go │ ├── solution.js │ └── test.js ├── palindrome │ ├── prompt.md │ ├── solution.go │ ├── solution.js │ └── test.js ├── plusOne │ ├── prompt.md │ ├── solution.js │ └── test.js ├── powerSet │ ├── prompt.md │ ├── solution.go │ └── solution.js ├── rainWater │ ├── prompt.md │ └── solution.js ├── repeatedStringMatch │ ├── prompt.md │ └── solution.js ├── rotateArray │ ├── prompt.md │ ├── solution.js │ └── test.js ├── searchRotatedArray │ ├── prompt.md │ ├── solution.js │ └── test.js ├── sentenceReverse │ ├── prompt.md │ └── solution.js ├── smallestCommonNumber │ ├── prompt.md │ ├── solution.js │ └── test.js ├── smallestDifference │ ├── prompt.md │ ├── solution.go │ └── solution.js ├── spiralMatrix │ ├── prompt.md │ └── solution.js └── stringSegmentation │ ├── prompt.md │ └── solution.js ├── Design ├── medianDataStream │ ├── prompt.md │ └── solution.js ├── movingAverageDataStream │ ├── prompt.md │ └── solution.js └── rangeSumQuery │ ├── prompt.md │ └── solution.js ├── DynamicProgramming ├── fibonacci │ ├── prompt.md │ ├── solution.go │ └── solution.js ├── levenshteinDistance │ ├── prompt.md │ └── solution.js ├── maxProfitWithKTransactions │ ├── prompt.md │ ├── solution.js │ └── test.js ├── palindromePartitioningMinCuts │ ├── prompt.md │ ├── solution.js │ └── test.js ├── rodCutting │ ├── prompt.md │ └── solution.js ├── tripleStep │ ├── prompt.md │ ├── solution.js │ └── test.js └── wordBreak │ ├── prompt.md │ └── solution.js ├── LICENSE ├── LinkedLists ├── deleteNode │ ├── prompt.md │ ├── solution.js │ └── test.js ├── intersectionPointOfTwoLists │ ├── prompt.md │ └── solution.js ├── linkedListLoop │ ├── prompt.md │ ├── solution.go │ └── solution.js ├── mergeKSortedLists │ ├── prompt.md │ └── solution.js ├── nthFromLastNode │ ├── prompt.md │ ├── solution.js │ └── test.js ├── removeDuplicatesFromList │ ├── prompt.md │ ├── solution.js │ └── test.js └── reverseSinglyLinkedList │ ├── prompt.md │ └── solution.js ├── Other ├── LRUCache │ ├── prompt.md │ └── solution.js ├── boggle │ ├── prompt.md │ └── solution.js ├── rootNumber │ ├── prompt.md │ └── solution.js └── wordDecryption │ ├── prompt.md │ └── solution.js ├── README.md ├── Recursion ├── numberOfPaths │ ├── prompt.md │ └── solution.js ├── permuteString │ ├── prompt.md │ ├── solution.js │ └── test.js └── sudokuSolver │ ├── prompt.md │ └── solution.js ├── SortingAndSearching ├── bubbleSort │ ├── prompt.md │ ├── solution.go │ └── solution.js ├── insertionSort │ ├── prompt.md │ ├── solution.go │ └── solution.js ├── kthLargestElementInArray │ ├── prompt.md │ └── solution.js ├── mergeIntervals │ ├── prompt.md │ ├── solution.js │ └── test.js ├── minimumWindowSubstring │ ├── prompt.md │ └── solution.js ├── pancakeSort │ ├── prompt.md │ └── solution.js └── quickSort │ ├── prompt.md │ ├── solution.js │ └── test.js ├── TreesAndGraphs ├── binarySearchTree │ ├── prompt.md │ ├── solution.go │ └── solution.js ├── cloneDirectedGraph │ ├── prompt.md │ └── solution.js ├── closestBinarySearchTreeValue │ ├── prompt.md │ └── solution.js ├── depthFirstSearch │ ├── prompt.md │ ├── solution.go │ └── solution.js ├── evaluateDivision │ ├── prompt.md │ └── solution.js ├── inorderBstSuccessor │ ├── prompt.md │ └── solution.js ├── longestUnivaluePath │ ├── prompt.md │ └── solution.js ├── numberOfPossibleBinaryTreeTopologies │ ├── prompt.md │ ├── solution.js │ └── test.js ├── riverSizes │ ├── prompt.md │ ├── solution.js │ └── test.js └── validateBst │ ├── prompt.md │ └── solution.js ├── _Template ├── prompt.md ├── solution.js └── test.js └── package.json /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "standard", 3 | "env": { 4 | "jest": true 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | TODO 4 | -------------------------------------------------------------------------------- /ArraysAndStrings/arrayQuadrupletSum/prompt.md: -------------------------------------------------------------------------------- 1 | # Array Quadruplet 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given an unsorted array of integers `arr` and a number `s`, write a function `findArrayQuadruplet` that finds four numbers (quadruplet) in `arr` that sum up to `s`. Your function should return an array of these numbers in an ascending order. If such a quadruplet doesn’t exist, return an empty array. 6 | 7 | Note that there may be more than one quadruplet in `arr` whose sum is `s`. You’re asked to return the first one you encounter (considering the results are sorted). 8 | 9 | Explain and code the most efficient solution possible, and analyze its time and space complexities. 10 | 11 | ## Example: 12 | 13 | ``` 14 | input: arr = [2, 7, 4, 0, 9, 5, 1, 3], s = 20 15 | 16 | output: [0, 4, 7, 9] # The ordered quadruplet of (7, 4, 0, 9) 17 | # whose sum is 20. Notice that there 18 | # are two other quadruplets whose sum is 20: 19 | # (7, 9, 1, 3) and (2, 4, 9, 5), but again you’re 20 | # asked to return the just one quadruplet (in an 21 | # ascending order) 22 | ``` 23 | -------------------------------------------------------------------------------- /ArraysAndStrings/arrayQuadrupletSum/solution.js: -------------------------------------------------------------------------------- 1 | function findArrayQuadruplet (arr, s) { 2 | arr.sort((a, b) => a > b) 3 | for (let first = 0; first < arr.length - 3; first++) { 4 | for (let second = first + 1; second < arr.length - 2; second++) { 5 | let third = second + 1 6 | let fourth = arr.length - 1 7 | while (third < fourth) { 8 | let sum = arr[first] + arr[second] + arr[third] + arr[fourth] 9 | if (sum === s) { 10 | return [arr[first], arr[second], arr[third], arr[fourth]] 11 | } else if (sum < s) { 12 | third++ 13 | } else { 14 | fourth-- 15 | } 16 | } 17 | } 18 | } 19 | return [] 20 | } 21 | 22 | module.exports = { findArrayQuadruplet } 23 | -------------------------------------------------------------------------------- /ArraysAndStrings/arrayQuadrupletSum/test.js: -------------------------------------------------------------------------------- 1 | const { findArrayQuadruplet } = require('./solution') 2 | 3 | test('[1, 2, 3, 4], 10', () => { 4 | expect(findArrayQuadruplet([1, 2, 3, 4], 10)).toEqual([1, 2, 3, 4]) 5 | }) 6 | test('[2, 7, 4, 0, 9, 5, 1, 3], 20', () => { 7 | expect(findArrayQuadruplet([2, 7, 4, 0, 9, 5, 1, 3], 20)).toEqual([ 8 | 0, 9 | 4, 10 | 7, 11 | 9 12 | ]) 13 | }) 14 | -------------------------------------------------------------------------------- /ArraysAndStrings/binarySearch/prompt.md: -------------------------------------------------------------------------------- 1 | # Binary Search 2 | 3 | ## [Solution (JS)](./solution.js) / [Solution (Go)](./solution.go) 4 | 5 | Given a sorted array of integers, write a function to search for a given element x in that array using the Binary Search method. If found, return the index of the element, otherwise return -1. 6 | 7 | ``` 8 | Sample input: [1,2,5,9,13,18,26,45], 18 9 | Sample output: 5 10 | ``` 11 | -------------------------------------------------------------------------------- /ArraysAndStrings/binarySearch/solution.go: -------------------------------------------------------------------------------- 1 | package program 2 | 3 | func BinarySearch(array []int, target int) int { 4 | min, mid, max := 0, 1, len(array)-1 5 | for min <= max { 6 | mid = (max + min) / 2 7 | if array[mid] == target { 8 | return mid 9 | } else if array[mid] > target { 10 | max = mid - 1 11 | } else { 12 | min = mid + 1 13 | } 14 | } 15 | return -1 16 | } 17 | -------------------------------------------------------------------------------- /ArraysAndStrings/binarySearch/solution.js: -------------------------------------------------------------------------------- 1 | function binarySearch (array, target) { 2 | let mid 3 | let min = 0 4 | let max = array.length - 1 5 | 6 | while (min <= max) { 7 | mid = Math.floor((min + max) / 2) 8 | if (array[mid] === target) { 9 | return mid 10 | } else if (array[mid] < target) { 11 | min = mid + 1 12 | } else { 13 | max = mid - 1 14 | } 15 | } 16 | 17 | return -1 18 | } 19 | 20 | module.exports = { binarySearch } 21 | -------------------------------------------------------------------------------- /ArraysAndStrings/binarySearch/test.js: -------------------------------------------------------------------------------- 1 | const { binarySearch } = require('./solution') 2 | 3 | test('[1, 2, 3, 4], 3', () => { 4 | expect(binarySearch([1, 2, 3, 4], 3)).toBe(2) 5 | }) 6 | test('[1, 10, 50, 999, 10002], 1', () => { 7 | expect(binarySearch([1, 10, 50, 999, 10002], 1)).toBe(0) 8 | }) 9 | test('[1], 1', () => { 10 | expect(binarySearch([1], 1)).toBe(0) 11 | }) 12 | test('[12, 15, 92, 100, 5689230389], 98374', () => { 13 | expect(binarySearch([12, 15, 92, 100, 5689230389], 98374)).toBe(-1) 14 | }) 15 | test('[], 9', () => { 16 | expect(binarySearch([], 9)).toBe(-1) 17 | }) 18 | -------------------------------------------------------------------------------- /ArraysAndStrings/budgetCuts/prompt.md: -------------------------------------------------------------------------------- 1 | # Award Budget Cuts 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | The awards committee of your alma mater (i.e. your college/university) asked for your assistance with a budget allocation problem they’re facing. Originally, the committee planned to give `N` research grants this year. However, due to spending cutbacks, the budget was reduced to `newBudget` dollars and now they need to reallocate the grants. The committee made a decision that they’d like to impact as few grant recipients as possible by applying a maximum `cap` on all grants. Every grant initially planned to be higher than `cap` will now be exactly `cap` dollars. Grants less or equal to `cap`, obviously, won’t be impacted. 6 | 7 | Given an array grantsArray of the original grants and the reduced budget `newBudget`, write a function `findGrantsCap` that finds in the most efficient manner a `cap` such that the least number of recipients is impacted and that the new budget constraint is met (i.e. sum of the `N` reallocated grants equals to `newBudget`). 8 | 9 | Analyze the time and space complexities of your solution. 10 | 11 | Example: 12 | 13 | ``` 14 | input: grantsArray = [2, 100, 50, 120, 1000], newBudget = 190 15 | 16 | output: 47 # and given this cap the new grants array would be 17 | # [2, 47, 47, 47, 47]. Notice that the sum of the 18 | # new grants is indeed 190 19 | ``` 20 | -------------------------------------------------------------------------------- /ArraysAndStrings/budgetCuts/solution.js: -------------------------------------------------------------------------------- 1 | // time: O(n-ish) space: O(n) 2 | function findGrantsCap (grantsArray, newBudget) { 3 | // evenly distribute budget to start 4 | let cap = newBudget / grantsArray.length 5 | 6 | // if we settle into the same cap we have reached a local minimum 7 | let newCap 8 | while (cap !== newCap) { 9 | cap = newCap || cap 10 | 11 | // find grants that are under current cap 12 | let underBudgetGrants = grantsArray.filter(el => el < cap) 13 | 14 | // find surplus at given cap 15 | let surplus = newBudget - underBudgetGrants.reduce((a, b) => a + b, 0) 16 | 17 | // set new cap to redistribute surplus among grants over the cap 18 | newCap = surplus / (grantsArray.length - underBudgetGrants.length) 19 | } 20 | 21 | return newCap 22 | } 23 | 24 | module.exports = { findGrantsCap } 25 | -------------------------------------------------------------------------------- /ArraysAndStrings/budgetCuts/test.js: -------------------------------------------------------------------------------- 1 | const { findGrantsCap } = require('./solution') 2 | 3 | test('[2, 100, 50, 120, 1000], 190', () => { 4 | expect(findGrantsCap([2, 100, 50, 120, 1000], 190)).toEqual(47) 5 | }) 6 | 7 | test('[8, 30, 35, 42, 50], 120', () => { 8 | expect(findGrantsCap([8, 30, 35, 42, 50], 120)).toEqual(28) 9 | }) 10 | -------------------------------------------------------------------------------- /ArraysAndStrings/findAllPalindromeSubstrings/prompt.md: -------------------------------------------------------------------------------- 1 | # Find All Palindrome Substrings 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given a string find all substrings that are palindromes. 6 | -------------------------------------------------------------------------------- /ArraysAndStrings/findAllPalindromeSubstrings/solution.js: -------------------------------------------------------------------------------- 1 | const findAllPalindromeSubstrings = str => { 2 | let palindromes = [] 3 | for (let i = 0; i < str.length; i++) { 4 | findOddPalindromes(str, i, palindromes) 5 | findEvenPalindromes(str, i, palindromes) 6 | } 7 | return palindromes 8 | } 9 | 10 | const findOddPalindromes = (str, i, palindromes) => { 11 | let palindrome = str[i] 12 | let left = i - 1 13 | let right = i + 1 14 | while (str[left] === str[right] && left > -1 && right < str.length) { 15 | palindrome = str[left] + palindrome + str[right] 16 | palindromes.push(palindrome) 17 | left-- 18 | right++ 19 | } 20 | } 21 | 22 | const findEvenPalindromes = (str, i, palindromes) => { 23 | let palindrome = '' 24 | let left = i 25 | let right = i + 1 26 | while (str[left] === str[right] && left > -1 && right < str.length) { 27 | palindrome = str[left] + palindrome + str[right] 28 | palindromes.push(palindrome) 29 | left-- 30 | right++ 31 | } 32 | } 33 | 34 | module.exports = { findAllPalindromeSubstrings } 35 | -------------------------------------------------------------------------------- /ArraysAndStrings/findAllPalindromeSubstrings/test.js: -------------------------------------------------------------------------------- 1 | const { findAllPalindromeSubstrings } = require('./solution') 2 | 3 | test('findAllPalindromeSubstrings(aabbbaa)', () => { 4 | expect(findAllPalindromeSubstrings('aabbbaa')).toEqual([ 5 | 'aa', 6 | 'bb', 7 | 'bbb', 8 | 'abbba', 9 | 'aabbbaa', 10 | 'bb', 11 | 'aa' 12 | ]) 13 | }) 14 | -------------------------------------------------------------------------------- /ArraysAndStrings/flattenDictionary/prompt.md: -------------------------------------------------------------------------------- 1 | # Flatten a Dictionary 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | A dictionary is a type of data structure that is supported natively in all major interpreted languages such as JavaScript, Python, Ruby and PHP, where it’s known as an Object, Dictionary, Hash and Array, respectively. In simple terms, a dictionary is a collection of unique keys and their values. The values can typically be of any primitive type (i.e an integer, boolean, double, string etc) or other dictionaries (dictionaries can be nested). However, for this exercise assume that values are either an integer, a string or another dictionary. 6 | 7 | Given a dictionary `dict`, write a function `flattenDictionary` that returns a flattened version of it. 8 | 9 | If you’re using a compiled language such Java, C++, C#, Swift and Go, you may want to use a Map/Dictionary/Hash Table that maps strings (keys) to a generic type (e.g. Object in Java, AnyObject in Swift etc.) to allow nested dictionaries. 10 | 11 | If a certain key is empty, it should be excluded from the output (see `e` in the example below). 12 | 13 | Example: 14 | 15 | ``` 16 | input: dict = { 17 | "Key1" : "1", 18 | "Key2" : { 19 | "a" : "2", 20 | "b" : "3", 21 | "c" : { 22 | "d" : "3", 23 | "e" : { 24 | "" : "1" 25 | } 26 | } 27 | } 28 | } 29 | 30 | output: { 31 | "Key1" : "1", 32 | "Key2.a" : "2", 33 | "Key2.b" : "3", 34 | "Key2.c.d" : "3", 35 | "Key2.c.e" : "1" 36 | } 37 | ``` 38 | 39 | Important: when you concatenate keys, make sure to add the dot character between them. For instance concatenating `Key2`, `c` and `d` the result key would be `Key2.c.d`. 40 | -------------------------------------------------------------------------------- /ArraysAndStrings/flattenDictionary/solution.js: -------------------------------------------------------------------------------- 1 | function flattenDictionary(dict) { 2 | const flatDictionary = {} 3 | buildFlattenedDictionary(dict, '', flatDictionary) 4 | return flatDictionary 5 | } 6 | 7 | function buildFlattenedDictionary(dict, prefix, flatDictionary) { 8 | for (let key in dict) { 9 | // get correct prefix 10 | let prefixedKey 11 | if (prefix === '') { 12 | prefixedKey = key 13 | } else if (key === '') { 14 | prefixedKey = prefix 15 | } else { 16 | prefixedKey = `${prefix}.${key}` 17 | } 18 | // flatten 19 | if (typeof dict[key] !== 'object') { 20 | flatDictionary[prefixedKey] = dict[key] 21 | } else { 22 | buildFlattenedDictionary(dict[key], prefixedKey, flatDictionary) 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ArraysAndStrings/kEmptySlots/prompt.md: -------------------------------------------------------------------------------- 1 | # K Empty Slots 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | There is a garden with N slots. In each slot, there is a flower. The N flowers will bloom one by one in N days. In each day, there will be exactly one flower blooming and it will be in the status of blooming since then. 6 | 7 | Given an array flowers consists of number from 1 to N. Each number in the array represents the place where the flower will open in that day. 8 | 9 | For example, flowers[i] = x means that the unique flower that blooms at day i will be at position x, where i and x will be in the range from 1 to N. 10 | 11 | Also given an integer k, you need to output in which day there exists two flowers in the status of blooming, and also the number of flowers between them is k and these flowers are not blooming. 12 | 13 | If there isn't such day, output -1. 14 | -------------------------------------------------------------------------------- /ArraysAndStrings/longestIncreasingSubsequence/prompt.md: -------------------------------------------------------------------------------- 1 | # Longest Increasing Subsequence 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given an array of integers, write a function that returns the longest strictly-increasing subsequence in that array. A subsequence is defined as a set of numbers that aren't necessarily adjacent but are in the same order they appear in the array. Assume there will only be one longest increasing subsequence. 6 | 7 | ``` 8 | Sample Input: [6, 7, -24, 12, 15, -12, 12, 5, 4, 35, 9] 9 | Sample Output: [ 6, 7, 12, 15, 35 ] 10 | ``` 11 | -------------------------------------------------------------------------------- /ArraysAndStrings/longestIncreasingSubsequence/solution.js: -------------------------------------------------------------------------------- 1 | function longestIncreasingSubsequence (array) { 2 | console.log('input', array) 3 | const subsequences = new Array(array.length) 4 | const indices = new Array(array.length + 1) 5 | let length = 0 6 | for (let i = 0; i < array.length; i++) { 7 | const currNum = array[i] 8 | console.log('---------currnum', currNum) 9 | const newLength = binarySearch(1, length, indices, array, currNum) 10 | console.log('newlength', newLength) 11 | subsequences[i] = indices[newLength - 1] 12 | indices[newLength] = i 13 | length = Math.max(length, newLength) 14 | 15 | console.log('array', array) 16 | console.log('subsequences', subsequences) 17 | console.log('indices', indices) 18 | console.log('length', length) 19 | } 20 | console.log('---------Final') 21 | console.log('array', array) 22 | console.log('subsequences', subsequences) 23 | console.log('indices', indices) 24 | console.log('length', length) 25 | return buildSequence(array, subsequences, indices[length]) 26 | } 27 | 28 | function binarySearch (startIdx, endIdx, indices, array, currNum) { 29 | if (startIdx > endIdx) return startIdx 30 | const middle = Math.floor((startIdx + endIdx) / 2) 31 | console.log('--Middle:', middle) 32 | if (array[indices[middle]] < currNum) { 33 | startIdx = middle + 1 34 | } else { 35 | endIdx = middle - 1 36 | } 37 | return binarySearch(startIdx, endIdx, indices, array, currNum) 38 | } 39 | 40 | function buildSequence (array, subsequences, currIdx) { 41 | const longestIncSubsequence = [] 42 | while (currIdx !== undefined) { 43 | longestIncSubsequence.unshift(array[currIdx]) 44 | currIdx = subsequences[currIdx] 45 | } 46 | return longestIncSubsequence 47 | } 48 | 49 | console.log(longestIncreasingSubsequence([1, 2, 3, 4, 5])) 50 | // console.log(longestIncreasingSubsequence([6, 7, -24, 12, 15, -12, 12, 5, 4, 35, 9])) 51 | -------------------------------------------------------------------------------- /ArraysAndStrings/longestSubstringWithAtMostKDistinctCharacters/prompt.md: -------------------------------------------------------------------------------- 1 | # Longest Substring with At Most K Distinct Characters 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given a string, find the length of the longest substring `T` that contains at most `k` distinct characters. 6 | 7 | For example, Given `s = “eceba”` and `k = 2`, 8 | 9 | `T` is `"ece"` with length `3`. 10 | -------------------------------------------------------------------------------- /ArraysAndStrings/longestSubstringWithAtMostKDistinctCharacters/solution.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @param {string} string 3 | * @param {number} k 4 | * @return {number} 5 | */ 6 | const lengthOfLongestSubstringKDistinct = function(string, k) { 7 | if (string === null || string.length === 0 || k === 0) return 0 8 | 9 | let characters = {} 10 | let start = 0 11 | let maxLength = 0 12 | let distinctCharacters = 0 13 | 14 | for (let end = 0; end < string.length; end++) { 15 | let currentCharacter = string[end] 16 | if (!characters[currentCharacter]) { 17 | distinctCharacters++ 18 | characters[currentCharacter] = 0 19 | } 20 | characters[currentCharacter] += 1 21 | if (distinctCharacters <= k) { 22 | maxLength = Math.max(end - start + 1, maxLength) 23 | } else { 24 | while (distinctCharacters > k) { 25 | currentCharacter = string[start] 26 | characters[currentCharacter] -= 1 27 | if (characters[currentCharacter] === 0) { 28 | distinctCharacters-- 29 | } 30 | start += 1 31 | } 32 | } 33 | } 34 | return maxLength 35 | } 36 | 37 | console.log(lengthOfLongestSubstringKDistinct('eceba', 2)) 38 | -------------------------------------------------------------------------------- /ArraysAndStrings/matchingBrackets/prompt.md: -------------------------------------------------------------------------------- 1 | # Matching Brackets 2 | 3 | ## [Solution (JS)](./solution.js) / [Solution (Go)](./solution.go) 4 | 5 | Write a function that takes in a string of brackets and other characters, the function should return a boolean representing whether or not the string has matching brackets throughout. 6 | 7 | ``` 8 | Sample Input: "([])(){}((()))()()" 9 | Sample Output: true 10 | ``` 11 | -------------------------------------------------------------------------------- /ArraysAndStrings/matchingBrackets/solution.go: -------------------------------------------------------------------------------- 1 | package program 2 | 3 | func matchingBrackets(s string) bool { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /ArraysAndStrings/matchingBrackets/solution.js: -------------------------------------------------------------------------------- 1 | function matchingBrackets(string) { 2 | let matchingSet = { 3 | "}": "{", 4 | ")": "(", 5 | "]": "[" 6 | } 7 | let openingBrackets = "({[" 8 | let closingBrackets = "]})" 9 | let openStack = [] 10 | for (let char of string){ 11 | if (openingBrackets.includes(char)) { 12 | openStack.push(char) 13 | } else if (closingBrackets.includes(char)) { 14 | if (openStack.length === 0) { 15 | return false 16 | } else if (matchingSet[char] !== openStack.pop()){ 17 | return false 18 | } 19 | } 20 | } 21 | return openStack.length === 0 22 | } 23 | 24 | console.log(matchingBrackets("([])(){}((()))()()")) 25 | -------------------------------------------------------------------------------- /ArraysAndStrings/maxSlidingWindow/prompt.md: -------------------------------------------------------------------------------- 1 | # Find Maximum in Sliding Window 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given a large array of integers and a window of size 'w', find the current maximum in the window as the window slides through the entire array. 6 | -------------------------------------------------------------------------------- /ArraysAndStrings/maxSlidingWindow/solution.js: -------------------------------------------------------------------------------- 1 | const maxInSlidingWindow = (arr, windowSize) => { 2 | const window = [] 3 | const result = [] 4 | if (windowSize > arr.length) return 5 | 6 | // initialize window 7 | for (let i = 0; i < windowSize; i++) { 8 | while (window.length > 0 && arr[i] >= arr[window[window.length - 1]]) { 9 | window.pop() 10 | } 11 | window.push(i) 12 | } 13 | result.push(arr[window[0]]) 14 | 15 | // begin sliding 16 | for (let i = windowSize; i < arr.length; i++) { 17 | while (window.length > 0 && arr[i] >= arr[window[window.length - 1]]) { 18 | window.pop() 19 | } 20 | if (window.length > 0 && window[0] <= i - windowSize) { 21 | window.shift() 22 | } 23 | window.push(i) 24 | result.push(arr[window[0]]) 25 | } 26 | return result 27 | } 28 | 29 | module.exports = { maxInSlidingWindow } 30 | -------------------------------------------------------------------------------- /ArraysAndStrings/maxSlidingWindow/test.js: -------------------------------------------------------------------------------- 1 | const { maxInSlidingWindow } = require('./solution') 2 | 3 | test('maxInSlidingWindow([-4, 2, -5, 1, -1, 6], 3)', () => { 4 | expect(maxInSlidingWindow([-4, 2, -5, 1, -1, 6], 3)).toEqual([2, 2, 1, 6]) 5 | }) 6 | -------------------------------------------------------------------------------- /ArraysAndStrings/minNumberOfJumps/prompt.md: -------------------------------------------------------------------------------- 1 | # Minimum Number of Jumps 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | You are given a non-empty array of integers. Each element represents the maximum number of steps you can take forward. For example, if the element at index 1 is 3, you can go from index 1 to index 2, 3, or 4. Write a function that returns the minimum number of jumps needed to reach the final index. Note that jumping from index i to index i + x always constitutes 1 jump, no matter how large x is. 6 | -------------------------------------------------------------------------------- /ArraysAndStrings/minNumberOfJumps/solution.js: -------------------------------------------------------------------------------- 1 | function minNumberOfJumps(array) { 2 | // Initialize all indexes as 'unreachable' with inifinite number of jumps needed to get there 3 | let jumps = Array(array.length).fill(Infinity) 4 | // Getting to the first index takes 0 jumps 5 | jumps[0] = 0 6 | for (let i = 1; i < array.length; i++) { 7 | for (let j = 0; j < i; j++) { 8 | // Find smallest number of jumps to get to index i 9 | if (array[j] >= i - j) { 10 | jumps[i] = Math.min(jumps[i], jumps[j] + 1) 11 | } 12 | } 13 | } 14 | return jumps[jumps.length - 1] 15 | } 16 | -------------------------------------------------------------------------------- /ArraysAndStrings/moveZerosToLeft/prompt.md: -------------------------------------------------------------------------------- 1 | # Move Zeros to Left 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given an integer array, move all elements containing '0' to the left while maintaining the order of other elements in the array. 6 | 7 | ### Example 8 | 9 | ``` 10 | Input: [1, 10, 20, 0, 59, 63, 0, 88, 0] 11 | Output: [0, 0, 0, 1, 10, 20, 59, 63, 88] 12 | ``` 13 | -------------------------------------------------------------------------------- /ArraysAndStrings/moveZerosToLeft/solution.js: -------------------------------------------------------------------------------- 1 | const moveZerosToLeft = arr => { 2 | let read = arr.length - 1 3 | let write = arr.length - 1 4 | 5 | // shift all non zeros to right end of array 6 | while (read >= 0) { 7 | if (arr[read] !== 0) { 8 | arr[write] = arr[read] 9 | write -= 1 10 | } 11 | read -= 1 12 | } 13 | 14 | // fill rest of array with 0s 15 | while (write >= 0) { 16 | arr[write] = 0 17 | write -= 1 18 | } 19 | } 20 | 21 | module.exports = { moveZerosToLeft } 22 | -------------------------------------------------------------------------------- /ArraysAndStrings/moveZerosToLeft/test.js: -------------------------------------------------------------------------------- 1 | const { moveZerosToLeft } = require('./solution') 2 | 3 | test('moveZerosToLeft([1, 10, 20, 0, 59, 63, 0, 88, 0])', () => { 4 | let array = [1, 10, 20, 0, 59, 63, 0, 88, 0] 5 | moveZerosToLeft(array) 6 | expect(array).toEqual([0, 0, 0, 1, 10, 20, 59, 63, 88]) 7 | }) 8 | -------------------------------------------------------------------------------- /ArraysAndStrings/pairSum/prompt.md: -------------------------------------------------------------------------------- 1 | # Two Number Sum 2 | 3 | ## [Solution (JS)](./solution.js) / [Solution (Go)](./solution.go) 4 | 5 | Write a function that takes in a non-empty array of distinct integers and an integer representing a target sum. If any two numbers in the input array sum up to the target sum, the function should return them in an array, in sorted order. If no two numbers sum up to the target sum, the function should return an empty array. 6 | 7 | ``` 8 | Sample input: [3, 5, -4, 8, 11, 1, -1, 6], 10 9 | Sample output: [-1, 11] 10 | ``` 11 | -------------------------------------------------------------------------------- /ArraysAndStrings/pairSum/solution.go: -------------------------------------------------------------------------------- 1 | package program 2 | 3 | import "sort" 4 | 5 | func TwoNumberSum(array []int, target int) []int { 6 | sort.Ints(array) 7 | left := 0 8 | right := len(array) - 1 9 | for left < right { 10 | sum := array[left] + array[right] 11 | if sum == target { 12 | return []int{array[left], array[right]} 13 | } else if sum < target { 14 | left++ 15 | } else { 16 | right-- 17 | } 18 | } 19 | return []int{} 20 | } 21 | 22 | func NaiveTwoNumberSum(array []int, target int) []int { 23 | for i := 0; i < len(array); i++ { 24 | for j := i + 1; j < len(array); j++ { 25 | sum := array[i] + array[j] 26 | if sum == target { 27 | result := []int{array[i], array[j]} 28 | sort.Ints(result) 29 | return result 30 | } 31 | } 32 | } 33 | return []int{} 34 | } 35 | -------------------------------------------------------------------------------- /ArraysAndStrings/pairSum/solution.js: -------------------------------------------------------------------------------- 1 | function pairSum (array, targetSum) { 2 | array.sort((a, b) => a > b) 3 | let left = 0 4 | let right = array.length - 1 5 | while (left < right) { 6 | let sum = array[left] + array[right] 7 | if (sum === targetSum) { 8 | return [array[left], array[right]] 9 | } else if (sum < targetSum) { 10 | left++ 11 | } else if (sum > targetSum) { 12 | right-- 13 | } 14 | } 15 | return [] 16 | } 17 | 18 | module.exports = { pairSum } 19 | -------------------------------------------------------------------------------- /ArraysAndStrings/pairSum/test.js: -------------------------------------------------------------------------------- 1 | const { pairSum } = require('./solution') 2 | 3 | test('[1, 2], 3', () => { 4 | expect(pairSum([1, 2], 3)).toEqual([1, 2]) 5 | }) 6 | test('[1, 2, 3, 4, 5, 6, 7, 8, 9, 15], 18', () => { 7 | expect(pairSum([1, 2, 3, 4, 5, 6, 7, 8, 9, 15], 18)).toEqual([3, 15]) 8 | }) 9 | test('[1, 2, 3, 4, 5, 6, 7, 8, 9, 15], 18', () => { 10 | expect(pairSum([1, 2, 3, 4, 5, 6, 7, 8, 9, 15], 18)).toEqual([3, 15]) 11 | }) 12 | test('[1, 2, 3, 4, 5, 6, 7, 8, 9, 15], 18', () => { 13 | expect(pairSum([1, 2, 3, 4, 5, 6, 7, 8, 9, 15], 18)).toEqual([3, 15]) 14 | }) 15 | test('[1, 2, 3, 4, 5, 6, 7, 8, 9, 15], 18', () => { 16 | expect(pairSum([1, 2, 3, 4, 5, 6, 7, 8, 9, 15], 18)).toEqual([3, 15]) 17 | }) 18 | -------------------------------------------------------------------------------- /ArraysAndStrings/palindrome/prompt.md: -------------------------------------------------------------------------------- 1 | # Palindrome 2 | 3 | ## [Solution (JS)](./solution.js) / [Solution (Go)](./solution.go) 4 | 5 | Write a function that takes in a non empty string and returns a boolean representing whether or not the string is a palindrome. 6 | 7 | ``` 8 | Sample input: "racecar" 9 | Sample output: true 10 | ``` 11 | -------------------------------------------------------------------------------- /ArraysAndStrings/palindrome/solution.go: -------------------------------------------------------------------------------- 1 | package program 2 | 3 | func isPalindrome(str string) bool { 4 | left := 0 5 | right := len(str) - 1 6 | for left < right { 7 | if str[left] != str[right] { 8 | return false 9 | } 10 | left++ 11 | right-- 12 | } 13 | return true 14 | } 15 | -------------------------------------------------------------------------------- /ArraysAndStrings/palindrome/solution.js: -------------------------------------------------------------------------------- 1 | function isPalindrome (string) { 2 | let left = 0 3 | let right = string.length - 1 4 | while (left < right) { 5 | if (string[left] !== string[right]) return false 6 | left++ 7 | right-- 8 | } 9 | return true 10 | } 11 | 12 | module.exports = { isPalindrome } 13 | -------------------------------------------------------------------------------- /ArraysAndStrings/palindrome/test.js: -------------------------------------------------------------------------------- 1 | const { isPalindrome } = require('./solution') 2 | 3 | test('racecar', () => { 4 | expect(isPalindrome('racecar')).toBe(true) 5 | }) 6 | test('notracecar', () => { 7 | expect(isPalindrome('notracecar')).toBe(false) 8 | }) 9 | test('a', () => { 10 | expect(isPalindrome('a')).toBe(true) 11 | }) 12 | test('bbb', () => { 13 | expect(isPalindrome('bbb')).toBe(true) 14 | }) 15 | test('', () => { 16 | expect(isPalindrome('')).toBe(true) 17 | }) 18 | test('asdfghjklkjhgfdsa', () => { 19 | expect(isPalindrome('asdfghjklkjhgfdsa')).toBe(true) 20 | }) 21 | -------------------------------------------------------------------------------- /ArraysAndStrings/plusOne/prompt.md: -------------------------------------------------------------------------------- 1 | # Plus One 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given a non-negative integer represented as a non-empty array of digits, add one to the integer. 6 | 7 | You may assume the integer does not contain any leading zeros, except the number 0 itself. 8 | 9 | The digits are stored such that the most significant digit is at the head of the list. 10 | -------------------------------------------------------------------------------- /ArraysAndStrings/plusOne/solution.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} digits 3 | * @return {number[]} 4 | */ 5 | const plusOne = function (digits) { 6 | let carry = 0 7 | let length = digits.length 8 | 9 | // add one 10 | digits[length - 1] += 1 11 | 12 | for (let i = length - 1; i >= 0; i--) { 13 | if (carry === 1) { 14 | digits[i] += 1 15 | } 16 | if (digits[i] > 9) { 17 | carry = 1 18 | digits[i] = 0 19 | } else { 20 | carry = 0 21 | } 22 | } 23 | 24 | if (carry === 1) { 25 | digits[0] = 0 26 | digits.unshift(1) 27 | } 28 | 29 | return digits 30 | } 31 | 32 | module.exports = { plusOne } 33 | -------------------------------------------------------------------------------- /ArraysAndStrings/plusOne/test.js: -------------------------------------------------------------------------------- 1 | const { plusOne } = require('./solution') 2 | 3 | test('Adds one to [1, 9]', () => { 4 | expect(plusOne([1, 9])).toEqual([2, 0]) 5 | }) 6 | 7 | test('Adds one to [1, 2, 8, 9]', () => { 8 | expect(plusOne([1, 2, 8, 9])).toEqual([1, 2, 9, 0]) 9 | }) 10 | 11 | test('Adds one to [1, 2, 3, 4, 5, 6, 7, 8]', () => { 12 | expect(plusOne([1, 2, 3, 4, 5, 6, 7, 8])).toEqual([1, 2, 3, 4, 5, 6, 7, 9]) 13 | }) 14 | 15 | test('Adds one to [9,9,9,9,9,9,9,9]', () => { 16 | expect(plusOne([9, 9, 9, 9, 9, 9, 9, 9])).toEqual([1, 0, 0, 0, 0, 0, 0, 0, 0]) 17 | }) 18 | -------------------------------------------------------------------------------- /ArraysAndStrings/powerSet/prompt.md: -------------------------------------------------------------------------------- 1 | # Power Set 2 | 3 | ## [Solution (JS)](./solution.js) / [Solution (Go)](./solution.go) 4 | 5 | Write a function that takes in an array of unique integers and returns its Power Set. A Power Set is a set of all the subsets of a set. 6 | 7 | ``` 8 | Sample input: [1, 3, 5] 9 | Sample output: [[], [1], [3], [5], [1, 3], [1, 5], [3, 5], [1, 3, 5]] 10 | ``` 11 | -------------------------------------------------------------------------------- /ArraysAndStrings/powerSet/solution.go: -------------------------------------------------------------------------------- 1 | package program 2 | 3 | func Powerset(array []int) [][]int { 4 | superSet := [][]int{[]int{}} 5 | for _, el := range array { 6 | superSetLength := len(superSet) 7 | for i := 0; i < superSetLength; i++ { 8 | currSubset := superSet[i] 9 | newSubset := append(currSubset, el) 10 | superSet = append(superSet, newSubset) 11 | } 12 | } 13 | return superSet 14 | } 15 | -------------------------------------------------------------------------------- /ArraysAndStrings/powerSet/solution.js: -------------------------------------------------------------------------------- 1 | function powerset(array) { 2 | let superSet = [[]] 3 | array.forEach(el => { 4 | let superSetLength = superSet.length 5 | for (let i = 0; i < superSetLength; i++) { 6 | superSet.push(superSet[i].concat(el)) 7 | } 8 | }) 9 | return superSet 10 | } 11 | 12 | console.log(powerset([1, 2, 3])) 13 | -------------------------------------------------------------------------------- /ArraysAndStrings/rainWater/prompt.md: -------------------------------------------------------------------------------- 1 | # Trapping Rain Water 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining. 6 | 7 | For example, 8 | Given `[0,1,0,2,1,0,1,3,2,1,2,1]`, return `6`. 9 | -------------------------------------------------------------------------------- /ArraysAndStrings/rainWater/solution.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @param {number[]} height 3 | * @return {number} 4 | */ 5 | var trap = function(height) { 6 | // find heighest wall to right 7 | let rightMax = 0 8 | let rightWalls = [] 9 | for (let i = height.length - 1; i >= 0; i--) { 10 | rightMax = Math.max(rightMax, height[i]) 11 | rightWalls[i] = rightMax 12 | } 13 | 14 | // find heighest wall to left 15 | let leftMax = 0 16 | let leftWalls = [] 17 | for (let i = 0; i < height.length; i++) { 18 | leftMax = Math.max(leftMax, height[i]) 19 | leftWalls[i] = leftMax 20 | } 21 | 22 | // find volume over each block for sum 23 | let sum = 0 24 | for (let i = 1; i < height.length; i++) { 25 | sum += Math.min(leftWalls[i], rightWalls[i]) - height[i] 26 | } 27 | 28 | return sum 29 | } 30 | 31 | // let heights = [0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1] 32 | // console.log(trap(heights)) //6 33 | -------------------------------------------------------------------------------- /ArraysAndStrings/repeatedStringMatch/prompt.md: -------------------------------------------------------------------------------- 1 | # Repeated String Match 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given two strings A and B, find the minimum number of times A has to be repeated such that B is a substring of it. If no such solution, return -1. 6 | 7 | For example, with A = "abcd" and B = "cdabcdab". 8 | 9 | Return 3, because by repeating A three times (“abcdabcdabcd”), B is a substring of it; and B is not a substring of A repeated two times ("abcdabcd"). 10 | 11 | Note: 12 | The length of A and B will be between 1 and 10000. 13 | -------------------------------------------------------------------------------- /ArraysAndStrings/repeatedStringMatch/solution.js: -------------------------------------------------------------------------------- 1 | var repeatedStringMatch = function(A, B) { 2 | let count = 1 3 | let maxLength = Math.max(A.length, B.length) 4 | while (A.length < maxLength) { 5 | count++ 6 | A = A + A 7 | } 8 | if (A.includes(B)) return count 9 | if ((A + A).includes(B)) return count + 1 10 | return -1 11 | } 12 | 13 | console.log('A') 14 | console.log('results', repeatedStringMatch('abcd', 'cdabcdab')) 15 | console.log('B') 16 | console.log('results', repeatedStringMatch('bb', 'bbbbbbb')) 17 | -------------------------------------------------------------------------------- /ArraysAndStrings/rotateArray/prompt.md: -------------------------------------------------------------------------------- 1 | # Rotate Array 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given an array of integers, rotate the array by 'N' elements. 6 | 7 | ### Example 8 | 9 | ``` 10 | Input: [1, 10, 20, 0, 59, 86, 32, 11, 9, 40], -1 11 | Output: [10, 20, 0, 59, 86, 32, 11, 9, 40, 1] 12 | 13 | Input: [1, 10, 20, 0, 59, 86, 32, 11, 9, 40], 2 14 | Output: [9, 40, 1, 10, 20, 0, 59, 86, 32, 11] 15 | ``` 16 | -------------------------------------------------------------------------------- /ArraysAndStrings/rotateArray/solution.js: -------------------------------------------------------------------------------- 1 | const rotateArray = (arr, k) => { 2 | // normalize k 3 | k = k % arr.length 4 | if (k < 0) { 5 | k = k + arr.length 6 | } 7 | 8 | reverseArray(arr, 0, arr.length - 1) 9 | reverseArray(arr, 0, k - 1) 10 | reverseArray(arr, k, arr.length - 1) 11 | } 12 | 13 | const reverseArray = (arr, start, end) => { 14 | while (start < end) { 15 | let temp = arr[start] 16 | arr[start] = arr[end] 17 | arr[end] = temp 18 | start++ 19 | end-- 20 | } 21 | } 22 | 23 | module.exports = { rotateArray } 24 | -------------------------------------------------------------------------------- /ArraysAndStrings/rotateArray/test.js: -------------------------------------------------------------------------------- 1 | const { rotateArray } = require('./solution') 2 | 3 | test('rotateArray([1, 10, 20, 0, 59, 86, 32, 11, 9, 40], -1)', () => { 4 | let array = [1, 10, 20, 0, 59, 86, 32, 11, 9, 40] 5 | rotateArray(array, -1) 6 | expect(array).toEqual([10, 20, 0, 59, 86, 32, 11, 9, 40, 1]) 7 | }) 8 | 9 | test('rotateArray([1, 10, 20, 0, 59, 86, 32, 11, 9, 40], 2)', () => { 10 | let array = [1, 10, 20, 0, 59, 86, 32, 11, 9, 40] 11 | rotateArray(array, 2) 12 | expect(array).toEqual([9, 40, 1, 10, 20, 0, 59, 86, 32, 11]) 13 | }) 14 | -------------------------------------------------------------------------------- /ArraysAndStrings/searchRotatedArray/prompt.md: -------------------------------------------------------------------------------- 1 | # Search Rotated Array 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Search a given number in a sorted array that has been rotated by some arbitrary number. Return -1 if the number does not exist. 6 | 7 | ### Hints 8 | 9 | * Linear search is not an acceptable solution 10 | * Think modified binary search 11 | -------------------------------------------------------------------------------- /ArraysAndStrings/searchRotatedArray/solution.js: -------------------------------------------------------------------------------- 1 | const searchRotatedArray = (arr, key) => { 2 | let start = 0 3 | let end = arr.length - 1 4 | let mid = Math.floor((end + start) / 2) 5 | 6 | while (end >= start) { 7 | mid = Math.floor((end + start) / 2) 8 | if (arr[mid] === key) { 9 | return mid 10 | } else if (arr[start] < arr[mid] && key < arr[mid] && key >= arr[start]) { 11 | end = mid - 1 12 | } else if (arr[mid] < arr[end] && key > arr[mid] && key <= arr[end]) { 13 | start = mid + 1 14 | } else if (arr[start] > arr[mid]) { 15 | end = mid - 1 16 | } else if (arr[end] < arr[mid]) { 17 | start = mid + 1 18 | } 19 | } 20 | return -1 21 | } 22 | 23 | module.exports = { searchRotatedArray } 24 | -------------------------------------------------------------------------------- /ArraysAndStrings/searchRotatedArray/test.js: -------------------------------------------------------------------------------- 1 | const { searchRotatedArray } = require('./solution') 2 | 3 | test('searchRotatedArray([176, 188,199,200,210,222,1,10,20,47,59,63,75,88,99,107,120,133,155,162], 200)', () => { 4 | expect( 5 | searchRotatedArray( 6 | [ 7 | 176, 8 | 188, 9 | 199, 10 | 200, 11 | 210, 12 | 222, 13 | 1, 14 | 10, 15 | 20, 16 | 47, 17 | 59, 18 | 63, 19 | 75, 20 | 88, 21 | 99, 22 | 107, 23 | 120, 24 | 133, 25 | 155, 26 | 162 27 | ], 28 | 200 29 | ) 30 | ).toEqual(3) 31 | }) 32 | -------------------------------------------------------------------------------- /ArraysAndStrings/sentenceReverse/prompt.md: -------------------------------------------------------------------------------- 1 | # Sentence Reverse 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | You are given an array of characters arr that consists of sequences of characters separated by space characters. Each space-delimited sequence of characters defines a word. 6 | 7 | Implement a function reverseWords that reverses the order of the words in the array in the most efficient manner. 8 | 9 | Explain your solution and analyze its time and space complexities. 10 | 11 | Example: 12 | 13 | ``` 14 | input: arr = [ 'p', 'e', 'r', 'f', 'e', 'c', 't', ' ', 15 | 'm', 'a', 'k', 'e', 's', ' ', 16 | 'p', 'r', 'a', 'c', 't', 'i', 'c', 'e' ] 17 | 18 | output: [ 'p', 'r', 'a', 'c', 't', 'i', 'c', 'e', ' ', 19 | 'm', 'a', 'k', 'e', 's', ' ', 20 | 'p', 'e', 'r', 'f', 'e', 'c', 't' ] 21 | ``` 22 | -------------------------------------------------------------------------------- /ArraysAndStrings/sentenceReverse/solution.js: -------------------------------------------------------------------------------- 1 | // time: O(n) space: O(1) 2 | function reverseWords(arr) { 3 | // Reverse sentence 4 | reverser(arr, 0, arr.length - 1) 5 | // Reverse each word in place 6 | start = null 7 | for (let i = 0; i < arr.length; i++) { 8 | if (arr[i] === ' ') { 9 | if (start !== null) { 10 | reverser(arr, start, i - 1) 11 | start = null 12 | } 13 | } else if (i === arr.length - 1) { 14 | if (start !== null) { 15 | reverser(arr, start, i) 16 | } 17 | } else { 18 | if (start === null) { 19 | start = i 20 | } 21 | } 22 | } 23 | return arr 24 | } 25 | 26 | function reverser(arr, start, end) { 27 | while (start < end) { 28 | let temp = arr[start] 29 | arr[start] = arr[end] 30 | arr[end] = temp 31 | start++ 32 | end-- 33 | } 34 | } 35 | 36 | // time:O(n) space:O(n) 37 | function reverseWords(arr) { 38 | let outputSentence = [] 39 | let currentWord = [] 40 | for (let i = arr.length - 1; i >= 0; i--) { 41 | if (arr[i] === ' ') { 42 | outputSentence = outputSentence.concat(currentWord) 43 | outputSentence.push(arr[i]) 44 | currentWord = [] 45 | } else { 46 | currentWord.unshift(arr[i]) 47 | } 48 | } 49 | outputSentence = outputSentence.concat(currentWord) 50 | return outputSentence 51 | } 52 | -------------------------------------------------------------------------------- /ArraysAndStrings/smallestCommonNumber/prompt.md: -------------------------------------------------------------------------------- 1 | # Find Smallest Common Number 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given three integer arrays sorted in ascending order, find the smallest number that is common in all three arrays. 6 | 7 | ### Example 8 | 9 | Given three integer arrays sorted in ascending order, find the smallest number that is common in all three arrays. 10 | For example, let's look at the below three arrays. Here 6 is the smallest number that's common in all the arrays. 11 | 12 | ``` 13 | const a = [6, 7, 10, 25, 30, 63, 64] 14 | const b = [-1, 4, 5, 6, 7, 8, 50] 15 | const c = [1, 6, 10, 14] 16 | ``` 17 | 18 | ### Hints 19 | 20 | * Take advantage of sorted array to reduce complexity 21 | * Use three pointers 22 | -------------------------------------------------------------------------------- /ArraysAndStrings/smallestCommonNumber/solution.js: -------------------------------------------------------------------------------- 1 | const smallestCommonNumber = (arr1, arr2, arr3) => { 2 | let pointer1 = 0 3 | let pointer2 = 0 4 | let pointer3 = 0 5 | 6 | while ( 7 | pointer1 < arr1.length && 8 | pointer2 < arr2.length && 9 | pointer3 < arr3.length 10 | ) { 11 | // found smallest matching number 12 | if ( 13 | arr1[pointer1] === arr2[pointer2] && 14 | arr2[pointer2] === arr3[pointer3] 15 | ) { 16 | return arr1[pointer1] 17 | } 18 | 19 | // advance pointer for smallest number 20 | if (arr1[pointer1] <= arr2[pointer2] && arr1[pointer1] <= arr3[pointer3]) { 21 | pointer1 += 1 22 | } else if ( 23 | arr2[pointer2] <= arr1[pointer1] && 24 | arr2[pointer2] <= arr3[pointer3] 25 | ) { 26 | pointer2 += 1 27 | } else if ( 28 | arr3[pointer3] <= arr1[pointer1] && 29 | arr3[pointer3] <= arr2[pointer2] 30 | ) { 31 | pointer3 += 1 32 | } 33 | } 34 | 35 | return -1 36 | } 37 | 38 | module.exports = { smallestCommonNumber } 39 | -------------------------------------------------------------------------------- /ArraysAndStrings/smallestCommonNumber/test.js: -------------------------------------------------------------------------------- 1 | const { smallestCommonNumber } = require('./solution') 2 | 3 | test('smallestCommonNumber([6, 7, 10, 25, 30, 63, 64], [-1, 4, 5, 6, 7, 8, 50], [1, 6, 10, 14])', () => { 4 | expect( 5 | smallestCommonNumber( 6 | [6, 7, 10, 25, 30, 63, 64], 7 | [-1, 4, 5, 6, 7, 8, 50], 8 | [1, 6, 10, 14] 9 | ) 10 | ).toEqual(6) 11 | }) 12 | -------------------------------------------------------------------------------- /ArraysAndStrings/smallestDifference/prompt.md: -------------------------------------------------------------------------------- 1 | # Smallest Difference 2 | 3 | ## [Solution (JS)](./solution.js) / [Solution (Go)](./solution.go) 4 | 5 | Write a function that takes in two arrays of integers and finds the pair of numbers whose difference 6 | is closest to zero. (One from each array). It should return an array consisting of two numbers or an 7 | empty array, assume that there is only one pair with the smallest difference. 8 | 9 | ``` 10 | Sample input: [0, 20], [-13, 2, 5, 12, 19] 11 | Sample output: [20, 19] 12 | ``` 13 | -------------------------------------------------------------------------------- /ArraysAndStrings/smallestDifference/solution.go: -------------------------------------------------------------------------------- 1 | package program 2 | 3 | import ( 4 | "math" 5 | "sort" 6 | ) 7 | 8 | func SmallestDifference(array1, array2 []int) []int { 9 | sort.Ints(array1) 10 | sort.Ints(array2) 11 | idxOne, idxTwo := 0, 0 12 | smallestDiff, currentDiff := math.MaxInt32, math.MaxInt32 13 | smallestPair := []int{} 14 | for idxOne < len(array1) && idxTwo < len(array2) { 15 | numOne, numTwo := array1[idxOne], array2[idxTwo] 16 | if numOne < numTwo { 17 | currentDiff = numTwo - numOne 18 | idxOne++ 19 | } else if numTwo < numOne { 20 | currentDiff = numOne - numTwo 21 | idxTwo++ 22 | } else { 23 | return []int{numOne, numTwo} 24 | } 25 | if smallestDiff > currentDiff { 26 | smallestDiff = currentDiff 27 | smallestPair = []int{numOne, numTwo} 28 | } 29 | } 30 | return smallestPair 31 | } 32 | -------------------------------------------------------------------------------- /ArraysAndStrings/smallestDifference/solution.js: -------------------------------------------------------------------------------- 1 | function smallestDifference(arrayOne, arrayTwo) { 2 | arrayOne = arrayOne.sort((a, b) => a - b) 3 | arrayTwo = arrayTwo.sort((a, b) => a - b) 4 | let idxOne = 0, 5 | idxTwo = 0, 6 | smallestDiff = Infinity, 7 | currentDiff = Infinity, 8 | smallestPair = [] 9 | while (idxOne < arrayOne.length && idxTwo < arrayTwo.length) { 10 | let numOne = arrayOne[idxOne] 11 | let numTwo = arrayTwo[idxTwo] 12 | if (numOne < numTwo) { 13 | currentDiff = numTwo - numOne 14 | idxOne++ 15 | } else if (numTwo < numOne) { 16 | currentDiff = numOne - numTwo 17 | idxTwo++ 18 | } else { 19 | return [numOne, numTwo] 20 | } 21 | if (smallestDiff > currentDiff){ 22 | smallestDiff = currentDiff 23 | smallestPair = [numOne, numTwo] 24 | } 25 | } 26 | return smallestPair 27 | } 28 | 29 | console.log(smallestDifference([0, 20], [-13, 2, 5, 12, 19])) 30 | -------------------------------------------------------------------------------- /ArraysAndStrings/spiralMatrix/prompt.md: -------------------------------------------------------------------------------- 1 | # Spiral Matrix 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given a matrix of `m x n` elements (`m` rows, `n` columns), return all elements of the matrix in spiral order. 6 | 7 | For example, 8 | Given the following matrix: 9 | 10 | ``` 11 | [ 12 | [ 1, 2, 3 ], 13 | [ 4, 5, 6 ], 14 | [ 7, 8, 9 ] 15 | ] 16 | ``` 17 | 18 | You should return `[1,2,3,6,9,8,7,4,5]`. 19 | -------------------------------------------------------------------------------- /ArraysAndStrings/spiralMatrix/solution.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @param {number[][]} matrix 3 | * @return {number[]} 4 | */ 5 | var spiralOrder = function(matrix) { 6 | if (matrix.length === 0) return [] 7 | 8 | let output = [] 9 | let ceil = 0 10 | let floor = matrix.length - 1 11 | let left = 0 12 | let right = matrix[0].length - 1 13 | 14 | while (ceil <= floor && left <= right) { 15 | // collect top level 16 | for (let c = left; c <= right; c++) { 17 | output.push(matrix[ceil][c]) 18 | } 19 | ceil++ 20 | 21 | //collect right most 22 | for (let r = ceil; r <= floor; r++) { 23 | output.push(matrix[r][right]) 24 | } 25 | right-- 26 | 27 | //collect bottom 28 | if (ceil <= floor) { 29 | for (let c = right; c >= left; c--) { 30 | output.push(matrix[floor][c]) 31 | } 32 | } 33 | floor-- 34 | 35 | //collect left most 36 | if (left <= right) { 37 | for (let r = floor; r >= ceil; r--) { 38 | output.push(matrix[r][left]) 39 | } 40 | } 41 | left++ 42 | } 43 | 44 | return output 45 | } 46 | 47 | // let matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] 48 | // let matrix = [[1, 2], [3, 4]] 49 | let matrix = [[2, 3, 4], [5, 6, 7], [8, 9, 10], [11, 12, 13], [14, 15, 16]] 50 | 51 | console.log(spiralOrder(matrix)) 52 | -------------------------------------------------------------------------------- /ArraysAndStrings/stringSegmentation/prompt.md: -------------------------------------------------------------------------------- 1 | # String Segmentation 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given a dictionary of words and an input string tell whether the input string can be completely segmented into dictionary words. 6 | -------------------------------------------------------------------------------- /ArraysAndStrings/stringSegmentation/solution.js: -------------------------------------------------------------------------------- 1 | const stringSegmentation = (str, dict) => { 2 | const solved = new Set([]) 3 | return stringSegmentationRec(str, dict, solved) 4 | } 5 | 6 | const stringSegmentationRec = (str, dict, solved) => { 7 | for (let i = 0; i <= str.length; i++) { 8 | let first = str.substring(0, i) 9 | if (dict.has(first)) { 10 | let second = str.substring(i) 11 | if (second.length === 0) { 12 | return true 13 | } 14 | if (dict.has(second)) { 15 | return true 16 | } 17 | if (!solved.has(second)) { 18 | if (stringSegmentationRec(second, dict, solved)) { 19 | return true 20 | } 21 | solved.add(second) 22 | } 23 | } 24 | } 25 | return false 26 | } 27 | module.exports = { stringSegmentation } 28 | -------------------------------------------------------------------------------- /Design/medianDataStream/prompt.md: -------------------------------------------------------------------------------- 1 | # Find Median from Data Stream 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value. So the median is the mean of the two middle value. 6 | 7 | Examples: 8 | 9 | ``` 10 | [2,3,4] , the median is 3 11 | 12 | [2,3], the median is (2 + 3) / 2 = 2.5 13 | ``` 14 | 15 | Design a data structure that supports the following two operations: 16 | 17 | * void addNum(int num) - Add a integer number from the data stream to the data structure. 18 | * double findMedian() - Return the median of all elements so far. 19 | 20 | ## For example: 21 | 22 | ``` 23 | addNum(1) 24 | addNum(2) 25 | findMedian() -> 1.5 26 | addNum(3) 27 | findMedian() -> 2 28 | ``` 29 | -------------------------------------------------------------------------------- /Design/medianDataStream/solution.js: -------------------------------------------------------------------------------- 1 | /* 2 | * initialize your data structure here. 3 | */ 4 | var MedianFinder = function() { 5 | this.list = null 6 | this.length = 0 7 | } 8 | 9 | /* 10 | * @param {number} num 11 | * @return {void} 12 | */ 13 | MedianFinder.prototype.addNum = function(num) { 14 | if (this.list === null) { 15 | this.list = { val: num, next: null } 16 | } else { 17 | let currNode = this.list 18 | while (num >= currNode.val && currNode.next) { 19 | currNode = currNode.next 20 | } 21 | let newNode = { val: num, next: currNode.next } 22 | currNode.next = newNode 23 | } 24 | this.length++ 25 | // console.log('list', this.list) 26 | } 27 | 28 | /* 29 | * @return {number} 30 | */ 31 | MedianFinder.prototype.findMedian = function() { 32 | let counter = 0 33 | let medianNode = this.list 34 | while (counter < this.length / 2 - 1) { 35 | counter++ 36 | medianNode = medianNode.next 37 | } 38 | if (this.length % 2 === 0) { 39 | return (medianNode.val + medianNode.next.val) / 2 40 | } else { 41 | return medianNode.val 42 | } 43 | } 44 | 45 | /* 46 | * Your MedianFinder object will be instantiated and called as such: 47 | * var obj = Object.create(MedianFinder).createNew() 48 | * obj.addNum(num) 49 | * var param_2 = obj.findMedian() 50 | */ 51 | 52 | let test = new MedianFinder() 53 | test.addNum(-1) 54 | console.log(test.findMedian()) // [-1] => -1 55 | test.addNum(-2) 56 | console.log(test.findMedian()) // [-1, -2] => -1.5 57 | test.addNum(-3) 58 | console.log(test.findMedian()) // [-1, -2, -3] => -2 59 | test.addNum(-4) 60 | console.log(test.findMedian()) // [-1, -2, -3, -4] => -2.5 61 | test.addNum(-5) 62 | console.log(test.findMedian()) // [-1, -2, -3, -4, -5] => -3 63 | -------------------------------------------------------------------------------- /Design/movingAverageDataStream/prompt.md: -------------------------------------------------------------------------------- 1 | # Moving Average from Data Stream 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given a stream of integers and a window size, calculate the moving average of all integers in the sliding window. 6 | 7 | For example, 8 | 9 | ``` 10 | MovingAverage m = new MovingAverage(3); 11 | m.next(1) = 1 12 | m.next(10) = (1 + 10) / 2 13 | m.next(3) = (1 + 10 + 3) / 3 14 | m.next(5) = (10 + 3 + 5) / 3 15 | ``` 16 | -------------------------------------------------------------------------------- /Design/movingAverageDataStream/solution.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Initialize your data structure here. 3 | * @param {number} size 4 | */ 5 | var MovingAverage = function(size) { 6 | this.windowSize = size 7 | this.windowSum = 0 8 | this.windowStartIndex = 0 9 | this.numbers = [] 10 | } 11 | 12 | /* 13 | * @param {number} val 14 | * @return {number} 15 | */ 16 | MovingAverage.prototype.next = function(val) { 17 | // time: O(1) space: O(n) 18 | if (this.numbers.length >= this.windowSize) { 19 | this.windowSum -= this.numbers[this.windowStartIndex] 20 | this.windowStartIndex++ 21 | } 22 | this.numbers.push(val) 23 | this.windowSum += this.numbers[this.numbers.length - 1] 24 | return this.windowSum / (this.numbers.length - this.windowStartIndex) 25 | } 26 | 27 | /* 28 | * Your MovingAverage object will be instantiated and called as such: 29 | * var obj = Object.create(MovingAverage).createNew(size) 30 | * var param_1 = obj.next(val) 31 | */ 32 | -------------------------------------------------------------------------------- /Design/rangeSumQuery/prompt.md: -------------------------------------------------------------------------------- 1 | # Peeking Iterator 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given an Iterator class interface with methods: `next()` and `hasNext()`, design and implement a PeekingIterator that support the `peek()` operation -- it essentially `peek()` at the element that will be returned by the next call to `next()`. 6 | 7 | Here is an example. Assume that the iterator is initialized to the beginning of the list: `[1, 2, 3]`. 8 | 9 | Call `next()` gets you `1`, the first element in the list. 10 | 11 | Now you call `peek()` and it returns `2`, the next element. Calling `next()` after that still return `2`. 12 | 13 | You call `next()` the final time and it returns `3`, the last element. Calling `hasNext()` after that should return `false`. 14 | 15 | Follow up: How would you extend your design to be generic and work with all types, not just integer? 16 | 17 | Credits: 18 | Special thanks to @porker2008 for adding this problem and creating all test cases. 19 | -------------------------------------------------------------------------------- /Design/rangeSumQuery/solution.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @param {number[][]} matrix 3 | */ 4 | var NumMatrix = function(matrix) { 5 | if (matrix === null || matrix.length === 0 || matrix[0].length === 0) return 6 | 7 | this.matrix = matrix 8 | this.rows = matrix.length 9 | this.cols = matrix[0].length 10 | 11 | // row sums 12 | for (let r = 0; r < this.rows; r++) { 13 | for (let c = 1; c < this.cols; c++) { 14 | this.matrix[r][c] = this.matrix[r][c] + this.matrix[r][c - 1] 15 | } 16 | } 17 | } 18 | 19 | /* 20 | * @param {number} row 21 | * @param {number} col 22 | * @param {number} val 23 | * @return {void} 24 | */ 25 | NumMatrix.prototype.update = function(row, col, val) { 26 | let original = 27 | col === 0 28 | ? this.matrix[row][0] 29 | : this.matrix[row][col] - this.matrix[row][col - 1] 30 | 31 | let diff = val - original 32 | 33 | for (let c = col; c < this.cols; c++) { 34 | this.matrix[row][c] += diff 35 | } 36 | } 37 | 38 | /* 39 | * @param {number} row1 40 | * @param {number} col1 41 | * @param {number} row2 42 | * @param {number} col2 43 | * @return {number} 44 | */ 45 | NumMatrix.prototype.sumRegion = function(row1, col1, row2, col2) { 46 | let sum = 0 47 | for (let r = row1; r <= row2; r++) { 48 | sum += 49 | col1 === 0 50 | ? this.matrix[r][col2] 51 | : this.matrix[r][col2] - this.matrix[r][col1 - 1] 52 | } 53 | return sum 54 | } 55 | 56 | // naive solution 57 | // /* 58 | // * @param {number[][]} matrix 59 | // */ 60 | // var NumMatrix = function(matrix) { 61 | // this.matrix = [] 62 | // for (let row = 0; row < matrix.length; row++) { 63 | // this.matrix[row] = [] 64 | // for (let col = 0; col < matrix[row].length; col++) { 65 | // this.matrix[row][col] = matrix[row][col] 66 | // } 67 | // } 68 | // } 69 | 70 | // /* 71 | // * @param {number} row 72 | // * @param {number} col 73 | // * @param {number} val 74 | // * @return {void} 75 | // */ 76 | // NumMatrix.prototype.update = function(row, col, val) { 77 | // this.matrix[row][col] = val 78 | // } 79 | 80 | // /* 81 | // * @param {number} row1 82 | // * @param {number} col1 83 | // * @param {number} row2 84 | // * @param {number} col2 85 | // * @return {number} 86 | // */ 87 | // NumMatrix.prototype.sumRegion = function(row1, col1, row2, col2) { 88 | // let sum = 0 89 | // for (let row = row1; row <= row2; row++) { 90 | // for (let col = col1; col <= col2; col++) { 91 | // sum += this.matrix[row][col] 92 | // } 93 | // } 94 | // return sum 95 | // } 96 | 97 | let matrix = [ 98 | [3, 0, 1, 4, 2], 99 | [5, 6, 3, 2, 1], 100 | [1, 2, 0, 1, 5], 101 | [4, 1, 0, 1, 7], 102 | [1, 0, 3, 0, 5] 103 | ] 104 | 105 | let myMatrix = new NumMatrix(matrix) 106 | myMatrix.update(0, 0, 9) 107 | -------------------------------------------------------------------------------- /DynamicProgramming/fibonacci/prompt.md: -------------------------------------------------------------------------------- 1 | # Fibonacci 2 | 3 | ## [Solution (JS)](./solution.js) / [Solution (Go)](./solution.go) 4 | 5 | Write a function that returns the nth number of the Fibonacci Sequence. 6 | 7 | ``` 8 | Sample input: 7 9 | Sample output: 8 (fib. sequence: 0, 1, 1, 2, 3, 5, 8) 10 | ``` 11 | -------------------------------------------------------------------------------- /DynamicProgramming/fibonacci/solution.go: -------------------------------------------------------------------------------- 1 | package program 2 | 3 | func GetNthFib(n int) int { 4 | prevprev := 0 5 | prev := 1 6 | for i := 2; i < n; i++ { 7 | current := prev + prevprev 8 | prevprev = prev 9 | prev = current 10 | } 11 | if n > 1 { 12 | return prev 13 | } else { 14 | return prevprev 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /DynamicProgramming/fibonacci/solution.js: -------------------------------------------------------------------------------- 1 | function getNthFib(n) { 2 | let prevprev = 0 3 | let prev = 1 4 | for (let i = 2; i < n; i++) { 5 | let current = prev + prevprev 6 | prevprev = prev 7 | prev = current 8 | } 9 | return n > 1 ? prev : prevprev 10 | } 11 | -------------------------------------------------------------------------------- /DynamicProgramming/levenshteinDistance/prompt.md: -------------------------------------------------------------------------------- 1 | # Levenshtein Distance 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Write a function that takes two strings and returns the minimum number of operations on the first string necessary to get the second string. Operations include: insertion of character, deletion of character, and substitution of a character for another. 6 | 7 | ``` 8 | Sample Input: 'abc', 'yadc' 9 | Sample Output: 2 (insert y and sub d for b) 10 | ``` 11 | -------------------------------------------------------------------------------- /DynamicProgramming/levenshteinDistance/solution.js: -------------------------------------------------------------------------------- 1 | function levenshteinDistance (strA, strB) { 2 | if (strA.length === 0) return strB.length 3 | if (strB.length === 0) return strA.length 4 | 5 | const minEdits = [] 6 | 7 | // Build base 2D array for min num of edits 8 | for (let i = 0; i < strB.length + 1; i++) { 9 | const row = [] 10 | for (let j = 0; j < strA.length + 1; j++) { 11 | row.push(j) 12 | } 13 | row[0] = 1 14 | minEdits.push(row) 15 | } 16 | for (let i = 1; i < strB.length + 1; i++) { 17 | for (let j = 1; j < strA.length + 1; j++) { 18 | if (strB[i - 1] === strA[j - 1]) { 19 | minEdits[i][j] = minEdits[i - 1][j - 1] 20 | } else { 21 | minEdits[i][j] = 1 + Math.min(minEdits[i - 1][j - 1], minEdits[i - 1][j], minEdits[i][j - 1]) 22 | } 23 | } 24 | } 25 | return minEdits[strB.length][strA.length] 26 | } 27 | -------------------------------------------------------------------------------- /DynamicProgramming/maxProfitWithKTransactions/prompt.md: -------------------------------------------------------------------------------- 1 | # Max Profit with K Transactions 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | You are given an array of integers representing the prices of a single stock on various days (each index in the array represents a different day). You are also given an integer k, which represents the number of transactions you are allowed to make. One transaction consists of buying the stock on a given day and selling it on another, later day. Write a function that returns the maximum profit that you can make buying and selling the stock, given k transactions. Note that you can only hold 1 share of the stock at a time; in other words, you cannot buy more than 1 share of the stock on any given day, and you cannot buy a share of the stock if you are still holding another share. 6 | -------------------------------------------------------------------------------- /DynamicProgramming/maxProfitWithKTransactions/solution.js: -------------------------------------------------------------------------------- 1 | const maxProfitWithKTransactions = (prices, k) => { 2 | if (prices.length < 2 || k < 1) return 0 3 | 4 | // initialize transactions x days profit matrix as all 0s 5 | const profits = [] 6 | for (let i = 0; i <= k; i++) { 7 | profits.push(new Array(prices.length).fill(0)) 8 | } 9 | 10 | // build up transaction x days profit matric 11 | for (let transactions = 1; transactions <= k; transactions++) { 12 | for (let day = 1; day < prices.length; day++) { 13 | let maxProfitWithSale = -Infinity 14 | for (let i = day - 1; i >= 0; i--) { 15 | let profitWithSale = 16 | prices[day] - prices[i] + profits[transactions - 1][i] 17 | if (profitWithSale > maxProfitWithSale) { 18 | maxProfitWithSale = profitWithSale 19 | } 20 | } 21 | profits[transactions][day] = Math.max( 22 | profits[transactions][day - 1], 23 | maxProfitWithSale 24 | ) 25 | } 26 | } 27 | return profits[k][prices.length - 1] 28 | } 29 | 30 | module.exports = { maxProfitWithKTransactions } 31 | -------------------------------------------------------------------------------- /DynamicProgramming/maxProfitWithKTransactions/test.js: -------------------------------------------------------------------------------- 1 | const { maxProfitWithKTransactions } = require('./solution') 2 | 3 | test('maxProfitWithKTransactions #1', () => { 4 | expect(maxProfitWithKTransactions([], 1)).toEqual(0) 5 | }) 6 | 7 | test('maxProfitWithKTransactions #2', () => { 8 | expect(maxProfitWithKTransactions([1], 1)).toEqual(0) 9 | }) 10 | 11 | test('maxProfitWithKTransactions #3', () => { 12 | expect(maxProfitWithKTransactions([1, 10], 1)).toEqual(9) 13 | }) 14 | 15 | test('maxProfitWithKTransactions #4', () => { 16 | expect(maxProfitWithKTransactions([1, 10], 3)).toEqual(9) 17 | }) 18 | 19 | test('maxProfitWithKTransactions #5', () => { 20 | expect(maxProfitWithKTransactions([3, 2, 5, 7, 1, 3, 7], 1)).toEqual(6) 21 | }) 22 | 23 | test('maxProfitWithKTransactions #6', () => { 24 | expect(maxProfitWithKTransactions([5, 11, 3, 50, 60, 90], 2)).toEqual(93) 25 | }) 26 | 27 | test('maxProfitWithKTransactions #7', () => { 28 | expect(maxProfitWithKTransactions([5, 11, 3, 50, 40, 90], 2)).toEqual(97) 29 | }) 30 | 31 | test('maxProfitWithKTransactions #8', () => { 32 | expect(maxProfitWithKTransactions([5, 11, 3, 50, 40, 90], 3)).toEqual(103) 33 | }) 34 | -------------------------------------------------------------------------------- /DynamicProgramming/palindromePartitioningMinCuts/prompt.md: -------------------------------------------------------------------------------- 1 | # Palindrome Partitioning Min Cuts 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given a non-empty string, write a function that returns the minimum number of cuts needed to perform on the string such that each remaining substring is a palindrome. A palindrome is defined as a string that is written the same forward as backward. Note that single-character strings are palindromes. 6 | 7 | ``` 8 | Sample Input: 'noonabbad' 9 | Sample Output: 2 ('noon' | 'abba' | 'd') 10 | ``` 11 | -------------------------------------------------------------------------------- /DynamicProgramming/palindromePartitioningMinCuts/solution.js: -------------------------------------------------------------------------------- 1 | const palindromePartitioningMinCuts = str => { 2 | if (str.length === 1) return 0 3 | 4 | // is the substring from i to j a palindrome? 5 | const palindromicity = [] 6 | for (let i = 0; i < str.length; i++) { 7 | palindromicity.push([]) 8 | for (let j = i; j < str.length; j++) { 9 | let left = i 10 | let right = j 11 | let isPalindrome = true 12 | while (left <= right) { 13 | if (str[left] !== str[right]) { 14 | isPalindrome = false 15 | break 16 | } 17 | left++ 18 | right-- 19 | } 20 | palindromicity[i][j] = isPalindrome 21 | } 22 | } 23 | 24 | // array of min cuts for substring 0 to i 25 | let cuts = new Array(str.length).fill(Infinity) 26 | for (let i = 0; i < str.length; i++) { 27 | if (palindromicity[0][i]) { 28 | cuts[i] = 0 29 | } else { 30 | cuts[i] = cuts[i - 1] + 1 31 | for (let j = 1; j < i; j++) { 32 | if (palindromicity[j][i] && cuts[j - 1] + 1 < cuts[i]) { 33 | cuts[i] = cuts[j - 1] + 1 34 | } 35 | } 36 | } 37 | } 38 | return cuts[cuts.length - 1] 39 | } 40 | 41 | module.exports = { palindromePartitioningMinCuts } 42 | -------------------------------------------------------------------------------- /DynamicProgramming/palindromePartitioningMinCuts/test.js: -------------------------------------------------------------------------------- 1 | const { palindromePartitioningMinCuts } = require('./solution') 2 | 3 | test('palindromePartitioningMinCuts #1', () => { 4 | expect(palindromePartitioningMinCuts('a')).toEqual(0) 5 | }) 6 | 7 | test('palindromePartitioningMinCuts #2', () => { 8 | expect(palindromePartitioningMinCuts('abbb')).toEqual(1) 9 | }) 10 | 11 | test('palindromePartitioningMinCuts #3', () => { 12 | expect(palindromePartitioningMinCuts('ababbbabbababa')).toEqual(3) 13 | }) 14 | 15 | test('palindromePartitioningMinCuts #4', () => { 16 | expect(palindromePartitioningMinCuts('abbacecffgbgffab')).toEqual(4) 17 | }) 18 | 19 | test('palindromePartitioningMinCuts #5', () => { 20 | expect( 21 | palindromePartitioningMinCuts('abcdefghijklmnoracecarpqrstuvwxyz') 22 | ).toEqual(26) 23 | }) 24 | -------------------------------------------------------------------------------- /DynamicProgramming/rodCutting/prompt.md: -------------------------------------------------------------------------------- 1 | # Rod Cutting Problem 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given a rod of size n and values of various sizes of rod. The problem is to cut the rod in such a way that the sum of values of the pieces is maximum. 6 | -------------------------------------------------------------------------------- /DynamicProgramming/rodCutting/solution.js: -------------------------------------------------------------------------------- 1 | const rodCutting = (length, values) => { 2 | const optimalValues = [0] 3 | for (let i = 1; i < length; i++) { 4 | optimalValues[i] = -Infinity 5 | for (let k = 0; k < i; k++) { 6 | optimalValues[i] = Math.max( 7 | optimalValues[i], 8 | values[k] + optimalValues[i - k - 1] 9 | ) 10 | } 11 | } 12 | return optimalValues[length] 13 | } 14 | -------------------------------------------------------------------------------- /DynamicProgramming/tripleStep/prompt.md: -------------------------------------------------------------------------------- 1 | # Triple Step 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | A child is running up a staircase with n staeps and can hop either 1 step, 2 steps, or 3 steps at a time. Implement a method to count how many possible ways the child can run up the stairs. 6 | -------------------------------------------------------------------------------- /DynamicProgramming/tripleStep/solution.js: -------------------------------------------------------------------------------- 1 | const tripleStep = n => { 2 | return waysToStep(n, {}) 3 | } 4 | 5 | const waysToStep = (n, memo) => { 6 | if (n < 0) { 7 | return 0 8 | } else if (n === 0) { 9 | return 1 10 | } else if (memo[n] !== undefined) { 11 | return memo[n] 12 | } else { 13 | memo[n] = 14 | waysToStep(n - 1, memo) + 15 | waysToStep(n - 2, memo) + 16 | waysToStep(n - 3, memo) 17 | return memo[n] 18 | } 19 | } 20 | 21 | module.exports = { tripleStep } 22 | -------------------------------------------------------------------------------- /DynamicProgramming/tripleStep/test.js: -------------------------------------------------------------------------------- 1 | const { tripleStep } = require('./solution') 2 | 3 | test('tripleStep(0)', () => { 4 | expect(tripleStep(0)).toEqual(1) 5 | }) 6 | 7 | test('tripleStep(3)', () => { 8 | expect(tripleStep(3)).toEqual(4) 9 | }) 10 | 11 | test('tripleStep(5)', () => { 12 | expect(tripleStep(5)).toEqual(13) 13 | }) 14 | 15 | test('tripleStep(23)', () => { 16 | expect(tripleStep(23)).toEqual(755476) 17 | }) 18 | -------------------------------------------------------------------------------- /DynamicProgramming/wordBreak/prompt.md: -------------------------------------------------------------------------------- 1 | # Word Break 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, determine if s can be segmented into a space-separated sequence of one or more dictionary words. You may assume the dictionary does not contain duplicate words. 6 | 7 | For example, given 8 | 9 | ``` 10 | s = "leetcode", 11 | dict = ["leet", "code"]. 12 | ``` 13 | 14 | Return true because "leetcode" can be segmented as "leet code". 15 | -------------------------------------------------------------------------------- /DynamicProgramming/wordBreak/solution.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} s 3 | * @param {string[]} wordDict 4 | * @return {boolean} 5 | */ 6 | const wordBreak = (s, wordDict) => { 7 | // time: O(n^2) space: O(n) 8 | let matchingSubstring = [true] //because null string is always present 9 | 10 | for (let i = 0; i <= s.length; i++) { 11 | for (let j = 0; j < i; j++) { 12 | if (matchingSubstring[j] && wordDict.includes(s.substring(j, i))) { 13 | matchingSubstring[i] = true 14 | break 15 | } 16 | } 17 | } 18 | return matchingSubstring[s.length] ? true : false 19 | } 20 | 21 | // Naive solution 22 | // time: O(n^n) space: O(n) 23 | // const wordBreak = (s, wordDict) => { 24 | // if (s === '') return true 25 | // let options = [] 26 | // for (let i = 0; i < wordDict.length; i++) { 27 | // if (s.startsWith(wordDict[i])) { 28 | // options.push(i) 29 | // } 30 | // } 31 | // for (let i = 0; i < options.length; i++) { 32 | // if (wordBreak(s.slice(wordDict[options[i]].length), wordDict)) { 33 | // return true 34 | // } 35 | // } 36 | // return false 37 | // } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Alex Villarreal 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LinkedLists/deleteNode/prompt.md: -------------------------------------------------------------------------------- 1 | # Delete Node with a Given Key 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given head of a linked list and a key, delete node with this given key from the linked list. 6 | -------------------------------------------------------------------------------- /LinkedLists/deleteNode/solution.js: -------------------------------------------------------------------------------- 1 | const deleteNode = (head, key) => { 2 | if (head.data === key) { 3 | return head.next 4 | } 5 | 6 | let currentNode = head 7 | while (currentNode.next) { 8 | if (currentNode.next.data === key) { 9 | currentNode.next = currentNode.next.next 10 | } else { 11 | currentNode = currentNode.next 12 | } 13 | } 14 | 15 | return head 16 | } 17 | 18 | module.exports = { deleteNode } 19 | -------------------------------------------------------------------------------- /LinkedLists/deleteNode/test.js: -------------------------------------------------------------------------------- 1 | const { deleteNode } = require('./solution') 2 | 3 | test('deleteNode(list, key)', () => { 4 | let list = { 5 | data: 20, 6 | next: { 7 | data: 14, 8 | next: { 9 | data: 36, 10 | next: { 11 | data: 11, 12 | next: { 13 | data: 72, 14 | next: { 15 | data: 41, 16 | next: null 17 | } 18 | } 19 | } 20 | } 21 | } 22 | } 23 | list = deleteNode(list, 72) 24 | expect(list).toEqual({ 25 | data: 20, 26 | next: { 27 | data: 14, 28 | next: { 29 | data: 36, 30 | next: { 31 | data: 11, 32 | next: { 33 | data: 41, 34 | next: null 35 | } 36 | } 37 | } 38 | } 39 | }) 40 | }) 41 | -------------------------------------------------------------------------------- /LinkedLists/intersectionPointOfTwoLists/prompt.md: -------------------------------------------------------------------------------- 1 | # Intersection Point of Two Lists 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given head nodes of two linked lists that may or may not intersect, find out if they intersect and return the point of intersection; return null otherwise. 6 | -------------------------------------------------------------------------------- /LinkedLists/intersectionPointOfTwoLists/solution.js: -------------------------------------------------------------------------------- 1 | const intersection = (head1, head2) => { 2 | if (!head1 || !head2) return null 3 | // find length of list 1 4 | let length1 = 1 5 | let current1 = head1 6 | while (current1.next) { 7 | length1 += 1 8 | current1 = current1.next 9 | } 10 | // find length of list 2 11 | let length2 = 1 12 | let current2 = head2 13 | while (current2.next) { 14 | length2 += 1 15 | current2 = current2.next 16 | } 17 | // advance head of longer list 18 | if (length1 > length2) { 19 | while (length1 > length2) { 20 | head1 = head1.next 21 | length1 -= 1 22 | } 23 | } else if (length2 > length1) { 24 | while (length2 > length1) { 25 | head2 = head2.next 26 | length2 -= 1 27 | } 28 | } 29 | // iterate through both, if match return, else return null 30 | while (head1) { 31 | if (head1 === head2) { 32 | return head1 33 | } 34 | head1 = head1.next 35 | head2 = head2.next 36 | } 37 | 38 | return null 39 | } 40 | 41 | module.exports = { intersection } 42 | -------------------------------------------------------------------------------- /LinkedLists/linkedListLoop/prompt.md: -------------------------------------------------------------------------------- 1 | # Find Loop 2 | 3 | ## [Solution (JS)](./solution.js) / [Solution (Go)](./solution.go) 4 | 5 | Write a function that takes in the head of a singly linked list that contains a loop and returns the node from which the loop originates. 6 | Every node has a value and a next property. 7 | 8 | ``` 9 | Sample Input: 10 | n0 -> n1 -> n2 -> n3 -> n4 -> n5 11 | ^ v 12 | n8 <- n7 13 | Sample Output: 14 | n4 15 | ``` 16 | -------------------------------------------------------------------------------- /LinkedLists/linkedListLoop/solution.go: -------------------------------------------------------------------------------- 1 | package program 2 | 3 | type LinkedList struct { 4 | value int 5 | next *LinkedList 6 | } 7 | 8 | func LinkedListLoop(head *LinkedList) *LinkedList { 9 | slowNode := head.next 10 | fastNode := head.next.next 11 | 12 | for slowNode != fastNode { 13 | slowNode = slowNode.next 14 | fastNode = fastNode.next.next 15 | } 16 | 17 | slowNode = head 18 | 19 | for slowNode != fastNode { 20 | slowNode = slowNode.next 21 | fastNode = fastNode.next 22 | } 23 | 24 | return slowNode 25 | } 26 | -------------------------------------------------------------------------------- /LinkedLists/linkedListLoop/solution.js: -------------------------------------------------------------------------------- 1 | function linkedListLoop(head) { 2 | let slowNode = head 3 | let fastNode = head.next 4 | 5 | // Increment nodes until you are in the loop 6 | while (slowNode !== fastNode){ 7 | slowNode = slowNode.next 8 | fastNode = fastNode.next.next 9 | } 10 | 11 | // Calculate beginning of loop 12 | slowNode = head 13 | while (slowNode !== fastNode) { 14 | slowNode = slowNode.next 15 | fastNode = fastNode.next 16 | } 17 | 18 | // Return node that starts loop 19 | return slowNode 20 | } 21 | -------------------------------------------------------------------------------- /LinkedLists/mergeKSortedLists/prompt.md: -------------------------------------------------------------------------------- 1 | # Merge k Sorted Lists 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. 6 | 7 | ``` 8 | /** 9 | * Definition for singly-linked list. 10 | * function ListNode(val) { 11 | * this.val = val; 12 | * this.next = null; 13 | * } 14 | */ 15 | /** 16 | * @param {ListNode[]} lists 17 | * @return {ListNode} 18 | */ 19 | ``` 20 | -------------------------------------------------------------------------------- /LinkedLists/mergeKSortedLists/solution.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * function ListNode(val) { 4 | * this.val = val; 5 | * this.next = null; 6 | * } 7 | */ 8 | /** 9 | * @param {ListNode[]} lists 10 | * @return {ListNode} 11 | */ 12 | const mergeKLists = lists => { 13 | if (lists === null) return null 14 | 15 | // delete all empty lists 16 | for (let i = 0; i < lists.length; ) { 17 | if (lists[i]) { 18 | i++ 19 | } else { 20 | lists.splice(i, 1) 21 | } 22 | } 23 | 24 | if (lists.length === 0) return null 25 | 26 | let mergedList = null 27 | let minNodeIndex = -1 28 | 29 | // continue until array of lists is 0 length 30 | while (lists.length > 0) { 31 | let minNode = { val: Infinity } 32 | // find smallest list head 33 | for (let i = 0; i < lists.length; i++) { 34 | if (lists[i].val <= minNode.val) { 35 | minNode = lists[i] 36 | minNodeIndex = i 37 | } 38 | } 39 | 40 | // add said head to new list 41 | if (mergedList === null) { 42 | mergedList = new ListNode() 43 | mergedList.val = minNode.val 44 | } else { 45 | let currentNode = mergedList 46 | while (currentNode.next) { 47 | currentNode = currentNode.next 48 | } 49 | currentNode.next = new ListNode() 50 | currentNode.next.val = minNode.val 51 | } 52 | 53 | // shorten list that head was taken from 54 | // if list is of 0 length remove from array 55 | if (lists[minNodeIndex].next !== null) { 56 | lists[minNodeIndex] = lists[minNodeIndex].next 57 | } else { 58 | lists.splice(minNodeIndex, 1) 59 | } 60 | } 61 | 62 | return mergedList 63 | } 64 | -------------------------------------------------------------------------------- /LinkedLists/nthFromLastNode/prompt.md: -------------------------------------------------------------------------------- 1 | # Nth from last node 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given a singly linked list, return nth from last node. Return null if 'n' is out-of-bounds. 6 | -------------------------------------------------------------------------------- /LinkedLists/nthFromLastNode/solution.js: -------------------------------------------------------------------------------- 1 | const nthFromLastNode = (head, n) => { 2 | if (!head || n < 1) { 3 | return null 4 | } 5 | 6 | let tail = head 7 | let nth = head 8 | 9 | // move tail n away from nth 10 | while (tail && n > 0) { 11 | tail = tail.next 12 | n -= 1 13 | } 14 | if (n !== 0) return null 15 | 16 | while (tail) { 17 | tail = tail.next 18 | nth = nth.next 19 | } 20 | 21 | return nth 22 | } 23 | 24 | module.exports = { nthFromLastNode } 25 | -------------------------------------------------------------------------------- /LinkedLists/nthFromLastNode/test.js: -------------------------------------------------------------------------------- 1 | const { nthFromLastNode } = require('./solution') 2 | 3 | test('nthFromLastNode(list)', () => { 4 | let list = { 5 | data: 7, 6 | next: { 7 | data: 14, 8 | next: { 9 | data: 21, 10 | next: { 11 | data: 28, 12 | next: { 13 | data: 35, 14 | next: { 15 | data: 42, 16 | next: null 17 | } 18 | } 19 | } 20 | } 21 | } 22 | } 23 | expect(nthFromLastNode(list, 3).data).toEqual(28) 24 | }) 25 | -------------------------------------------------------------------------------- /LinkedLists/removeDuplicatesFromList/prompt.md: -------------------------------------------------------------------------------- 1 | # Remove Duplicates from a Linked List 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Remove duplicate nodes from linked list of integers while keeping only the first occurrence of duplicates. 6 | -------------------------------------------------------------------------------- /LinkedLists/removeDuplicatesFromList/solution.js: -------------------------------------------------------------------------------- 1 | const removeDuplicates = head => { 2 | const visited = {} 3 | 4 | let currentNode = head 5 | visited[currentNode.data] = true 6 | 7 | while (currentNode.next) { 8 | if (visited[currentNode.next.data]) { 9 | currentNode.next = currentNode.next.next 10 | } else { 11 | visited[currentNode.next.data] = true 12 | currentNode = currentNode.next 13 | } 14 | } 15 | return head 16 | } 17 | 18 | module.exports = { removeDuplicates } 19 | -------------------------------------------------------------------------------- /LinkedLists/removeDuplicatesFromList/test.js: -------------------------------------------------------------------------------- 1 | const { removeDuplicates } = require('./solution') 2 | 3 | test('removeDuplicates(list)', () => { 4 | let list = { 5 | data: 7, 6 | next: { 7 | data: 14, 8 | next: { 9 | data: 28, 10 | next: { 11 | data: 28, 12 | next: { 13 | data: 14, 14 | next: { 15 | data: 21, 16 | next: null 17 | } 18 | } 19 | } 20 | } 21 | } 22 | } 23 | list = removeDuplicates(list) 24 | expect(list).toEqual({ 25 | data: 7, 26 | next: { 27 | data: 14, 28 | next: { 29 | data: 28, 30 | next: { 31 | data: 21, 32 | next: null 33 | } 34 | } 35 | } 36 | }) 37 | }) 38 | -------------------------------------------------------------------------------- /LinkedLists/reverseSinglyLinkedList/prompt.md: -------------------------------------------------------------------------------- 1 | # Reverse a Singly Linked List 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given the pointer/reference to the head of a singly linked list, reverse it and return the pointer/reference to the head of reversed linked list. 6 | -------------------------------------------------------------------------------- /LinkedLists/reverseSinglyLinkedList/solution.js: -------------------------------------------------------------------------------- 1 | const reverse = head => { 2 | if (!head || !head.next) { 3 | return head 4 | } 5 | 6 | let currentHead = head.next 7 | let reversedHead = head 8 | reversedHead.next = null 9 | 10 | while (currentHead) { 11 | let temp = currentHead 12 | currentHead = currentHead.next 13 | 14 | temp.next = reversedHead 15 | reversedHead = temp 16 | } 17 | return reversedHead 18 | } 19 | 20 | module.exports = { reverse } 21 | -------------------------------------------------------------------------------- /Other/LRUCache/prompt.md: -------------------------------------------------------------------------------- 1 | # Implement LRU Cache 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Implement LRU (Least Recently Used) Cache. Discuss data structures involved. 6 | -------------------------------------------------------------------------------- /Other/LRUCache/solution.js: -------------------------------------------------------------------------------- 1 | class LRUCache { 2 | constructor (capacity) { 3 | this.capacity = capacity 4 | this.cache = {} 5 | this.cacheVals = new LinkedList() 6 | } 7 | 8 | set (key, value) { 9 | if (this.cache[key]) { 10 | let node = this.cache[key] 11 | // add node to tail of list 12 | this.cacheVals.remove(node) 13 | this.cacheVals.insertAtTail(node) 14 | } else { 15 | // evict 16 | this.evictIfNeedeed() 17 | // add to cache 18 | let newNode = new LinkedListNode(key, value) 19 | this.cacheVals.insertAtTail(newNode) 20 | this.cache[key] = newNode 21 | } 22 | } 23 | 24 | get (key, value) { 25 | if (this.cache[key]) { 26 | let node = this.cache[key] 27 | this.cacheVals.remove(node) 28 | this.cacheVals.insertAtTail(node) 29 | return node.data 30 | } else { 31 | return -1 32 | } 33 | } 34 | 35 | evictIfNeedeed () { 36 | if (this.cacheVals.size >= this.capacity) { 37 | let removedNode = this.cacheVals.removeHead() 38 | this.cache.remove(removedNode) 39 | } 40 | } 41 | } 42 | 43 | class LinkedList { 44 | constructor () { 45 | this.head = null 46 | this.tail = null 47 | this.size = 0 48 | } 49 | 50 | insertAtHead (node) { 51 | if (!this.head) { 52 | this.head = node 53 | this.tail = node 54 | } else { 55 | node.next = this.head 56 | this.head.prev = node 57 | this.head = node 58 | } 59 | this.size += 1 60 | } 61 | 62 | insertAtTail (node) { 63 | if (!this.tail) { 64 | this.head = node 65 | this.tail = node 66 | } else { 67 | node.prev = this.tail 68 | this.tail.next = node 69 | this.tail = node 70 | } 71 | this.size += 1 72 | } 73 | 74 | remove (node) { 75 | if (!node) return 76 | 77 | if (node.prev !== null) { 78 | node.prev.next = node.next 79 | } 80 | if (node.next !== null) { 81 | node.next.prev = node.prev 82 | } 83 | if (node === this.head) { 84 | this.head = node.next 85 | this.head.prev = null 86 | } 87 | if (node === this.tail) { 88 | this.tail = node.prev 89 | this.tail.next = null 90 | } 91 | 92 | this.size -= 1 93 | 94 | return node 95 | } 96 | 97 | removeHead () { 98 | return this.remove(this.head) 99 | } 100 | 101 | removeTail () { 102 | return this.remove(this.tail) 103 | } 104 | } 105 | 106 | class LinkedListNode { 107 | constructor (key, data) { 108 | this.data = data 109 | this.key = key 110 | this.next = null 111 | this.prev = null 112 | } 113 | } 114 | 115 | module.exports = { LRUCache } 116 | -------------------------------------------------------------------------------- /Other/boggle/prompt.md: -------------------------------------------------------------------------------- 1 | # Boggle 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given a dictionary, a method to do lookup in dictionary, and a M x N board where every cell has one character. 6 | Find all possible words that can be formed by a sequence of adjacent characters. Note that we can move to any of 8 adjacent characters, 7 | but a word should not have multiple instances of same cell. 8 | -------------------------------------------------------------------------------- /Other/boggle/solution.js: -------------------------------------------------------------------------------- 1 | function boggle (boggle, trie) { 2 | let rows = boggle.getNumRows() 3 | let cols = boggle.getNumCols() 4 | 5 | let charStack = [] 6 | let words = [] 7 | 8 | function findWords (row, col, node) { 9 | if (visited[row][col]) return 10 | if (!node || !node.has(boggle.charAt(row, col))) return 11 | node = node.next(boggle.charAt(row, col)) 12 | 13 | charStack.push(boggle.charAt(row, col)) 14 | visited[row][col] = true 15 | 16 | for (let dx = -1; dx <= 1; dx++) { 17 | let c = col + dx 18 | if (c < 0 || c >= cols) continue 19 | 20 | for (let dy = -1; dy <= 1; dy++) { 21 | let r = row + dy 22 | if (r < 0 || r >= rows) continue 23 | if (dx === 0 && dy === 0) continue 24 | 25 | findWords(r, c, node) 26 | } 27 | } 28 | 29 | if (node.isEndOfWord) { 30 | let s = '' 31 | for (let i = 0; i < charStack.length; i++) { 32 | s = s + charStack[i] 33 | } 34 | words.push(s) 35 | } 36 | 37 | visited[row][col] = false 38 | charStack.pop() 39 | } 40 | 41 | // Initialize each position as not visited 42 | let visited = [] 43 | for (let row = 0; row < rows; row++) { 44 | visited[row] = [] 45 | for (let col = 0; col < cols; col++) { 46 | visited[row][col] = false 47 | } 48 | } 49 | 50 | for (let r = 0; r < rows; r++) { 51 | for (let c = 0; c < cols; c++) { 52 | findWords(r, c, trie) 53 | } 54 | } 55 | 56 | return words 57 | }; 58 | -------------------------------------------------------------------------------- /Other/rootNumber/prompt.md: -------------------------------------------------------------------------------- 1 | # Nth Root of a Number 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Many times, we need to re-implement basic functions without using any standard library functions already implemented. For example, when designing a chip that requires very little memory space. 6 | 7 | In this question we’ll implement a function `root` that calculates the `n’th` root of a number. The function takes a nonnegative number x and a positive integer `n`, and returns the positive `n’th` root of `x` within an error of `0.001` (i.e. suppose the real root is `y`, then the error is: `|y-root(x,n)|` and must satisfy `|y-root(x,n)| < 0.001`). 8 | 9 | Don’t be intimidated by the question. While there are many algorithms to calculate roots that require prior knowledge in numerical analysis, there is also an elementary method which doesn’t require more than guessing-and-checking. Try to think more in terms of the latter. 10 | 11 | Make sure your algorithm is efficient, and analyze its time and space complexities. 12 | 13 | Examples: 14 | 15 | ``` 16 | input: x = 7, n = 3 17 | output: 1.913 18 | 19 | input: x = 9, n = 2 20 | output: 3 21 | ``` 22 | -------------------------------------------------------------------------------- /Other/rootNumber/solution.js: -------------------------------------------------------------------------------- 1 | function root(x, n) { 2 | if (x === 0) return 0 3 | 4 | let lowerBound = 0 5 | let upperBound = Math.max(1, x) 6 | let currentGuess = (upperBound + lowerBound) / 2 7 | 8 | while (currentGuess - lowerBound >= 0.001) { 9 | if (Math.pow(currentGuess, n) > x) { 10 | upperBound = currentGuess 11 | } else { 12 | lowerBound = currentGuess 13 | } 14 | currentGuess = (upperBound + lowerBound) / 2 15 | } 16 | return currentGuess 17 | } 18 | -------------------------------------------------------------------------------- /Other/wordDecryption/prompt.md: -------------------------------------------------------------------------------- 1 | # Decrypt Message 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | An infamous gang of cyber criminals named “The Gray Cyber Mob”, which is behind many hacking attacks and drug trafficking, has recently become a target for the FBI. After intercepting some of their messages, which looked like complete nonsense, the agency learned that they indeed encrypt their messages, and studied their method of encryption. 6 | 7 | Their messages consist of lowercase latin letters only, and every word is encrypted separately as follows: 8 | 9 | Convert every letter to its ASCII value. Add 1 to the first letter, and then for every letter from the second one to the last one, add the value of the previous letter. Subtract 26 from every letter until it is in the range of lowercase letters a-z in ASCII. Convert the values back to letters. 10 | 11 | For instance, to encrypt the word “crime” 12 | 13 | ``` 14 | Decrypted message: c r i m e 15 | Step 1: 99 114 105 109 101 16 | Step 2: 100 214 319 428 529 17 | Step 3: 100 110 111 116 113 18 | Encrypted message: d n o t q 19 | ``` 20 | 21 | The FBI needs an efficient method to decrypt messages. Write a function named decrypt(word) that receives a string that consists of small latin letters only, and returns the decrypted word. 22 | 23 | Explain your solution and analyze its time and space complexities. 24 | 25 | Examples: 26 | 27 | ``` 28 | input: word = "dnotq" 29 | output: "crime" 30 | 31 | input: word = "flgxswdliefy" 32 | output: "encyclopedia" 33 | ``` 34 | 35 | Since the function should be used on messages with many words, make sure the function is as efficient as possible in both time and space. Explain the correctness of your function, and analyze its asymptotic runtime and space complexity. 36 | 37 | Note: Most programing languages have built-in methods of converting letters to ASCII values and vica versa. You may search the internet for the appropriate method. 38 | -------------------------------------------------------------------------------- /Other/wordDecryption/solution.js: -------------------------------------------------------------------------------- 1 | function decrypt(word) { 2 | if (word === '') return '' 3 | 4 | let decryptedString = '' 5 | 6 | // first letter 7 | let encryptedFirst = word.charCodeAt(0) 8 | let decryptedFirst = encryptedFirst - 1 9 | decryptedString += String.fromCharCode(decryptedFirst) 10 | 11 | // other letters 12 | let encryptedPrevious = encryptedFirst 13 | for (let i = 1; i < word.length; i++) { 14 | let encryptedLetter = word.charCodeAt(i) 15 | let currentVal = encryptedLetter - encryptedPrevious 16 | // while ascii value isn't with valid range continue to add 26 17 | while (currentVal < 97) { 18 | encryptedLetter += 26 19 | currentVal = encryptedLetter - encryptedPrevious 20 | } 21 | encryptedPrevious += currentVal 22 | decryptedString += String.fromCharCode(currentVal) 23 | } 24 | 25 | return decryptedString 26 | } 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Algorithms 2 | 3 | A collection of solutions to common algorithm questions in both Javascript and Go (sometimes). 4 | 5 | Javascript is formatted with ESlint and Standard for sanity, tests are run with Jest. 6 | 7 | ## Index 8 | 9 | ### Arrays and Strings 10 | 11 | * [arrayQuadrupletSum](./ArraysAndStrings/arrayQuadrupletSum/prompt.md) 12 | * [binarySearch](./ArraysAndStrings/binarySearch/prompt.md) 13 | * [budgetCuts](./ArraysAndStrings/budgetCuts/prompt.md) 14 | * [findAllPalindromeSubstrings](./ArraysAndStrings/findAllPalindromeSubstrings/prompt.md) 15 | * [flattenDictionary](./ArraysAndStrings/flattenDictionary/prompt.md) 16 | * [kEmptySlots](./ArraysAndStrings/kEmptySlots/prompt.md) 17 | * [longestIncreasingSubsequence](./ArraysAndStrings/longestIncreasingSubsequence/prompt.md) 18 | * [longestSubstringWithAtMostKDistinctCharacters (whew)](./ArraysAndStrings/longestSubstringWithAtMostKDistinctCharacters/prompt.md) 19 | * [matchingBrackets](./ArraysAndStrings/matchingBrackets/prompt.md) 20 | * [maxSlidingWindow](./ArraysAndStrings/maxSlidingWindow/prompt.md) 21 | * [medianOfTwoSortedArrays](./ArraysAndStrings/medianOfTwoSortedArrays/prompt.md) 22 | * [minNumberOfJumps](./ArraysAndStrings/minNumberOfJumps/prompt.md) 23 | * [moveZerosToLeft](./ArraysAndStrings/moveZerosToLeft/prompt.md) 24 | * [pairSum](./ArraysAndStrings/pairSum/prompt.md) 25 | * [palindrome](./ArraysAndStrings/palindrome/prompt.md) 26 | * [plusOne](./ArraysAndStrings/plusOne/prompt.md) 27 | * [powerSet](./ArraysAndStrings/powerSet/prompt.md) 28 | * [rainWater](./ArraysAndStrings/rainWater/prompt.md) 29 | * [repeatedStringMatch](./ArraysAndStrings/repeatedStringMatch/prompt.md) 30 | * [rotateArray](./ArraysAndStrings/rotateArray/prompt.md) 31 | * [searchRotatedArray](./ArraysAndStrings/searchRotatedArray/prompt.md) 32 | * [sentenceReverse](./ArraysAndStrings/sentenceReverse/prompt.md) 33 | * [smallestCommonNumber](./ArraysAndStrings/smallestCommonNumber/prompt.md) 34 | * [smallestDifference](./ArraysAndStrings/smallestDifference/prompt.md) 35 | * [spiralMatrix](./ArraysAndStrings/spiralMatrix/prompt.md) 36 | * [stringSegmentation](./ArraysAndStrings/stringSegmentation/prompt.md) 37 | 38 | ### Design 39 | 40 | * [medianDataStream](./Design/medianDataStream/prompt.md) 41 | * [movingAverageDataStream](./Design/movingAverageDataStream/prompt.md) 42 | * [rangeSumQuery](./Design/rangeSumQuery/prompt.md) 43 | 44 | ### Dynamic Programming 45 | 46 | * [coinChange](./DynamicProgramming/coinChange/prompt.md) 47 | * [fibonacci](./DynamicProgramming/fibonacci/prompt.md) 48 | * [levenshteinDistance](./DynamicProgramming/levenshteinDistance/prompt.md) 49 | * [maxProfitWithKTransactions](./DynamicProgramming/maxProfitWithKTransactions/prompt.md) 50 | * [palindromePartitioningMinCuts](./DynamicProgramming/palindromePartitioningMinCuts`/prompt.md) 51 | * [rodCutting](./DynamicProgramming/rodCutting/prompt.md) 52 | * [tripleStep](./DynamicProgramming/tripleStep/prompt.md) 53 | * [wordBreak](./DynamicProgramming/wordBreak/prompt.md) 54 | 55 | ### Linked Lists 56 | 57 | * [deleteNode](./LinkedLists/deleteNode/prompt.md) 58 | * [intersectionPointOfTwoLists](./LinkedLists/intersectionPointOfTwoLists/prompt.md) 59 | * [linkedListLoop](./LinkedLists/linkedListLoop/prompt.md) 60 | * [mergeKSortedLists](./LinkedLists/mergeKSortedLists/prompt.md) 61 | * [nthFromLastNode](./LinkedLists/nthFromLastNode/prompt.md) 62 | * [removeDuplicatesFromList](./LinkedLists/removeDuplicatesFromList/prompt.md) 63 | * [reverseSinglyLinkedList](./LinkedLists/reverseSinglyLinkedList/prompt.md) 64 | 65 | ### Other 66 | 67 | * [boggle](./Other/boggle/prompt.md) 68 | * [LRUCache](./Other/LRUCache/prompt.md) 69 | * [rootNumber](./Other/rootNumber/prompt.md) 70 | * [wordDecryption](./Other/wordDecryption/prompt.md) 71 | 72 | ### Recursion 73 | 74 | * [numberOfPaths](./Recursion/numberOfPaths/prompt.md) 75 | * [permuteString](./Recursion/permuteString/prompt.md) 76 | * [sudokuSolver](./Recursion/sudokuSolver/prompt.md) 77 | 78 | ### Searching and Sorting 79 | 80 | * [bubbleSort](./SortingAndSearching/bubbleSort/prompt.md) 81 | * [insertionSort](./SortingAndSearching/insertionSort/prompt.md) 82 | * [kthLargestElementInArray](./SortingAndSearching/kthLargestElementInArray/prompt.md) 83 | * [mergeIntervals](./SortingAndSearching/mergeIntervals/prompt.md) 84 | * [minimumWindowSubstring](./SortingAndSearching/minimumWindowSubstring/prompt.md) 85 | * [pancakeSort](./SortingAndSearching/pancakeSort/prompt.md) 86 | * [quickSort](./SortingAndSearching/quickSort/prompt.md) 87 | 88 | ### Trees and Graphs 89 | 90 | * [binarySearchTree](./TreesAndGraphs/binarySearchTree/prompt.md) 91 | * [cloneDirectedGraph](./TreesAndGraphs/cloneDirectedGraph/prompt.md) 92 | * [closestBinarySearchTreeValue](./TreesAndGraphs/closestBinarySearchTreeValue/prompt.md) 93 | * [depthFirstSearch](./TreesAndGraphs/depthFirstSearch/prompt.md) 94 | * [evaluateDivision](./TreesAndGraphs/evaluateDivision/prompt.md) 95 | * [inorderBstSuccessor](./TreesAndGraphs/inorderBstSuccessor/prompt.md) 96 | * [longestUnivaluePath](./TreesAndGraphs/longestUnivaluePath/prompt.md) 97 | * [numberOfPossibleBinaryTreeTopologies](./TreesAndGraphs/numberOfPossibleBinaryTreeTopologies/prompt.md) 98 | * [riverSizes](./TreesAndGraphs/riverSizes/prompt.md) 99 | * [validateBst](./TreesAndGraphs/validateBst/prompt.md) 100 | -------------------------------------------------------------------------------- /Recursion/numberOfPaths/prompt.md: -------------------------------------------------------------------------------- 1 | # Number of Paths 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | You’re testing a new driverless car that is located at the Southwest (bottom-left) corner of an n×n grid. The car is supposed to get to the opposite, Northeast (top-right), corner of the grid. Given `n`, the size of the grid’s axes, write a function `numOfPathsToDest` that returns the number of the possible paths the driverless car can take. 6 | 7 | For convenience, let’s represent every square in the grid as a pair `(i,j)`. The first coordinate in the pair denotes the east-to-west axis, and the second coordinate denotes the south-to-north axis. The initial state of the car is `(0,0)`, and the destination is `(n-1,n-1)`. 8 | 9 | The car must abide by the following two rules: it cannot cross the diagonal border. In other words, in every step the position `(i,j)` needs to maintain `i >= j`. See the illustration above for `n = 5`. In every step, it may go one square North (up), or one square East (right), but not both. E.g. if the car is at `(3,1)`, it may go to `(3,2)` or `(4,1)`. 10 | 11 | Explain the correctness of your function, and analyze its time and space complexities. 12 | 13 | Example: 14 | 15 | ``` 16 | input: n = 4 17 | 18 | output: 5 # since there are five possibilities: 19 | # “EEENNN”, “EENENN”, “ENEENN”, “ENENEN”, “EENNEN”, 20 | # where the 'E' character stands for moving one step 21 | # East, and the 'N' character stands for moving one step 22 | # North (so, for instance, the path sequence “EEENNN” 23 | # stands for the following steps that the car took: 24 | # East, East, East, North, North, North) 25 | ``` 26 | -------------------------------------------------------------------------------- /Recursion/numberOfPaths/solution.js: -------------------------------------------------------------------------------- 1 | // time: O(n^2) space: O(n^2) 2 | function numOfPathsToDest(n) { 3 | if (n < 3) return 1 4 | 5 | // keep track of num paths to given vertex 6 | const memo = [] 7 | for (let i = 0; i < n; i++) { 8 | for (let j = 0; j < n; j++) { 9 | if (j === 0) memo[i] = [] 10 | memo[i][j] = -1 11 | } 12 | } 13 | 14 | return numOfPathsTo(n - 1, n - 1, memo) 15 | } 16 | 17 | function numOfPathsTo(x, y, memo) { 18 | if (x < 0 || y < 0) { 19 | return 0 20 | } else if (x < y) { 21 | memo[x][y] = 0 22 | } else if (memo[x][y] !== -1) { 23 | return memo[x][y] 24 | } else if (x === 0 && y === 0) { 25 | memo[x][y] = 1 26 | } else { 27 | memo[x][y] = numOfPathsTo(x - 1, y, memo) + numOfPathsTo(x, y - 1, memo) 28 | } 29 | return memo[x][y] 30 | } 31 | -------------------------------------------------------------------------------- /Recursion/permuteString/prompt.md: -------------------------------------------------------------------------------- 1 | # Permute String 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Implement a method to print all permutations of a given string 6 | 7 | ### Example 8 | 9 | ``` 10 | Input: 'bad' 11 | Output: ['bad', 'bda', 'abd', 'adb', 'dba', 'dab'] 12 | ``` 13 | -------------------------------------------------------------------------------- /Recursion/permuteString/solution.js: -------------------------------------------------------------------------------- 1 | const permuteString = str => { 2 | const permutations = [] 3 | for (let i = 0; i < str.length; i++) { 4 | permuteStringRec(str, [i], str[i], permutations) 5 | } 6 | return permutations 7 | } 8 | 9 | const permuteStringRec = (str, visitedIndices, permutation, permutations) => { 10 | if (permutation.length === str.length) { 11 | permutations.push(permutation) 12 | } else { 13 | for (let i = 0; i < str.length; i++) { 14 | if (visitedIndices.includes(i)) continue 15 | permuteStringRec( 16 | str, 17 | [...visitedIndices, i], 18 | permutation + str[i], 19 | permutations 20 | ) 21 | } 22 | } 23 | } 24 | 25 | module.exports = { permuteString } 26 | -------------------------------------------------------------------------------- /Recursion/permuteString/test.js: -------------------------------------------------------------------------------- 1 | const { permuteString } = require('./solution') 2 | 3 | test('permuteString #1', () => { 4 | expect(permuteString('bad')).toEqual([ 5 | 'bad', 6 | 'bda', 7 | 'abd', 8 | 'adb', 9 | 'dba', 10 | 'dab' 11 | ]) 12 | }) 13 | -------------------------------------------------------------------------------- /Recursion/sudokuSolver/prompt.md: -------------------------------------------------------------------------------- 1 | # Sudoku Solver 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Write the function sudokuSolve that checks whether a given sudoku board (i.e. sudoku puzzle) is solvable. If so, the function will returns true. Otherwise (i.e. there is no valid solution to the given sudoku board), returns false. 6 | 7 | In sudoku, the objective is to fill a `9x9` board with digits so that each column, each row, and each of the nine `3x3` sub-boards that compose the board contains all of the digits from 1 to 9. The board setter provides a partially completed board, which for a well-posed board has a unique solution. `As explained above, for this problem, it suffices to calculate whether a given sudoku board has a solution. No need to return the actual numbers that make up a solution.` 8 | 9 | A sudoku board is represented as a two-dimensional `9x9` array of the characters ‘1’,‘2’,…,‘9’ and the '.' character, which represents a blank space. The function should fill the blank spaces with characters such that the following rules apply: 10 | 11 | 1. In every row of the array, all characters ‘1’,‘2’,…,‘9’ appear exactly once. 12 | 2. In every column of the array, all characters ‘1’,‘2’,…,‘9’ appear exactly once. 13 | 3. In every 3x3 sub-board that is illustrated below, all characters ‘1’,‘2’,…,‘9’ appear exactly once. 14 | 15 | A solved sudoku is a board with no blank spaces, i.e. all blank spaces are filled with characters that abide to the constraints above. If the function succeeds in solving the sudoku board, it’ll return true (false, otherwise). 16 | 17 | Example (more examples can be found [here](http://www.sudokukingdom.com/)) 18 | -------------------------------------------------------------------------------- /Recursion/sudokuSolver/solution.js: -------------------------------------------------------------------------------- 1 | function sudokuSolve(board) { 2 | // your code goes here 3 | // 3 rules 4 | // 1. every column has to have 1-9 in it 5 | // 2. every row has to have 1-9 in it 6 | // 3. every sub-board needs to have 1-9 in it 7 | 8 | let candidates = null 9 | let candidateRow = -1 10 | let candidateCol = -1 11 | for (let r = 0; r < 9; r++) { 12 | for (let c = 0; c < 9; c++) { 13 | if (board[r][c] === '.') { 14 | let newCandidates = getCandidates(r, c, board) 15 | // remember position with shortest set of candidates 16 | if (candidates === null || newCandidates.length < candidates.length) { 17 | candidates = newCandidates 18 | candidateRow = r 19 | candidateCol = c 20 | } 21 | } 22 | } 23 | } 24 | 25 | // no candidates === solved board 26 | if (candidates === null) { 27 | return true 28 | } 29 | 30 | // recursively solve board with each candidate substituted for empty space 31 | for (let i = 0; i < candidates.length; i++) { 32 | board[candidateRow][candidateCol] = candidates[i] 33 | if (sudokuSolve(board)) return true 34 | board[candidateRow][candidateCol] = '.' 35 | } 36 | 37 | return false 38 | } 39 | 40 | function getCandidates(r, c, board) { 41 | let candidates = [] 42 | 43 | // for each character 44 | for (let char = 1; char < 10; char++) { 45 | let collision = false 46 | // check if collision 47 | for (let i = 0; i < 9; i++) { 48 | if ( 49 | board[r][i] === `${char}` || 50 | board[i][c] === `${char}` || 51 | board[r - r % 3 + Math.floor(i / 3)][c - c % 3 + i % 3] === `${char}` 52 | ) { 53 | collision = true 54 | break 55 | } 56 | } 57 | 58 | // if no collision we add to candidates 59 | if (!collision) { 60 | candidates.push(`${char}`) 61 | } 62 | } 63 | 64 | return candidates 65 | } 66 | 67 | const testBoard = [ 68 | ['.', '8', '9', '.', '4', '.', '6', '.', '5'], 69 | ['.', '7', '.', '.', '.', '8', '.', '4', '1'], 70 | ['5', '6', '.', '9', '.', '.', '.', '.', '8'], 71 | ['.', '.', '.', '7', '.', '5', '.', '9', '.'], 72 | ['.', '9', '.', '4', '.', '1', '.', '5', '.'], 73 | ['.', '3', '.', '9', '.', '6', '.', '1', '.'], 74 | ['8', '.', '.', '.', '.', '.', '.', '.', '7'], 75 | ['.', '2', '.', '8', '.', '.', '.', '6', '.'], 76 | ['.', '.', '6', '.', '7', '.', '.', '8', '.'] 77 | ] 78 | 79 | console.log(sudokuSolve(testBoard)) //false 80 | -------------------------------------------------------------------------------- /SortingAndSearching/bubbleSort/prompt.md: -------------------------------------------------------------------------------- 1 | # Bubble Sort 2 | 3 | ## [Solution (JS)](./solution.js) / [Solution (Go)](./solution.go) 4 | 5 | Write a function that takes an array of integers and sorts them using the bubble sort method. 6 | 7 | "Bubble sort, sometimes referred to as sinking sort, is a simple sorting algorithm that repeatedly steps through the list to be sorted, compares each pair of adjacent items and swaps them if they are in the wrong order. The pass through the list is repeated until no swaps are needed, which indicates that the list is sorted. " 8 | 9 | ``` 10 | Sample Input: 11 | [8, 4, 2, 34, 9, -1, 12] 12 | Sample Output: 13 | [-1, 2, 4, 8, 9, 12, 34] 14 | ``` 15 | -------------------------------------------------------------------------------- /SortingAndSearching/bubbleSort/solution.go: -------------------------------------------------------------------------------- 1 | package program 2 | 3 | func BubbleSort(array []int) []int { 4 | sorted := false 5 | for !sorted { 6 | sorted = true 7 | for i := 1; i < len(array); i++ { 8 | if array[i] < array[i-1] { 9 | temp := array[i] 10 | array[i] = array[i-1] 11 | array[i-1] = temp 12 | sorted = false 13 | } 14 | } 15 | } 16 | return array 17 | } 18 | -------------------------------------------------------------------------------- /SortingAndSearching/bubbleSort/solution.js: -------------------------------------------------------------------------------- 1 | function bubbleSort(array) { 2 | let sorted = false 3 | while (!sorted) { 4 | sorted = true 5 | for (let i = 0; i < array.length; i++) { 6 | if (array[i + 1] < array[i]) { 7 | let nextVal = array[i + 1] 8 | array[i + 1] = array[i] 9 | array[i] = nextVal 10 | sorted = false 11 | } 12 | } 13 | } 14 | return array 15 | } 16 | -------------------------------------------------------------------------------- /SortingAndSearching/insertionSort/prompt.md: -------------------------------------------------------------------------------- 1 | # Insertion Sort 2 | 3 | ## [Solution (JS)](./solution.js) / [Solution (Go)](./solution.go) 4 | 5 | Write a function that takes an array of integers and sorts them using the insertion sort method. 6 | 7 | ``` 8 | Sample Input: 9 | [8, 4, 2, 34, 9, -1, 12] 10 | Sample Output: 11 | [-1, 2, 4, 8, 9, 12, 34] 12 | ``` 13 | -------------------------------------------------------------------------------- /SortingAndSearching/insertionSort/solution.go: -------------------------------------------------------------------------------- 1 | package program 2 | 3 | func InsertionSort(array []int) []int { 4 | for i := 0; i < len(array); i++ { 5 | j := i 6 | for j > 0 && array[j] < array[j-1] { 7 | temp := array[j] 8 | array[j] = array[j-1] 9 | array[j-1] = temp 10 | j-- 11 | } 12 | } 13 | return array 14 | } 15 | -------------------------------------------------------------------------------- /SortingAndSearching/insertionSort/solution.js: -------------------------------------------------------------------------------- 1 | function insertionSort(array) { 2 | for (let i = 1; i < array.length; i++) { 3 | let j = i 4 | while (j > 0 && array[j] < array[j - 1]) { 5 | let temp = array[j] 6 | array[j] = array[j - 1] 7 | array[j - 1] = temp 8 | j-- 9 | } 10 | } 11 | return array 12 | } 13 | -------------------------------------------------------------------------------- /SortingAndSearching/kthLargestElementInArray/prompt.md: -------------------------------------------------------------------------------- 1 | # Kth Largest Element in an Array 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element. 6 | 7 | For example, 8 | Given `[3,2,1,5,6,4]` and `k = 2`, return `5`. 9 | 10 | Note: 11 | You may assume `k` is always valid, `1 ≤ k ≤ array.length`. 12 | -------------------------------------------------------------------------------- /SortingAndSearching/kthLargestElementInArray/solution.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @param {number[]} nums 3 | * @param {number} k 4 | * @return {number} 5 | */ 6 | 7 | // time: O(nlogn) 8 | const findKthLargest = (nums, k) => { 9 | nums.sort((a, b) => a - b) 10 | return nums[nums.length - k] 11 | } 12 | -------------------------------------------------------------------------------- /SortingAndSearching/mergeIntervals/prompt.md: -------------------------------------------------------------------------------- 1 | # Merge Intervals 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given a collection of intervals, merge all overlapping intervals. 6 | 7 | ### Example 1: 8 | 9 | ``` 10 | Input: [[1,3],[2,6],[8,10],[15,18]] 11 | Output: [[1,6],[8,10],[15,18]] 12 | Explanation: Since intervals [1,3] and [2,6] overlaps, merge them into [1,6]. 13 | ``` 14 | 15 | ### Example 2: 16 | 17 | ``` 18 | Input: [[1,4],[4,5]] 19 | Output: [[1,5]] 20 | Explanation: Intervals [1,4] and [4,5] are considerred overlapping. 21 | ``` 22 | -------------------------------------------------------------------------------- /SortingAndSearching/mergeIntervals/solution.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for an interval. 3 | * function Interval(start, end) { 4 | * this.start = start; 5 | * this.end = end; 6 | * } 7 | */ 8 | /** 9 | * @param {Interval[]} intervals 10 | * @return {Interval[]} 11 | */ 12 | function Interval (start, end) { 13 | this.start = start 14 | this.end = end 15 | } 16 | 17 | const merge = intervals => { 18 | intervals = intervals.sort((a, b) => a.start - b.start) 19 | for (let i = 1; i < intervals.length; i++) { 20 | let prev = intervals[i - 1] 21 | let curr = intervals[i] 22 | if (curr.start <= prev.end) { 23 | intervals.splice( 24 | i - 1, 25 | 2, 26 | new Interval( 27 | Math.min(prev.start, curr.start), 28 | Math.max(prev.end, curr.end) 29 | ) 30 | ) 31 | i -= 1 32 | } 33 | } 34 | return intervals 35 | } 36 | 37 | module.exports = { merge } 38 | -------------------------------------------------------------------------------- /SortingAndSearching/mergeIntervals/test.js: -------------------------------------------------------------------------------- 1 | const { merge } = require('./solution') 2 | 3 | xtest('[[1,3],[2,6],[8,10],[15,18]]', () => { 4 | expect(merge([[1, 3], [2, 6], [8, 10], [15, 18]])).toEqual([ 5 | [1, 6], 6 | [8, 10], 7 | [15, 18] 8 | ]) 9 | }) 10 | 11 | xtest('[[1,4],[0,2],[3,5]]', () => { 12 | expect(merge([[1, 4], [0, 2], [3, 5]])).toEqual([[0, 5]]) 13 | }) 14 | -------------------------------------------------------------------------------- /SortingAndSearching/minimumWindowSubstring/prompt.md: -------------------------------------------------------------------------------- 1 | # Minimum Window Substring 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n). 6 | 7 | For example, 8 | 9 | ``` 10 | S = "ADOBECODEBANC" 11 | T = "ABC" 12 | ``` 13 | 14 | Minimum window is `"BANC"`. 15 | 16 | Note: 17 | If there is no such window in S that covers all characters in T, return the empty string "". 18 | 19 | If there are multiple such windows, you are guaranteed that there will always be only one unique minimum window in S. 20 | -------------------------------------------------------------------------------- /SortingAndSearching/minimumWindowSubstring/solution.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @param {string} s 3 | * @param {string} t 4 | * @return {string} 5 | */ 6 | const minWindow = (s, t) => { 7 | if (s === null || s.length < t.length) return '' 8 | 9 | // find number of each character necessary 10 | let charsNecessary = {} 11 | for (let character of t) { 12 | if (charsNecessary[character]) { 13 | charsNecessary[character] += 1 14 | } else { 15 | charsNecessary[character] = 1 16 | } 17 | } 18 | 19 | let start = 0 20 | let numberOfCharsNecessary = t.length 21 | for (let end = 0; end < s.length; end++) { 22 | if (charsNecessary[s[end]]) { 23 | numberOfCharsNecessary -= 1 24 | } 25 | } 26 | console.log(counter) 27 | } 28 | 29 | console.log(minWindow('abcd', 'abc')) 30 | -------------------------------------------------------------------------------- /SortingAndSearching/pancakeSort/prompt.md: -------------------------------------------------------------------------------- 1 | # Pancake Sort 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given an array of integers arr: 6 | 7 | * Write a function flip(arr, k) that reverses the order of the first k elements in the array arr. 8 | * Write a function pancakeSort(arr) that sorts and returns the input array. You are allowed to use only the function flip you wrote in the first step in order to make changes in the array. 9 | 10 | ## Example: 11 | 12 | ``` 13 | input: arr = [1, 5, 4, 3, 2] 14 | 15 | output: [1, 2, 3, 4, 5] # to clarify, this is pancakeSort's output 16 | ``` 17 | 18 | Analyze the time and space complexities of your solution. 19 | 20 | Note: it’s called pancake sort because it resembles sorting pancakes on a plate with a spatula, where you can only use the spatula to flip some of the top pancakes in the plate. To read more about the problem, see the Pancake Sorting Wikipedia page. 21 | -------------------------------------------------------------------------------- /SortingAndSearching/pancakeSort/solution.js: -------------------------------------------------------------------------------- 1 | // time: O(n^2) space: O(1) 2 | function pancakeSort(arr) { 3 | let workingLength = arr.length 4 | while (workingLength > 1) { 5 | let max = arr[0] 6 | let maxIndex = 0 7 | for (let i = 1; i < workingLength; i++) { 8 | if (arr[i] > max) { 9 | max = arr[i] 10 | maxIndex = i 11 | } 12 | } 13 | flip(arr, maxIndex + 1) 14 | flip(arr, workingLength) 15 | workingLength-- 16 | } 17 | return arr 18 | } 19 | 20 | function flip(arr, k) { 21 | let left = 0 22 | let right = k - 1 23 | while (left < right) { 24 | let temp = arr[left] 25 | arr[left] = arr[right] 26 | arr[right] = temp 27 | left++ 28 | right-- 29 | } 30 | } 31 | 32 | // pancakeSort([1, 5, 4, 3, 2]) 33 | -------------------------------------------------------------------------------- /SortingAndSearching/quickSort/prompt.md: -------------------------------------------------------------------------------- 1 | # Quick Sort 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given an integer array, sort it in ascending order using quicksort. 6 | 7 | ### Example 8 | 9 | ``` 10 | Input: [55, 23, 26, 2, 5] 11 | Output: [2, 23, 25, 26, 55] 12 | ``` 13 | 14 | Here is an overview of how the quicksort algorithm works. 15 | 16 | * Select a pivot element from the array. We can pick the first element as the pivot (following Hoare's algorithm). Another common approach is to select a random element as the pivot. 17 | * Reorder the array by comparing with the pivot element such that smaller values end up at the left side, and the larger values end up at the right side of the pivot. 18 | * Now, the pivot element is in its correct sorted position. 19 | 20 | Applying the above steps, we can recursively sort the sublists on the right and left sides of the pivot. 21 | -------------------------------------------------------------------------------- /SortingAndSearching/quickSort/solution.js: -------------------------------------------------------------------------------- 1 | const quicksort = arr => { 2 | quicksortRec(arr, 0, arr.length - 1) 3 | } 4 | 5 | const quicksortRec = (arr, low, high) => { 6 | if (high > low) { 7 | let pivot = parition(arr, low, high) 8 | quicksortRec(arr, low, pivot - 1) 9 | quicksortRec(arr, pivot + 1, high) 10 | } 11 | } 12 | 13 | const parition = (arr, low, high) => { 14 | let pivotVal = arr[low] 15 | let i = low 16 | let j = high 17 | 18 | while (i < j) { 19 | while (i <= high && arr[i] <= pivotVal) { 20 | i++ 21 | } 22 | while (arr[j] > pivotVal) { 23 | j-- 24 | } 25 | if (i < j) { 26 | let temp = arr[i] 27 | arr[i] = arr[j] 28 | arr[j] = temp 29 | } 30 | } 31 | 32 | arr[low] = arr[j] 33 | arr[j] = pivotVal 34 | 35 | return j 36 | } 37 | 38 | module.exports = { quicksort } 39 | -------------------------------------------------------------------------------- /SortingAndSearching/quickSort/test.js: -------------------------------------------------------------------------------- 1 | const { quicksort } = require('./solution') 2 | 3 | test('quicksort([55, 23, 26, 2, 5])', () => { 4 | let array = [55, 23, 26, 2, 5] 5 | quicksort(array) 6 | expect(array).toEqual([2, 5, 23, 26, 55]) 7 | }) 8 | 9 | test('quicksort([1, 10, 20, 0, 59, 63, 0, 88, 0])', () => { 10 | let array = [1, 10, 20, 0, 59, 63, 0, 88, 0] 11 | quicksort(array) 12 | expect(array).toEqual([0, 0, 0, 1, 10, 20, 59, 63, 88]) 13 | }) 14 | -------------------------------------------------------------------------------- /TreesAndGraphs/binarySearchTree/prompt.md: -------------------------------------------------------------------------------- 1 | # Binary Search Tree 2 | 3 | ## [Solution (JS)](./solution.js) / [Solution (Go)](./solution.go) 4 | 5 | Create a Binary Search Tree class with insert, contains, and remove methods. Every class should have a value (integer) and a left and right property which points to either null or another BST instance. 6 | 7 | ``` 8 | Sample Input: 9 | 12 10 | / \ 11 | 8 14 12 | / \ / \ 13 | 5 10 13 25 14 | / \ 15 | 1 30 16 | Sample Output: 17 | contains(25) => true 18 | 19 | insert(11) => 20 | 12 21 | / \ 22 | 8 14 23 | / \ / \ 24 | 5 10 13 25 25 | / \ \ 26 | 1 11 30 27 | 28 | remove(14) => 29 | 12 30 | / \ 31 | 8 13 32 | / \ \ 33 | 5 10 25 34 | / \ 35 | 1 30 36 | ``` 37 | -------------------------------------------------------------------------------- /TreesAndGraphs/binarySearchTree/solution.go: -------------------------------------------------------------------------------- 1 | package program 2 | 3 | type BST struct { 4 | value int 5 | 6 | left *BST 7 | right *BST 8 | } 9 | 10 | func (tree *BST) Insert(value int) *BST { 11 | if value >= tree.value { 12 | if tree.right == nil { 13 | tree.right = &BST{value: value} 14 | } else { 15 | tree.right.Insert(value) 16 | } 17 | } else if tree.left == nil { 18 | tree.left = &BST{value: value} 19 | } else { 20 | tree.left.Insert(value) 21 | } 22 | return tree 23 | } 24 | 25 | func (tree *BST) Contains(value int) bool { 26 | if value == tree.value { 27 | return true 28 | } else if value > tree.value && tree.right != nil { 29 | return tree.right.Contains(value) 30 | } else if value < tree.value && tree.left != nil { 31 | return tree.left.Contains(value) 32 | } else { 33 | return false 34 | } 35 | } 36 | 37 | func (tree *BST) getMinValue() int { 38 | if tree.left == nil { 39 | return tree.value 40 | } else { 41 | return tree.left.getMinValue() 42 | } 43 | } 44 | 45 | func (tree *BST) Remove(value int) *BST { 46 | tree.remove(value, nil) 47 | return tree 48 | } 49 | 50 | func (tree *BST) remove(value int, parent *BST) *BST { 51 | if value < tree.value { 52 | if tree.left != nil { 53 | tree.left.remove(value, tree) 54 | } 55 | } else if value > tree.value { 56 | if tree.right != nil { 57 | tree.right.remove(value, tree) 58 | } 59 | } else if tree.left != nil && tree.right != nil { 60 | tree.value = tree.right.getMinValue() 61 | tree.right.remove(value, tree) 62 | } else if parent == nil { 63 | if tree.left != nil { 64 | tree.value = tree.left.value 65 | tree.right = tree.left.right 66 | tree.left = tree.left.left 67 | } else if tree.right != nil { 68 | tree.value = tree.right.value 69 | tree.right = tree.right.right 70 | tree.left = tree.right.left 71 | } else { 72 | tree.value = 0 73 | } 74 | } else if parent.left == tree { 75 | if tree.left != nil { 76 | parent.left = tree.left 77 | } else { 78 | parent.left = tree.right 79 | } 80 | } else if parent.right == tree { 81 | if tree.left != nil { 82 | parent.right = tree.left 83 | } else { 84 | parent.right = tree.right 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /TreesAndGraphs/binarySearchTree/solution.js: -------------------------------------------------------------------------------- 1 | class BST { 2 | constructor(value) { 3 | this.value = value 4 | this.left = null 5 | this.right = null 6 | } 7 | 8 | insert(value) { 9 | if (value >= this.value) { 10 | if (this.right === null) { 11 | this.right = new BST(value) 12 | } else { 13 | this.right.insert(value) 14 | } 15 | } else if (this.left === null) { 16 | this.left = new BST(value) 17 | } else { 18 | this.left.insert(value) 19 | } 20 | return this 21 | } 22 | 23 | contains(value) { 24 | if (value === this.value) { 25 | return true 26 | } else if (value > this.value && this.right) { 27 | return this.right.contains(value) 28 | } else if (value < this.value && this.left) { 29 | return this.left.contains(value) 30 | } else { 31 | return false 32 | } 33 | } 34 | 35 | getMinValue() { 36 | if (this.left === null) { 37 | return this.value 38 | } else { 39 | return this.left.getMinValue() 40 | } 41 | } 42 | 43 | remove(value, parent = null) { 44 | if (value < this.value) { 45 | if (this.left !== null) { 46 | this.left.remove(value, this) 47 | } 48 | } else if (value > this.value) { 49 | if (this.right !== null) { 50 | this.right.remove(value, this) 51 | } 52 | } else if (this.left !== null && this.right !== null) { 53 | this.value = this.right.getMinValue() 54 | this.right.remove(this.value, this) 55 | } else if (parent === null) { 56 | if (this.left !== null) { 57 | this.value = this.left.value 58 | this.right = this.left.right 59 | this.left = this.left.left 60 | } else if (this.right !== null) { 61 | this.value = this.right.value 62 | this.left = this.right.left 63 | this.right = this.right.right 64 | } else { 65 | this.value = null 66 | } 67 | } else if (parent.left === this) { 68 | parent.left = this.left !== null ? this.left : this.right 69 | } else if (parent.right === this) { 70 | parent.right = this.left !== null ? this.left : this.right 71 | } 72 | return this 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /TreesAndGraphs/cloneDirectedGraph/prompt.md: -------------------------------------------------------------------------------- 1 | # Clone a Directed Graph 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given root node of a directed graph, clone this graph by creating its deep copy such that cloned graph has same vertices and edges as original graph. 6 | -------------------------------------------------------------------------------- /TreesAndGraphs/cloneDirectedGraph/solution.js: -------------------------------------------------------------------------------- 1 | class NodeClone { 2 | constructor (data) { 3 | this.data = data 4 | this.neighbors = [] 5 | } 6 | } 7 | 8 | const cloneDirectedGraphRec = (node, visited) => { 9 | if (!node) return null 10 | 11 | // Copy root node and mark as visited 12 | const copy = new NodeClone(node.data) 13 | visited[node.data] = copy 14 | 15 | // Clone each neighbor node as they come 16 | for (let i = 0; i < node.neighbors.length; i++) { 17 | let neighbor = visited[node.neighbors[i].data] 18 | if (!neighbor) { 19 | copy.neighbors.push(cloneDirectedGraphRec(node.neighbors[i], visited)) 20 | } else { 21 | copy.neighbors.push(neighbor) 22 | } 23 | } 24 | 25 | // return root copy 26 | return copy 27 | } 28 | 29 | const cloneDirectedGraph = node => { 30 | const visited = {} 31 | return cloneDirectedGraphRec(node, visited) 32 | } 33 | 34 | module.exports = { cloneDirectedGraph } 35 | -------------------------------------------------------------------------------- /TreesAndGraphs/closestBinarySearchTreeValue/prompt.md: -------------------------------------------------------------------------------- 1 | # Closest Binary Search Tree Value 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given a non-empty binary search tree and a target value, find the value in the BST that is closest to the target. 6 | 7 | ## Note: 8 | 9 | * Given target value is a floating point. 10 | * You are guaranteed to have only one unique value in the BST that is closest to the target. 11 | -------------------------------------------------------------------------------- /TreesAndGraphs/closestBinarySearchTreeValue/solution.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * function TreeNode(val) { 4 | * this.val = val; 5 | * this.left = this.right = null; 6 | * } 7 | */ 8 | /** 9 | * @param {TreeNode} root 10 | * @param {number} target 11 | * @return {number} 12 | */ 13 | const closestValue = function(root, target) { 14 | let closestValue = root.val 15 | while (root != null) { 16 | if (Math.abs(target - root.val) < Math.abs(target - closestValue)) { 17 | closestValue = root.val 18 | } 19 | root = root.val > target ? root.left : root.right 20 | } 21 | return closestValue 22 | } 23 | -------------------------------------------------------------------------------- /TreesAndGraphs/depthFirstSearch/prompt.md: -------------------------------------------------------------------------------- 1 | # Depth First Search 2 | 3 | ## [Solution (JS)](./solution.js) / [Solution (Go)](./solution.go) 4 | 5 | Implement the depthFirstSearch method on the Node class, it takes an empty array, traverses the tree depth-first and returns an array of all of the traversed nodes' names. 6 | -------------------------------------------------------------------------------- /TreesAndGraphs/depthFirstSearch/solution.go: -------------------------------------------------------------------------------- 1 | package program 2 | 3 | type Node struct { 4 | Name string 5 | Children []*Node 6 | } 7 | 8 | func (n *Node) DepthFirstSearch(array []string) []string { 9 | array = append(array, n.Name) 10 | for i := 0; i < len(n.Children); i++ { 11 | array = n.Children[i].DepthFirstSearch(array) 12 | } 13 | return array 14 | } 15 | -------------------------------------------------------------------------------- /TreesAndGraphs/depthFirstSearch/solution.js: -------------------------------------------------------------------------------- 1 | class Node { 2 | constructor(name) { 3 | this.name = name; 4 | this.children = []; 5 | } 6 | 7 | addChild(name) { 8 | this.children.push(new Node(name)); 9 | return this; 10 | } 11 | 12 | depthFirstSearch(array) { 13 | array.push(this.name) 14 | this.children.forEach(child => { 15 | child.depthFirstSearch(array) 16 | }) 17 | return array 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /TreesAndGraphs/evaluateDivision/prompt.md: -------------------------------------------------------------------------------- 1 | # Evaluate Division 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Equations are given in the format A / B = k, where A and B are variables represented as strings, and k is a real number (floating point number). Given some queries, return the answers. If the answer does not exist, return -1.0. 6 | 7 | Example: 8 | 9 | ``` 10 | Given a / b = 2.0, b / c = 3.0. 11 | queries are: a / c = ?, b / a = ?, a / e = ?, a / a = ?, x / x = ? . 12 | return [6.0, 0.5, -1.0, 1.0, -1.0 ]. 13 | ``` 14 | 15 | The shape is: 16 | 17 | ``` 18 | /** 19 | * @param {string[][]} equations 20 | * @param {number[]} values 21 | * @param {string[][]} queries 22 | * @return {number[]} 23 | */ 24 | ``` 25 | 26 | According to the example above: 27 | 28 | ``` 29 | equations = [ ["a", "b"], ["b", "c"] ], 30 | values = [2.0, 3.0], 31 | queries = [ ["a", "c"], ["b", "a"], ["a", "e"], ["a", "a"], ["x", "x"] ]. 32 | ``` 33 | 34 | The input is always valid. You may assume that evaluating the queries will result in no division by zero and there is no contradiction. 35 | -------------------------------------------------------------------------------- /TreesAndGraphs/evaluateDivision/solution.js: -------------------------------------------------------------------------------- 1 | const calcEquation = (equations, values, queries) => { 2 | const output = [] 3 | const graph = buildGraph({ equations, values }) 4 | for (let i = 0; i < queries.length; i++) { 5 | const [numerator, denominator] = queries[i] 6 | 7 | const value = depthFirstSearch({ 8 | graph, 9 | numerator, 10 | denominator, 11 | product: 1, 12 | visited: new Set() 13 | }) 14 | 15 | if (value) { 16 | output.push(value) 17 | //update graph to prevent duplicate calculation 18 | graph.get(numerator).set(denominator, value) 19 | graph.get(denominator).set(numerator, 1 / value) 20 | } else { 21 | output.push(-1) 22 | } 23 | } 24 | return output 25 | } 26 | 27 | const buildGraph = ({ equations, values }) => { 28 | const adjacenyList = new Map() 29 | 30 | for (let i = 0; i < equations.length; i++) { 31 | const [numerator, denominator] = equations[i] 32 | const quotient = values[i] 33 | 34 | if (!adjacenyList[numerator]) { 35 | adjacenyList.set(numerator, new Map()) 36 | } 37 | if (!adjacenyList[denominator]) { 38 | adjacenyList.set(denominator, new Map()) 39 | } 40 | 41 | adjacenyList.get(numerator).set(denominator, quotient) 42 | adjacenyList.get(denominator).set(numerator, 1 / quotient) 43 | } 44 | 45 | return adjacenyList 46 | } 47 | 48 | const depthFirstSearch = ({ 49 | graph, 50 | numerator, 51 | denominator, 52 | product, 53 | visited 54 | }) => { 55 | if (!graph.has(numerator)) return null 56 | if (numerator === denominator) return 1 57 | 58 | // mark current node as visited 59 | visited.add(numerator) 60 | 61 | const neighbors = [...graph.get(numerator).keys()] 62 | 63 | for (let i = 0; i < neighbors.length; i++) { 64 | const nextDenominator = neighbors[i] 65 | const currentProduct = product * graph.get(numerator).get(nextDenominator) 66 | 67 | if (nextDenominator === denominator) { 68 | return currentProduct 69 | } 70 | 71 | if (!visited.has(nextDenominator)) { 72 | const value = depthFirstSearch({ 73 | graph, 74 | numerator: nextDenominator, 75 | denominator, 76 | product: currentProduct, 77 | visited 78 | }) 79 | if (value) { 80 | return value 81 | } 82 | } 83 | 84 | return null 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /TreesAndGraphs/inorderBstSuccessor/prompt.md: -------------------------------------------------------------------------------- 1 | # Inorder Successor in BST 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given a binary search tree and a node in it, find the in-order successor of that node in the BST. 6 | Note: If the given node has no in-order successor in the tree, return null. 7 | 8 | ``` 9 | /** 10 | * Definition for a binary tree node. 11 | * function TreeNode(val) { 12 | * this.val = val; 13 | * this.left = this.right = null; 14 | * } 15 | */ 16 | /** 17 | * @param {TreeNode} root 18 | * @param {TreeNode} p 19 | * @return {TreeNode} 20 | */ 21 | ``` 22 | -------------------------------------------------------------------------------- /TreesAndGraphs/inorderBstSuccessor/solution.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * function TreeNode(val) { 4 | * this.val = val; 5 | * this.left = this.right = null; 6 | * } 7 | */ 8 | /** 9 | * @param {TreeNode} root 10 | * @param {TreeNode} p 11 | * @return {TreeNode} 12 | */ 13 | const inorderSuccessor = (root, p) => { 14 | let successor = null 15 | while (root !== null) { 16 | if (p.val < root.val) { 17 | successor = root 18 | root = root.left 19 | } else { 20 | root = root.right 21 | } 22 | } 23 | return successor 24 | } 25 | -------------------------------------------------------------------------------- /TreesAndGraphs/longestUnivaluePath/prompt.md: -------------------------------------------------------------------------------- 1 | # Longest Univalue Path 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given a binary tree, find the length of the longest path where each node in the path has the same value. This path may or may not pass through the root. 6 | 7 | Note: The length of path between two nodes is represented by the number of edges between them. 8 | 9 | Example 1: 10 | 11 | ``` 12 | Input: 13 | 14 | 5 15 | / \ 16 | 4 5 17 | / \ \ 18 | 1 1 5 19 | Output: 20 | 21 | 2 22 | ``` 23 | 24 | Example 2: 25 | 26 | ``` 27 | Input: 28 | 29 | 1 30 | / \ 31 | 4 5 32 | / \ \ 33 | 4 4 5 34 | Output: 35 | 36 | 2 37 | ``` 38 | 39 | Note: The given binary tree has not more than 10000 nodes. The height of the tree is not more than 1000. 40 | -------------------------------------------------------------------------------- /TreesAndGraphs/longestUnivaluePath/solution.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * function TreeNode(val) { 4 | * this.val = val; 5 | * this.left = this.right = null; 6 | * } 7 | * return number 8 | */ 9 | const longestUnivaluePath = function(root) { 10 | let longestPath = [0] // to maintain reference to longest path when passed in to dfs 11 | if (root !== null) dfs(root, longestPath) 12 | return longestPath[0] 13 | } 14 | 15 | const dfs = (node, longestPath) => { 16 | let leftPathLength = node.left === null ? 0 : dfs(node.left, longestPath) 17 | let rightPathLength = node.right === null ? 0 : dfs(node.right, longestPath) 18 | 19 | let newLeftPathLength = 20 | node.left !== null && node.left.val === node.val ? leftPathLength + 1 : 0 21 | let newRightPathLength = 22 | node.right !== null && node.right.val === node.val ? rightPathLength + 1 : 0 23 | 24 | longestPath[0] = Math.max( 25 | longestPath[0], 26 | newLeftPathLength + newRightPathLength 27 | ) 28 | return Math.max(newLeftPathLength, newRightPathLength) 29 | } 30 | -------------------------------------------------------------------------------- /TreesAndGraphs/numberOfPossibleBinaryTreeTopologies/prompt.md: -------------------------------------------------------------------------------- 1 | # Number of Possible Binary Tree Topologies 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Write a function that takes in a non-negative integer n and that returns the number of possible Binary Tree topologies that can be created with exactly n nodes. A Binary Tree topology is defined as any Binary Tree configuration, irrespective of node values. For instance, there exist only two Binary Tree topologies when n is equal to 2: a root node with a left node, and a root node with a right node. Node that when n is equal to 0, there is one topology that can be created: the None (null) node. 6 | 7 | ``` 8 | Sample Input: 3 9 | Sample Output: 5 10 | ``` 11 | -------------------------------------------------------------------------------- /TreesAndGraphs/numberOfPossibleBinaryTreeTopologies/solution.js: -------------------------------------------------------------------------------- 1 | const numberOfBinaryTreeTopologies = (n, cache = { 0: 1 }) => { 2 | if (n in cache) return cache[n] 3 | let topologies = 0 4 | for (let i = 0; i < n; i++) { 5 | let leftTopologies = numberOfBinaryTreeTopologies(i, cache) 6 | let rightTopologies = numberOfBinaryTreeTopologies(n - i - 1, cache) 7 | topologies += leftTopologies * rightTopologies 8 | } 9 | cache[n] = topologies 10 | return topologies 11 | } 12 | 13 | module.exports = { numberOfBinaryTreeTopologies } 14 | -------------------------------------------------------------------------------- /TreesAndGraphs/numberOfPossibleBinaryTreeTopologies/test.js: -------------------------------------------------------------------------------- 1 | const { numberOfBinaryTreeTopologies } = require('./solution') 2 | 3 | test('numberOfBinaryTreeTopologies #1', () => { 4 | expect(numberOfBinaryTreeTopologies(3)).toEqual(5) 5 | }) 6 | 7 | test('numberOfBinaryTreeTopologies #2', () => { 8 | expect(numberOfBinaryTreeTopologies(5)).toEqual(42) 9 | }) 10 | 11 | test('numberOfBinaryTreeTopologies #3', () => { 12 | expect(numberOfBinaryTreeTopologies(7)).toEqual(429) 13 | }) 14 | 15 | test('numberOfBinaryTreeTopologies #4', () => { 16 | expect(numberOfBinaryTreeTopologies(10)).toEqual(16796) 17 | }) 18 | 19 | test('numberOfBinaryTreeTopologies #5', () => { 20 | expect(numberOfBinaryTreeTopologies(13)).toEqual(742900) 21 | }) 22 | -------------------------------------------------------------------------------- /TreesAndGraphs/riverSizes/prompt.md: -------------------------------------------------------------------------------- 1 | # River Sizes 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | You are given a two-dimensional array (matrix) of potentially unequal height and width containing only 0s and 1s. Each 0 represents land, and each 1 represents part of a river. A river consists of any number of 1s that are either horizontally or vertically adjacent (but not diagonally adjacent). The number of adjacent 1s forming a river determine its size. Write a function that returns an array of the sizes of all rivers represented in the input matrix. Note that these sizes do not need to be in any particular order. 6 | 7 | ### Example 8 | 9 | ``` 10 | Sample Input: 11 | [ 12 | [1, 0, 0, 1, 0], 13 | [1, 0, 1, 0, 0], 14 | [0, 0, 1, 0, 1], 15 | [1, 0, 1, 0, 1], 16 | [1, 0, 1, 1, 0], 17 | ] 18 | 19 | Sample Output: 20 | [1, 2, 2, 2, 5] 21 | ``` 22 | -------------------------------------------------------------------------------- /TreesAndGraphs/riverSizes/solution.js: -------------------------------------------------------------------------------- 1 | const riverSizes = matrix => { 2 | const sizes = [] 3 | const visited = matrix.map(row => row.map(value => false)) 4 | for (let y = 0; y < matrix.length; y++) { 5 | for (let x = 0; x < matrix[y].length; x++) { 6 | if (visited[y][x]) continue 7 | checkRiver(y, x, matrix, visited, sizes) 8 | } 9 | } 10 | return sizes 11 | } 12 | 13 | const checkRiver = (y, x, matrix, visited, sizes) => { 14 | let currentRiverSize = 0 15 | const nodesToExplore = [[y, x]] 16 | while (nodesToExplore.length) { 17 | const [y, x] = nodesToExplore.pop() 18 | if (visited[y][x]) continue 19 | visited[y][x] = true 20 | if (matrix[y][x] === 0) continue 21 | currentRiverSize++ 22 | // push all possible neighbors to stack 23 | getPossibleNeighbors(y, x, matrix, visited, nodesToExplore) 24 | } 25 | if (currentRiverSize > 0) sizes.push(currentRiverSize) 26 | } 27 | 28 | const getPossibleNeighbors = (y, x, matrix, visited, nodesToExplore) => { 29 | if (y > 0) nodesToExplore.push([y - 1, x]) 30 | if (y < matrix.length - 1) nodesToExplore.push([y + 1, x]) 31 | if (x > 0) nodesToExplore.push([y, x - 1]) 32 | if (x < matrix[0].length - 1) nodesToExplore.push([y, x + 1]) 33 | } 34 | 35 | module.exports = { riverSizes } 36 | -------------------------------------------------------------------------------- /TreesAndGraphs/riverSizes/test.js: -------------------------------------------------------------------------------- 1 | const { riverSizes } = require('./solution') 2 | 3 | test('riverSizes(args)', () => { 4 | expect( 5 | riverSizes([ 6 | [1, 0, 0, 1, 0], 7 | [1, 0, 1, 0, 0], 8 | [0, 0, 1, 0, 1], 9 | [1, 0, 1, 0, 1], 10 | [1, 0, 1, 1, 0] 11 | ]).sort((a, b) => a - b) 12 | ).toEqual([1, 2, 2, 2, 5]) 13 | }) 14 | -------------------------------------------------------------------------------- /TreesAndGraphs/validateBst/prompt.md: -------------------------------------------------------------------------------- 1 | # Validate Binary Search Tree 2 | 3 | ## [Solution (JS)](./solution.js) 4 | 5 | Given a binary tree, determine if it is a valid binary search tree (BST). 6 | 7 | Assume a BST is defined as follows: 8 | 9 | * The left subtree of a node contains only nodes with keys less than the node's key. 10 | * The right subtree of a node contains only nodes with keys greater than the node's key. 11 | * Both the left and right subtrees must also be binary search trees. 12 | 13 | ## Example 1: 14 | 15 | ``` 16 | 2 17 | / \ 18 | 1 3 19 | ``` 20 | 21 | Binary tree `[2,1,3]`, return `true`. 22 | 23 | ## Example 2: 24 | 25 | ``` 26 | 1 27 | / \ 28 | 2 3 29 | ``` 30 | 31 | Binary tree `[1,2,3]`, return `false`. 32 | -------------------------------------------------------------------------------- /TreesAndGraphs/validateBst/solution.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Definition for a binary tree node. 3 | * function TreeNode(val) { 4 | * this.val = val; 5 | * this.left = this.right = null; 6 | * } 7 | */ 8 | /* 9 | * @param {TreeNode} root 10 | * @return {boolean} 11 | */ 12 | 13 | const isValidBST = function(root) { 14 | return checkBST(root, -Infinity, Infinity) 15 | } 16 | 17 | const checkBST = (root, minVal, maxVal) => { 18 | if (root === null) return true 19 | if (root.val >= maxVal || root.val <= minVal) return false 20 | return ( 21 | checkBST(root.left, minVal, root.val) && 22 | checkBST(root.right, root.val, maxVal) 23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /_Template/prompt.md: -------------------------------------------------------------------------------- 1 | # Title 2 | 3 | ## [Solution (JS)](./solution.js) 4 | -------------------------------------------------------------------------------- /_Template/solution.js: -------------------------------------------------------------------------------- 1 | module.exports = { something } 2 | -------------------------------------------------------------------------------- /_Template/test.js: -------------------------------------------------------------------------------- 1 | const { func } = require('./solution') 2 | 3 | test('func(args)', () => { 4 | expect(func('args')).toEqual('answer') 5 | }) 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "algorithms", 3 | "version": "1.0.0", 4 | "repository": "git@github.com:alexv/algorithms.git", 5 | "author": "alex@avill.io", 6 | "license": "MIT", 7 | "scripts": { 8 | "test": "jest", 9 | "test-watch": "jest --watch" 10 | }, 11 | "jest": { 12 | "testPathIgnorePatterns": ["/node_modules/", "/_Template/"] 13 | }, 14 | "dependencies": { 15 | "eslint": "^4.19.1", 16 | "jest": "^22.4.3" 17 | }, 18 | "devDependencies": { 19 | "eslint-config-standard": "^11.0.0", 20 | "eslint-plugin-import": "^2.11.0", 21 | "eslint-plugin-node": "^6.0.1", 22 | "eslint-plugin-promise": "^3.7.0", 23 | "eslint-plugin-standard": "^3.0.1" 24 | } 25 | } 26 | --------------------------------------------------------------------------------