├── Recursion ├── factorial_rescursive.js ├── sumrange.js ├── factorial_iterative.js ├── countdown.js ├── callstack_example.js ├── helper_method_recursion.js └── collect_odds_pure_recursion.js ├── Bonus CHALLENGING Recursion Problems ├── reverse.js └── isPalindrome.js ├── Recursion Problem Set ├── product_of_array.js ├── recursive_range.js ├── power.js ├── factorial.js └── recursive_fib.js ├── Problem Solving Patterns ├── Divide and Conquer Pattern │ ├── search.js │ └── search_refactored.js ├── Multiple Pointers Pattern │ ├── unique_values.js │ ├── sum_zero.js │ └── sum_zero_refactored.js ├── Sliding Window Pattern │ ├── max_sum.js │ └── max_sum_refactored.js └── Frequency Counter Pattern │ ├── same_naive_solution2.js │ ├── same_naive_solution.js │ ├── validAnagram.js │ ├── anagram.js │ └── same_refactored_solution.js ├── Searching Algorithms ├── linearSearch.js ├── string_search.js └── binary_search.js ├── Bubble Sort ├── bubblesort_unoptimized.js ├── bubblesort_unoptimizedES2015.js └── bubblesort_optimized.js ├── 100% OPTIONAL Challenges ├── average_pair.js ├── is_subsequence.js ├── same_frequency.js ├── max_subarray_sum.js └── are_there_duplicates.js └── Selection Sort └── selection_sort.js /Recursion/factorial_rescursive.js: -------------------------------------------------------------------------------- 1 | function factorial(num) { 2 | if(num === 1) return 1; 3 | return num * factorial(num - 1); 4 | } -------------------------------------------------------------------------------- /Recursion/sumrange.js: -------------------------------------------------------------------------------- 1 | function sumRange(num){ 2 | if(num === 1) return 1; 3 | return num + sumRange(num-1); 4 | } 5 | 6 | sumRange(4) 7 | -------------------------------------------------------------------------------- /Recursion/factorial_iterative.js: -------------------------------------------------------------------------------- 1 | function factorial(num) { 2 | let total = 1; 3 | 4 | for (let i = num; i > 0; num--) { 5 | total *= num; 6 | } 7 | 8 | return total; 9 | } -------------------------------------------------------------------------------- /Bonus CHALLENGING Recursion Problems/reverse.js: -------------------------------------------------------------------------------- 1 | // Write a recursive function called reverse which accepts a string 2 | // and returns a new string in reverse 3 | 4 | function reverse(str){ 5 | return str.length === 0 ? '' : reverse(str.slice(1)) + str[0]; 6 | } 7 | 8 | // reverse('awesome') // 'emosewa' 9 | // reverse('rithmschool') // 'loohcsmhtir' -------------------------------------------------------------------------------- /Recursion Problem Set/product_of_array.js: -------------------------------------------------------------------------------- 1 | // Write a function called productOfArray which takes in an array of numbers 2 | // and returns the product of them all 3 | 4 | // productOfArray([1,2,3]) // 6 5 | // productOfArray([1,2,3,10]) // 60 6 | 7 | function productOfArray(arr) { 8 | return arr.length === 0 ? 1 : arr[0] * productOfArray(arr.slice(1)); 9 | } -------------------------------------------------------------------------------- /Recursion Problem Set/recursive_range.js: -------------------------------------------------------------------------------- 1 | // Write a function called recursiveRange which accepts a number and 2 | // adds up all the numbers from 0 to the number passed to the function 3 | 4 | // SAMPLE INPUT/OUTPUT 5 | // recursiveRange(6) // 21 6 | // recursiveRange(10) // 55 7 | 8 | function recursiveRange(num){ 9 | return num === 1 ? 1 : num + recursiveRange(--num); 10 | } -------------------------------------------------------------------------------- /Recursion/countdown.js: -------------------------------------------------------------------------------- 1 | // Recursive Version 2 | function countDown(num){ 3 | if(num <= 0) { 4 | console.log("All done!"); 5 | return; 6 | } 7 | console.log(num); 8 | num--; 9 | countDown(num); 10 | } 11 | countDown(3) 12 | 13 | // Iterative Version 14 | function countDown(num){ 15 | for(var i = num; i > 0; i--){ 16 | console.log(i); 17 | } 18 | console.log("All done!") 19 | } -------------------------------------------------------------------------------- /Recursion Problem Set/power.js: -------------------------------------------------------------------------------- 1 | // Write a function called power which accepts a base and an exponent. 2 | // The function should return the power of the base to the exponent. 3 | // This function should mimic the functionality of Math.pow() 4 | // - do not worry about negative bases and exponents 5 | 6 | // power(2,0) // 1 7 | // power(2,2) // 4 8 | // power(2,4) // 16 9 | 10 | function power(base, exponent){ 11 | return exponent === 0 ? 1 : base * power(base, --exponent); 12 | } -------------------------------------------------------------------------------- /Recursion/callstack_example.js: -------------------------------------------------------------------------------- 1 | function takeShower(){ 2 | return "Showering!" 3 | } 4 | 5 | function eatBreakfast(){ 6 | let meal = cookFood() 7 | return `Eating ${meal}` 8 | } 9 | 10 | function cookFood(){ 11 | let items = ["Oatmeal", "Eggs", "Protein Shake"] 12 | return items[Math.floor(Math.random()*items.length)]; 13 | } 14 | function wakeUp() { 15 | takeShower() 16 | eatBreakfast() 17 | console.log("Ok ready to go to work!") 18 | } 19 | 20 | wakeUp(); -------------------------------------------------------------------------------- /Recursion/helper_method_recursion.js: -------------------------------------------------------------------------------- 1 | function collectOddValues(arr) { 2 | let result = []; 3 | 4 | function helper(helperInput) { 5 | if (helperInput.length === 0) { 6 | return; 7 | } 8 | 9 | if (helperInput[0] % 2 !== 0) { 10 | result.push(helperInput[0]); 11 | } 12 | 13 | helper(helperInput.slice(1)); 14 | } 15 | 16 | helper(arr); 17 | 18 | return result; 19 | } 20 | 21 | collectOddValues([1,2,3,4,5,6,7]) -------------------------------------------------------------------------------- /Recursion Problem Set/factorial.js: -------------------------------------------------------------------------------- 1 | // Write a function factorial which accepts a number and returns the factorial 2 | // of that number. A factorial is the product of an integer and all the integers 3 | // bellow it; e.g., factorial four (4!) is equal to 24, because 4 * 3 * 2 * 1 4 | // equals 24. factorial zero (0!) is always 1; 5 | 6 | //factorial(1) // 1 7 | // factorial(2) // 2 8 | // factorial(4) // 24 9 | // factorial(7) // 5040 10 | 11 | function factorial(num){ 12 | return num === 0 ? 1 : num * factorial(--num); 13 | } -------------------------------------------------------------------------------- /Problem Solving Patterns/Divide and Conquer Pattern/search.js: -------------------------------------------------------------------------------- 1 | // Given a sorted array of integers, write a function called search, 2 | // that accepts a value and returns the index where the value passed 3 | // to the function is located. If the values is not found, return -1. 4 | 5 | // Time Complexity O(N) 6 | // -- Linear Search 7 | 8 | function search(arr, val) { 9 | for(let i = 0; i < arr.length; i++) { 10 | if(arr[i] === val) { 11 | return i; 12 | } 13 | } 14 | return -1; 15 | } 16 | 17 | search([1,2,3,4,5,6],44); -------------------------------------------------------------------------------- /Problem Solving Patterns/Multiple Pointers Pattern/unique_values.js: -------------------------------------------------------------------------------- 1 | // Implement a function called countUniqueValues, 2 | // which accepts a sorted array, and counts the 3 | // unique values in the array. There can be negative 4 | // numbers in the array, but it will always be sorted 5 | 6 | function countUniqueValues(arr) { 7 | if(arr.length === 0) return 0; 8 | 9 | let i = 0; 10 | for(let j = 0; j < arr.length; j++) { 11 | if(arr[i] !== arr[j]) { 12 | i++; 13 | arr[i] = arr[j]; 14 | } 15 | } 16 | return i + 1; 17 | } 18 | 19 | countUniqueValues([1,1,2,3,3,4,5,6,6,7]); -------------------------------------------------------------------------------- /Bonus CHALLENGING Recursion Problems/isPalindrome.js: -------------------------------------------------------------------------------- 1 | // Write a recursive function called isPalindrome which returns true if the 2 | // string passed to it is a palindrome. Otherwise it returns false 3 | 4 | // isPalindrome('awesome') // false 5 | // isPalindrome('foobar') // false 6 | // isPalindrome('tacocat') // true 7 | // isPalindrome('amanaplanacanalpanama') // true 8 | // isPalindrome('amanaplanacanalpandemonium') // false 9 | 10 | function isPalindrome(str){ 11 | const reverse = (s) => s.length === 0 ? '' : reverse(s.slice(1)) + s[0]; 12 | let reversed = reverse(str); 13 | return reversed === str; 14 | } 15 | 16 | isPalindrome('tacocat'); -------------------------------------------------------------------------------- /Recursion/collect_odds_pure_recursion.js: -------------------------------------------------------------------------------- 1 | function collectOddValues(arr) { 2 | let newArr = []; 3 | 4 | if (arr.length === 0) { 5 | return newArr; 6 | } 7 | 8 | // if the first num of the array is odd, add it to newArr 9 | if (arr[0] % 2 !== 0) { 10 | newArr.push(arr[0]); 11 | } 12 | 13 | // assign newArray to equal the concatenation of all the rest of 14 | // the results provided by collectOddValues(arr.slice(1)) 15 | newArr = newArr.concat(collectOddValues(arr.slice(1))); 16 | 17 | console.log('arr:',arr); 18 | 19 | return newArr; 20 | } 21 | 22 | collectOddValues([1,2,4,65,8,9,4,25,17,76]); -------------------------------------------------------------------------------- /Problem Solving Patterns/Sliding Window Pattern/max_sum.js: -------------------------------------------------------------------------------- 1 | // Write a function called maxSubarraySum which accepts 2 | // an array of integers and a number called n. The function 3 | // should calculate the maximum sum of n consecutive 4 | // elements in the array 5 | 6 | function maxSubarraySum(arr, num) { 7 | if(num > arr.length) return null; 8 | 9 | let max = -Infinity; 10 | for (let i = 0; i < arr.length - num + 1; i++) { 11 | temp = 0; 12 | for (let j = 0; j < num; j++) { 13 | temp += arr[i + j]; 14 | } 15 | if(temp > max) { 16 | max = temp; 17 | } 18 | } 19 | return max; 20 | } 21 | 22 | maxSubarraySum([1,2,5,2,8,1,5],2); -------------------------------------------------------------------------------- /Problem Solving Patterns/Multiple Pointers Pattern/sum_zero.js: -------------------------------------------------------------------------------- 1 | // Write a function called sumZero which accepts a sorted 2 | // array of integers. The function should find the first pair 3 | // where the sum is 0. Return an array that includes both 4 | // values that sum to zero or undefined if a pair does not exist 5 | 6 | 7 | function sumZero(arr) { 8 | for(let i = 0; i < arr.length; i++) { 9 | for(let j = 1; j < arr.length; j++) { 10 | if(arr[i] + arr[j] === 0) { 11 | return [arr[i], arr[j]]; 12 | } 13 | } 14 | } 15 | } 16 | 17 | sumZero([-3,-2,-1,0,1,2,3]) // returns [-3,3] 18 | sumZero([-2,0,1,3]) // returns undefined 19 | sumZero([1,2,3]) // returns undefined -------------------------------------------------------------------------------- /Problem Solving Patterns/Frequency Counter Pattern/same_naive_solution2.js: -------------------------------------------------------------------------------- 1 | // Write a function called same, which accepts two arrays. 2 | // The function should return true if every value in the 3 | // array has it's corresponding value squared in the second array 4 | // The frequency of values must be the same. 5 | 6 | 7 | function same(arr1, arr2) { 8 | // Colt Steele's solution 9 | if(arr1.length !== arr2.length) return false; 10 | for(let i = 0; i < arr1.length; i++) { 11 | let correctIndex = arr2.indexOf(arr1[i] ** 2); // what is the index of num squared 12 | if(correctIndex === -1) return false; 13 | arr2.splice(correctIndex, 1); // remove num from arr2 14 | } 15 | return true; 16 | } 17 | 18 | same([3,6,5,2,8], [25,9,36,64,4]); -------------------------------------------------------------------------------- /Problem Solving Patterns/Frequency Counter Pattern/same_naive_solution.js: -------------------------------------------------------------------------------- 1 | // Write a function called same, which accepts two arrays. 2 | // The function should return true if every value in the 3 | // array has it's corresponding value squared in the second array 4 | // The frequency of values must be the same. 5 | 6 | 7 | function same(arr1, arr2) { 8 | // My solution 9 | if(arr1.length !== arr2.length) return false; 10 | 11 | arr1 = arr1.sort((a,b) => a - b); 12 | arr2 = arr2.sort((a,b) => a - b); 13 | 14 | console.log('arr1:', arr1, 'arr2:', arr2); 15 | 16 | for(let i = 0; i < arr1.length; i++) { 17 | if(arr1[i] ** 2 !== arr2[i]) { 18 | return false; 19 | } 20 | } 21 | return true; 22 | } 23 | 24 | same([3,6,5,2,8], [25,9,36,64,4]); -------------------------------------------------------------------------------- /Searching Algorithms/linearSearch.js: -------------------------------------------------------------------------------- 1 | /*** Linear Search ***/ 2 | 3 | // Write a function called linearSearch which accepts an array 4 | // and a value, and returns the index at which the value exists 5 | // If the value does not exist in the array, return -1 6 | 7 | // Examples: 8 | // linearSearch([10, 15, 20, 25, 30], 15) // 1 9 | // linearSearch([9, 8, 7, 6, 5, 4, 3, 2, 1, 0], 4) // 5 10 | // linearSearch([100], 100) // 0 11 | // linearSearch([1, 2, 3, 4, 5], 6) // -1 12 | // linearSearch([9, 8, 7, 6, 5, 4, 3, 2, 1, 0], 10) // -1 13 | // linearSearch([100], 200) // -1 14 | 15 | function linearSearch(arr, val) { 16 | for (let i = 0; i < arr.lenght; i++) { 17 | if (arr[i] === val) return i; 18 | } 19 | return - 1; 20 | } 21 | 22 | linearSearch([9, 8, 7, 6, 5, 4, 3, 2, 1, 0], 4) -------------------------------------------------------------------------------- /Bubble Sort/bubblesort_unoptimized.js: -------------------------------------------------------------------------------- 1 | // Bubble Sort Pseudocode 2 | 3 | // * Start looping from a variable called i the end of the array towards the beginning 4 | // * Start an inner loop with a variable called j from the beginning until i - 1 5 | // * If arr[j] is greater than arr[j+1], swap those two values 6 | // * Return the array 7 | 8 | function bubbleSort(arr) { 9 | for (let i = arr.length; i > 0; i--) { 10 | for (let j = 0; j < i - 1; j++) { 11 | console.log(arr, arr[j], arr[j+1]); 12 | if (arr[j] > arr[j+1]) { 13 | //SWAP 14 | var temp = arr[j]; 15 | arr[j] = arr[j+1]; 16 | arr[j+1] = temp; 17 | } 18 | } 19 | console.log("ONE PASS COMPLETE!"); 20 | } 21 | 22 | return arr; 23 | } 24 | 25 | bubbleSort([37, 45, 29, 8, 12, 88, -3]); -------------------------------------------------------------------------------- /Bubble Sort/bubblesort_unoptimizedES2015.js: -------------------------------------------------------------------------------- 1 | // Bubble Sort Pseudocode 2 | 3 | // * Start looping from a variable called i the end of the array towards the beginning 4 | // * Start an inner loop with a variable called j from the beginning until i - 1 5 | // * If arr[j] is greater than arr[j+1], swap those two values 6 | // * Return the array 7 | 8 | function bubbleSort(arr) { 9 | const swap = (arr, idx1, idx2) => { 10 | [arr[idx1], arr[idx2]] = [arr[idx2], arr[idx1]]; 11 | } 12 | 13 | for (let i = arr.length; i > 0; i--) { 14 | for (let j = 0; j < i - 1; j++) { 15 | console.log(arr, arr[j], arr[j+1]); 16 | if (arr[j] > arr[j+1]) { 17 | swap(arr, j, j+1); 18 | } 19 | } 20 | console.log("ONE PASS COMPLETE!"); 21 | } 22 | 23 | return arr; 24 | } 25 | 26 | bubbleSort([37, 45, 29, 8, 12, 88, -3]); -------------------------------------------------------------------------------- /Recursion Problem Set/recursive_fib.js: -------------------------------------------------------------------------------- 1 | // Write a recursive function called fib which accepts a number and returns the 2 | // nth number in the Fibonacci sequence. Recall that the Fibonacci sequence is 3 | // the sequence of whole numbers 1,1,2,3,5,8, ... which starts with 1 and 1, and 4 | // where every number thereafter is equal to the sum of the previous two numbers 5 | 6 | 7 | // fib(4) // 3 8 | // fib(10) // 55 9 | // fib(28) // 317811 10 | // fib(35) // 9227465 11 | 12 | // function fib(num){ 13 | // var i; 14 | // var fib = [0,1]; // Initialize array! 15 | 16 | 17 | // for (i = 2; i <= num; i++) { 18 | // // Next fibonacci number = previous + one before previous 19 | // fib[i] = fib[i - 2] + fib[i - 1]; 20 | // } 21 | // return fib[fib.length-1]; 22 | // } 23 | 24 | function fib(num){ 25 | return num <= 2 ? 1 : fib(num - 2) + fib(num - 1); 26 | } 27 | -------------------------------------------------------------------------------- /Problem Solving Patterns/Divide and Conquer Pattern/search_refactored.js: -------------------------------------------------------------------------------- 1 | // Given a sorted array of integers, write a function called search, 2 | // that accepts a value and returns the index where the value passed 3 | // to the function is located. If the values is not found, return -1. 4 | 5 | // Time Complexity Log(N) 6 | // -- Binary Search 7 | 8 | function search(array, val) { 9 | let min = 0; 10 | let max = array.length - 1; 11 | 12 | while (min <= max) { 13 | let middle = Math.floor((min + max) / 2); 14 | let currEl = array[middle]; 15 | 16 | if(currEl < val) { 17 | min = middle + 1; 18 | } 19 | else if (currEl > val) { 20 | max = middle - 1; 21 | } 22 | else { 23 | return middle; 24 | } 25 | } 26 | 27 | return -1; 28 | } 29 | 30 | search([1,2,3,6,7,9,11,15,22,24,27,29,31,33,36,40,41,43,44,52],31); -------------------------------------------------------------------------------- /Bubble Sort/bubblesort_optimized.js: -------------------------------------------------------------------------------- 1 | /*** Bubble Sort Optimized ***/ 2 | 3 | // Bubble Sort Pseudocode 4 | // * Start looping from a variable called i the end of the array towards the beginning 5 | // * Start an inner loop with a variable called j from the beginning until i - 1 6 | // * If arr[j] is greater than arr[j+1], swap those two values 7 | // * Return the array 8 | 9 | function bubbleSort(arr) { 10 | let noSwaps; 11 | for (let i = arr.length; i > 0; i--) { 12 | noSwaps = true; 13 | for (let j = 0; j < i - 1; j++) { 14 | console.log(arr, arr[j], arr[j+1]); 15 | if (arr[j] > arr[j+1]) { 16 | [arr[j], arr[j+1]] = [arr[j+1], arr[j]]; 17 | noSwaps = false; 18 | } 19 | } 20 | if (noSwaps) break; 21 | console.log("ONE PASS COMPLETE!"); 22 | } 23 | 24 | return arr; 25 | } 26 | 27 | bubbleSort([8, 1, 2, 3, 4, 5, 6, 7]); -------------------------------------------------------------------------------- /Problem Solving Patterns/Sliding Window Pattern/max_sum_refactored.js: -------------------------------------------------------------------------------- 1 | /*** SLIDING WINDOW PATTERN ***/ 2 | 3 | // This pattern involves creating a window which can either be an array 4 | // or number from one position to another. Depending on a certain condition, 5 | // the window either increases or closes (and a new window is created). 6 | // Very useful for keeping track of a subset of data in an array/string etc. 7 | 8 | 9 | function maxSubarraySum(arr, num) { 10 | if (arr.length < num) return null; 11 | 12 | let maxSum = 0; 13 | let tempSum = 0; 14 | for (let i = 0; i < num; i++) { 15 | maxSum += arr[i]; 16 | } 17 | 18 | tempSum = maxSum; 19 | for (let i = num; i < arr.length; i++) { 20 | tempSum = tempSum - arr[i - num] + arr[i]; 21 | maxSum = Math.max(maxSum, tempSum); 22 | } 23 | 24 | return maxSum; 25 | } 26 | 27 | maxSubarraySum([2,6,9,2,1,8,5,6,3],3); -------------------------------------------------------------------------------- /100% OPTIONAL Challenges/average_pair.js: -------------------------------------------------------------------------------- 1 | /*** Multiple Pointers - averagePair ***/ 2 | 3 | // Write a function called averagePair. Given a sorted array of integers and a target average, 4 | // determine if there is a pair of values in the array where the average of the pair equals the 5 | // target average. There may be more than one pair that matches the average 6 | 7 | // Bonus Contrains: 8 | // Time: O(N) 9 | // Space: O(1) 10 | // Sample Input: 11 | // averagePair([1,2,3], 2.5); // true 12 | // averagePair([1,3,3,5,6,7,10,12,19], 8); // true 13 | // averagePair([-1,0,3,4,5,6], 4.1); // false 14 | // averagePair([], 4); // false 15 | 16 | function averagePair(arr, num){ 17 | let start = 0; 18 | let end = arr.length - 1; 19 | 20 | while(start < end) { 21 | if (arr[start] + arr[end] / 2 === num) return true; 22 | start++; 23 | end--; 24 | } 25 | return false; 26 | } 27 | 28 | -------------------------------------------------------------------------------- /Problem Solving Patterns/Multiple Pointers Pattern/sum_zero_refactored.js: -------------------------------------------------------------------------------- 1 | // Write a function called sumZero which accepts a sorted 2 | // array of integers. The function should find the first pair 3 | // where the sum is 0. Return an array that includes both 4 | // values that sum to zero or undefined if a pair does not exist 5 | 6 | // Time Complexity - O(N) 7 | // Space Complexity - O(1) 8 | 9 | function sumZero(arr) { 10 | let left = 0; 11 | let right = arr.length - 1; 12 | while(left < right) { 13 | let sum = arr[left] + arr[right]; 14 | console.log('left:', arr[left], 'right:', arr[right]); 15 | 16 | if(sum === 0) { 17 | console.log('sum:', sum); 18 | return [arr[left], arr[right]]; 19 | } else if(sum > 0) { 20 | right--; 21 | } else { 22 | left++; 23 | } 24 | console.log('sum:', sum); 25 | } 26 | } 27 | 28 | sumZero([-4,-3,-2,-1,0,5,10]) // returns undefined 29 | -------------------------------------------------------------------------------- /Searching Algorithms/string_search.js: -------------------------------------------------------------------------------- 1 | /*** String Search ***/ 2 | 3 | // Pseudocode 4 | // * Loop over the longer string 5 | // * Loop over the shorter string 6 | // * If the characters don't match, break out of the inner loop 7 | // * If the characters do match, keep going 8 | // * If you complete the inner loop and find a match, increment the count of matches 9 | // * Return the count 10 | 11 | function stringSearch(s1,s2) { 12 | count = 0; 13 | for (let i = 0; i < s1.length; i++) { 14 | for (let j = 0; j < s2.length; j++) { 15 | // console.log(s2[j], s1[i+j]) 16 | if (s1[i+j] !== s2[j]) { 17 | // console.log('BREAK!'); 18 | break; 19 | } 20 | if (j === s2.length - 1) { 21 | // console.log('FOUND ONE!'); 22 | count++; 23 | continue; 24 | } 25 | } 26 | } 27 | return count < 2 ? `Found ${count} match` : `Found ${count} matches`; 28 | } 29 | 30 | stringSearch('lorie loled', 'lol'); -------------------------------------------------------------------------------- /100% OPTIONAL Challenges/is_subsequence.js: -------------------------------------------------------------------------------- 1 | /*** Multiple Pointers - isSubsequence ***/ 2 | 3 | // Write a function called isSubsequence which takes in two strings and checks whether 4 | // the characters in the first string form a subsequence of the characters in the second 5 | // string. In other words, the function should check whether the characters in the first 6 | // string appear somewhere in the second string, without their order changing. 7 | 8 | // Examples: 9 | // 1 isSubsequence('hello', 'by hecatl in lo world') 10 | // 2 isSubsequence('sing', 'sting') 11 | // 3 isSubsequence('abc', 'abracadabra') 12 | // 4 isSubsequence('abc', 'acb') 13 | 14 | // Your solution MUST have AT LEAST the following complexities: 15 | // Time Complexity - O(N + M) 16 | // Space Complexity - O(1) 17 | 18 | function isSubsequence(str1,str2) { 19 | let i = 0; 20 | 21 | for (let j = 0; j < str2.length; j++) { 22 | if (str1[i] === str2[j]) i++; 23 | if (i === str1.length) return true; 24 | } 25 | 26 | return false; 27 | } -------------------------------------------------------------------------------- /Selection Sort/selection_sort.js: -------------------------------------------------------------------------------- 1 | /*** Selection Sort ***/ 2 | 3 | // PSEUDOCODE 4 | // * Store the first element as the smallest value you've seen so far. 5 | // * Compare this item to the next item in the array until you find a smaller number. 6 | // * If a smaller number is found, designate that smaller number to be 7 | // the new "minimum" and continue until the end of the array. 8 | // * If the "minimum" is not the value(index) you initially began with, 9 | // swap the two values 10 | // * Repeat this with the next element until the array is sorted. 11 | 12 | function selectionSort(arr) { 13 | for (let i = 0; i < arr.length; i++) { 14 | let min = i; 15 | for (let j = i+1; j < arr.length; j++) { 16 | if (arr[j] < arr[min]) { 17 | min = j; 18 | } 19 | } 20 | if (i !== min) { 21 | // console.log(arr[i], arr[min]); 22 | // console.log(arr); 23 | [arr[i], arr[min]] = [arr[min], arr[i]]; 24 | } 25 | } 26 | 27 | return arr; 28 | } 29 | 30 | 31 | selectionSort([0,2,34,22,10,19,17]) -------------------------------------------------------------------------------- /100% OPTIONAL Challenges/same_frequency.js: -------------------------------------------------------------------------------- 1 | /*** Frequency Counter ***/ 2 | 3 | // Write a function called sameFrequency 4 | // Given two positive integers, find out if the two 5 | // numbers have the same frequency of digits. 6 | 7 | // Your solution MUST have the following complexities: 8 | // Time: O(N) 9 | 10 | // sameFrequency(182, 281) // true 11 | // sameFrequency(34, 14) // false 12 | // sameFrequency(3589578, 5879385) // true 13 | // sameFrequency(22, 222) // false 14 | 15 | function sameFrequency(num1, num2){ 16 | num1 = num1.toString(); 17 | num2 = num2.toString(); 18 | 19 | if(num1.length !== num2.length) return false; 20 | 21 | let freqCount1 = {}, 22 | freqCount2 = {}; 23 | 24 | for(let val of num1) { 25 | freqCount1[val] = (freqCount1[val] || 0) + 1; 26 | } 27 | for(let val of num2) { 28 | freqCount2[val] = (freqCount2[val] || 0) + 1; 29 | } 30 | 31 | for(let key in freqCount1) { 32 | if(freqCount1[key] !== freqCount2[key]) { 33 | return false; 34 | } 35 | } 36 | 37 | return true; 38 | } -------------------------------------------------------------------------------- /Problem Solving Patterns/Frequency Counter Pattern/validAnagram.js: -------------------------------------------------------------------------------- 1 | /*** Frequency Counter: Anagram Challenge ***/ 2 | 3 | // Given two strings, write a function to determine if the 4 | // second string is an anagram of the first. An anagram is 5 | // a word, phrase, or name formed by rearranging the letters 6 | // of another, such as 'cinema', formed from 'iceman'. 7 | 8 | /*************************/ 9 | /*** MY SOLUTION ***/ 10 | /*************************/ 11 | function validAnagram(str1, str2) { 12 | if(str1.length !== str2.length) return false; 13 | 14 | let freqCount1 = {}, 15 | freqCount2 = {}; 16 | 17 | for(let val of str1) { 18 | freqCount1[val] = (freqCount1[val] || 0) + 1; 19 | } 20 | for(let val of str2) { 21 | freqCount2[val] = (freqCount2[val] || 0) + 1; 22 | } 23 | 24 | for(let key in freqCount1) { 25 | if(freqCount1[key] !== freqCount2[key]) { 26 | return false; 27 | } 28 | } 29 | console.log('freqCount1:', freqCount1); 30 | console.log('freqCount2:', freqCount2); 31 | 32 | return true; 33 | } 34 | 35 | validAnagram('texttwisttime', 'timetwisttext'); -------------------------------------------------------------------------------- /100% OPTIONAL Challenges/max_subarray_sum.js: -------------------------------------------------------------------------------- 1 | /*** Sliding Window - maxSubarraySum ***/ 2 | 3 | // Given an array of integers and a number, write a function called maxSubArraySum, 4 | // which finds the maximum sum of a subarray with the length of the number passed 5 | // to the function. Note that a subarray consist of consecutive elements from the 6 | // original array. In the first example below, [100, 200, 300] is a subarray of the 7 | // original array, but [100,300] is not. 8 | 9 | // maxSubarraySum([100,200,300,400], 2) // 700 10 | // maxSubarraySum([1,4,2,10,23,3,1,0,20], 4) // 39 11 | // maxSubarraySum([-3,4,0,-2,6,-1], 2) // 5 12 | // maxSubarraySum([3,-2,7,-4,1,-1,4,-2,1], 2) // 5 13 | // maxSubarraySum([2,3], num) // null 14 | 15 | // Constraints: 16 | // Time Complexity - O(N) 17 | // Space Complexity - O(1) 18 | 19 | function maxSubarraySum(arr, num) { 20 | let maxSum = 0; 21 | let tempSum = 0; 22 | if(num > arr.length) return null; 23 | 24 | for (let i = 0; i < num; i++) { 25 | maxSum += arr[i]; 26 | } 27 | tempSum = maxSum; 28 | for (let i = num; i < arr.length; i++) { 29 | tempSum = tempSum - arr[i - num] + arr[i]; 30 | maxSum = Math.max(maxSum, tempSum); 31 | } 32 | 33 | return maxSum; 34 | } -------------------------------------------------------------------------------- /Problem Solving Patterns/Frequency Counter Pattern/anagram.js: -------------------------------------------------------------------------------- 1 | /*** Frequency Counter: Anagram Challenge ***/ 2 | 3 | // Given two strings, write a function to determine if the 4 | // second string is an anagram of the first. An anagram is 5 | // a word, phrase, or name formed by rearranging the letters 6 | // of another, such as 'cinema', formed from 'iceman'. 7 | 8 | /************************************/ 9 | /*** COLT STEELE'S SOLUTION ***/ 10 | /************************************/ 11 | 12 | function validAnagram(first, second) { 13 | if (first.length !== second.length) { 14 | return false; 15 | } 16 | 17 | const lookup = {}; 18 | 19 | for (let i = 0; i < first.length; i++) { 20 | let letter = first[i]; 21 | // if letter exists, increment, otherwise set to 1 22 | lookup[letter] ? lookup[letter] += 1 : lookup[letter] = 1; 23 | } 24 | console.log(lookup) 25 | 26 | for (let i = 0; i < second.length; i++) { 27 | let letter = second[i]; 28 | // can't find letter or letter is zero then it's not an anagram 29 | if (!lookup[letter]) { 30 | return false; 31 | } else { 32 | lookup[letter] -= 1; 33 | } 34 | } 35 | 36 | return true; 37 | } 38 | 39 | // {a: 0, n: 0, g: 0, r: 0, m: 0,s:1} 40 | validAnagram('anagrams', 'nagaramm') -------------------------------------------------------------------------------- /Searching Algorithms/binary_search.js: -------------------------------------------------------------------------------- 1 | /*** Binary Search ***/ 2 | 3 | // Write a function called binarySearch which accepts a sorted array and a value 4 | // and returns the index at which the value exists. Otherwise return -1. 5 | 6 | /* Pseudocode */ 7 | // * Create a left pointer at the start of the array, and a right pointer at the end of the array. 8 | // * While the left pointer comes before the right pointer: 9 | // * Create a pointer in the middle 10 | // * If you find the value you want, return the index 11 | // * If the value is too small, move the left pointer up 12 | // * If the value is too large, move the right pointer down 13 | // * If you never find the value, return -1 14 | 15 | // Examples: 16 | // binarySearch([1,2,3,4,5], 2) // 1 17 | // binarySearch([1,2,3,4,5], 5) // 4 18 | // binarySearch([5,6,10,13,14,18,30,34,35,37,40,44,64,79,84,86,95,96,98,99], 10) // 2 19 | // binarySearch([5,6,10,13,14,18,30,34,35,37,40,44,64,79,84,86,95,96,98,99], 95) // 16 20 | // binarySearch([5,6,10,13,14,18,30,34,35,37,40,44,64,79,84,86,95,96,98,99], 100) // -1 21 | 22 | 23 | function binarySearch(arr, val) { 24 | let start = 0; 25 | let end = arr.length - 1; 26 | 27 | while (start <= end) { 28 | let middleIndex = Math.floor((start + end) / 2); 29 | let middleEl = arr[middleIndex]; 30 | 31 | if (middleEl === val) return middleIndex; 32 | if(middleEl < val) start = ++middleIndex; 33 | if (middleEl > val) end = --middleIndex; 34 | } 35 | 36 | return -1; 37 | } -------------------------------------------------------------------------------- /100% OPTIONAL Challenges/are_there_duplicates.js: -------------------------------------------------------------------------------- 1 | /*** Coding Exercise 4: Frequency Counter / Multiple Pointers - areThereDuplicates ***/ 2 | 3 | // Implement a function called, areThereDuplicates which accepts a 4 | // variable number of arguments, and checks whether there are any 5 | // duplicates among the arguments passed in. You can solve this using 6 | // the frequency counter pattern OR the multiple pointers pattern. 7 | 8 | // areThereDuplicates(1, 2, 3) // false 9 | // areThereDuplicates(1, 2, 2) // true 10 | // areThereDuplicates('a', 'b', 'c', 'a') // false 11 | 12 | // Restrictions: 13 | // Time - O(N) 14 | // Space - O(N) 15 | // Bonus: 16 | // Time - O(N LOG N) 17 | // Space - O(1) 18 | 19 | 20 | // Using Frequency Counter Pattern 21 | function areThereDuplicates(...args) { 22 | let obj = {}; 23 | 24 | for (let val of args) { 25 | obj[val] = (obj[val] || 0) + 1; 26 | } 27 | 28 | for(let key in obj) { 29 | if(obj[key] !== 1) return true; 30 | } 31 | 32 | return false; 33 | } 34 | 35 | 36 | // Using Multiple Pointers Pattern 37 | function areThereDuplicates(...args) { 38 | // Two pointers 39 | args.sort((a,b) => a - b); 40 | let start = 0; 41 | let next = 1; 42 | 43 | while(next < args.length) { 44 | if(args[start] === args[next]) { 45 | return true; 46 | } 47 | start++; 48 | next++ 49 | } 50 | 51 | return false; 52 | } 53 | 54 | // Using Set 55 | function areThereDuplicates() { 56 | return new Set(arguments).size !== arguments.length; 57 | } -------------------------------------------------------------------------------- /Problem Solving Patterns/Frequency Counter Pattern/same_refactored_solution.js: -------------------------------------------------------------------------------- 1 | // Write a function called same, which accepts two arrays. 2 | // The function should return true if every value in the 3 | // array has it's corresponding value squared in the second array 4 | // The frequency of values must be the same. 5 | 6 | /*** REFACTORED ***/ 7 | function same(arr1, arr2) { 8 | if(arr1.length !== arr2.length) return false; 9 | 10 | // Each object is going to count the frequency of individual values in the arrays 11 | let frequencyCounter1 = {}; 12 | let frequencyCounter2 = {}; 13 | 14 | // Loop over every value in the array and count the number of times the value appears in the array 15 | for(let val of arr1) { 16 | frequencyCounter1[val] = (frequencyCounter1[val] || 0) + 1; 17 | } 18 | for(let val of arr2) { 19 | frequencyCounter2[val] = (frequencyCounter2[val] || 0) + 1; 20 | } 21 | 22 | // Loop over the first array, look at each key and check if the key squared... 23 | // can be found in frequencyCounter2; then check if the values correspond 24 | for(let key in frequencyCounter1) { 25 | if(!(key ** 2 in frequencyCounter2)) { 26 | return false; 27 | } 28 | // console.log(frequencyCounter1[key]); 29 | if(frequencyCounter2[key ** 2] !== frequencyCounter1[key]) { 30 | return false; 31 | } 32 | } 33 | console.log('frequencyCounter1:', frequencyCounter1); 34 | console.log('frequencyCounter2:', frequencyCounter2); 35 | return true; 36 | } 37 | 38 | same([3,6,5,2,8,5], [25,9,36,64,4,25]); --------------------------------------------------------------------------------