Study Guide 2023+

algorithms

Warning: These notes are partial, ongoing, incomplete, and may contain typos/inaccuracies. (They are kept factually accurate, time permitting.)

They are being united from many disparate notes created in the past and the layout/organization will gradually improve with time!

Please view them on a computer as they are not optimized for mobile (although you can still view them on Mobile along with the Flashcards at your own risk)!

Topics and code examples are lazy-loaded and may require two-clicks from the TOC to correctly calculate the updated x,y coordinates (after rendering). Thanks!

Algorithms: Big O Notation

Time Complexity

  1. Specifies the relationship between the number of operations performed across different Input Sizes for a Function. (Which in turn impacts the total amount of time a Function may take to run to completion.)
    • It's convenient to think of Time Complexity as successively running a Function with increasing or decreasing Input Sizes.
    • In practice, most computers run so quickly that there's no discernible difference in the amount of time to any kind of Function for small Input Sizes.
    • Time Complexity (e.g. Asymptotic Analysis) instead is concerned with the abstract mathematical relationships between a Function, its Control Flow, the number of operations it performs, the Input Size, and its Computability.
  2. By convention, Average Big O Time Complexity almost always indicates the worst-case time complexity.
    • It's also standard practice to drop multiples e.g. - O(2n) is usually just written as O(n).
  3. Time Complexity is almost always measured using Big O Notation.

Big O Notation

Given an input n, calculate, a priori, abstracting away certain physical implementation specifics, the time it takes to execute an algorithm relative to n. By convention, Big O Notation typically measures only the worst-case time complexity (upper bound).

Formal Definition

The best formal definition I’ve found:

  1. Where f, g are functions from N to the positive reals, R+; and
  2. Where O(g) is a set of functions from N to the positive reals, R+; and
  3. Where stands for the elemental inclusion operator:
    • f ∈ O(g) means: asymptotically and ignoring constant factors, f does not grow more quickly than g over time or input size.
    • f ∈ O(g) means: asymptotically and ignoring constant factors, g is the worst-case time complexity for f over time or input size.

Refer to: http://www.uni-forst.gwdg.de/~wkurth/cb/html/cs1_v06.pdf

Constant Time

Invariant, constant or unchanging, Time-Complexity. The number of operations performed remains constant and does not depend on the Input Size:

Linear Time

Time-Complexity is Directly Proportional to (the number of Inputs) n:

Logarithmic Time

The Time Complexity Logarithmically (gradually and varyingly) decreases (or increases) relative to change in Input Size, Not Constant, Linear, or Exponential.

Logarithms and Logarithmic Functions

  1. log specifies how much, n, the Base, β is raised to in order to obtain some x (e.g. - finds the Exponent given βⁿ = x):

    • logᵦ(x) = n if and only if (βⁿ = x)
    • (log baseᵦ x = n) if and only if (βⁿ = x)
    • E.g. - (log base₂ 64 = 6) if and only if (2⁶ = 64)
    • E.g. - (log₂ 64 = 6) if and only if (2⁶ = 64)
  2. log(x) = y is written as shorthand for an assumed or suppressed Base β:

    • E.g. - when using Base 10 log₁₀(x) = y .
    • When using Big O Notation, the assumed Base is usually taken to be Base 2 (Binary, base₂, 2, or log₂(x) = y).

https://en.wikipedia.org/wiki/Logarithm and notes on logarithms

Quadratic Time

Time-Complexity increases Exponentially with respect to (the number of inputs) n.

Calculations

Big O calculations can be combined:

Ambiguity and Equivocation

There are at least three equivocations that are commonly encountered regarding the above:

  1. Imprecision in computing exact Time Complexity. For example:
    • A Function may be bounded by a range of Input Sizes so that the result is actually Constant (for that range of Input Sizes) but will nevertheless be treated as some other kind of Time Complexity (or vice-versa, that a Function may be more properly classified by some other label but will be considered say Constant). Consider if the Logarithmic Function example above were bounded to Input Sizes 4:6).
    • For many Functions and Input Sizes, some XN = N^Y. Functions with that property may nevertheless be described by different Big O Time Complexities.
    • It's standard convention to omit Big O Notation multiples: O(2n) is usually just written as O(n).
  2. Quasilinear Time, Sublinear Time, and the like are usually ignored (and Big O Notation is essentially "rounded" to one of the four categories described above).
  3. "Inner" and "Outer" Time Complexity are often equivocated:
    • "Inner" - an Input is passed as a Parameter or Argument to a Function. Many Functions will alter this Value (in-place, for example). Some such Values are modified within a Function, each loop through a Function has a certain number of operations to be performed, a Function is a set of Functions, etc.
    • "Outer" - consideration of a Function's Time Complexity by comparison of different Input Sizes to their total number of operations (per the above).
  1. https://en.wikipedia.org/wiki/Logarithm
  2. https://www.thoughtscript.io/algos/0000000000003
  3. http://www.uni-forst.gwdg.de/~wkurth/cb/html/cs1_v06.pdf
  4. https://en.wikipedia.org/wiki/Time_complexity

Algorithms: Space Complexity

There’s a lot more ambiguity and disagreement about what constitutes what with respect to Space Complexity: https://www.studytonight.com/data-structures/space-complexity-of-algorithms observes that:

“Sometimes Auxiliary Space is confused with Space Complexity. But Auxiliary Space is the extra space or the temporary space used by the algorithm during it's execution.”

Furthermore, small Input Sizes are often just called O(1) (despite being strictly Linear): https://stackoverflow.com/questions/44430974/space-complexity-of-an-array.

Big O Notation

Is similar to Big O Notation for Time Complexity.

Algorithms: Famous Algorithms

Minimum Spanning Tree

Kruskal’s Algorithm

Prim’s Algorithm

Dijkstra's Algorithm

Heap’s Algorithm

// Heap's Algorithm
// https://stackoverflow.com/questions/27539223/permutations-via-heaps-algorithm-with-a-mystery-comma#27540053
function permutation(originalArr) {
  let transferArr = originalArr, resultsAsStrings = []

  function swap(end, begin) {
    let original = transferArr[begin]
    transferArr[begin] = transferArr[end]
    transferArr[end] = original
  }

  function heaps_algorithm(n) {
    if (n === 1) resultsAsStrings.push(transferArr.join(""))

    for (let i = 0; i != n; ++i) {
      heaps_algorithm(n - 1)
      swap(n - 1, n % 2 === 0 ? i : 0)
    }
  }

  heaps_algorithm(originalArr.length)
  return resultsAsStrings
}

const a = [1, 2, 3, 4]
console.log(permutation(a))

const b = [0, 1, 2]
console.log(permutation(b))

const c = [2, 3, 4]
console.log(permutation(c))

Kadane's Algorithm

Given:

int[] input = new int[]{2, 3, -8, 7, -1, 2, 3};
int result = input[0];

for (int i = 0; i < input.length; i++) {
  int current = 0;
  
  for (int j = i; j < input.length; j++) {
    current += input[j];
    result = Math.max(result, current);
  }
}

//return result;

The Brute-Force implementation O(N²) can be optimzed to O(N):

int result = input[0]; 
int maxEnding = input[0]; 

for (int i = 1; i < input.length; i++) {
  int N = input[i];

  maxEnding = Math.max(maxEnding + N, N); 
  result = Math.max(maxEnding, result);
}

Observe:

  1. There are three conditions:
    • New highest sum
    • Replacing the last highest sum with current index value
    • Same highest sum
  2. Highests subarray sums are transitive across indicies (except in the second condition where a positive number follows a negative one).
  3. This necessitates two Variables, one (result) that's derived from the other (maxEnding). (I attempted to reduce this to a single multiple Max expression with a single Variable and was unable to optimize beyond the above.)
  1. https://www.geeksforgeeks.org/largest-sum-contiguous-subarray
  2. https://www.math.umd.edu/~immortal/CMSC351/notes/maxcontiguoussum.pdf

Algorithms: Some Fun Ones

Some fun algorithms I've encountered from here and there.

Implement Lodash Curry

Challenge: implement Lodash .curry() from scratch. Official Code snippet.

function W(func) {
    // Key insight here is to use an aux buffer to store args into.
    let resolvedArgs = []
    return C(func, resolvedArgs)
}

function C(func, resolvedArgs, arity=func.length) {
    // Return an anon function with ...args here
    return function(...args) {
        resolvedArgs = [...resolvedArgs, ...args]
        // This is the trickiest part conceptually: recursively curry here
        if (args.length < arity) return C(func, resolvedArgs, arity-args.length)
        return func(...resolvedArgs)
  }
}

function T(a,b,c) {
    return [a,b,c]
}

const F = W(T)

console.log(T("A","B","C"))
console.log(F("A", "B", "C"))
console.log(F("A")("B", "C"))
console.log(F("A", "B")("C"))
console.log(F("A")("B")("C"))
["A", "B", "C"]
["A", "B", "C"]
["A", "B", "C"]
["A", "B", "C"]
["A", "B", "C"]

Flatten Without Flatten

Flatten an Array by a specified amount without using .flat():

var flatten = function (arr, flatten_by) {
    console.log(`Input: ${JSON.stringify(arr)} flatten_by: ${flatten_by}`)

    if (flatten_by === 0) return arr

    let str_arr = JSON.stringify(arr),
        result = "[",
        f_rem = flatten_by
    
    for (let i = 1; i < str_arr.length - 1; i++) {
        const C = str_arr[i]
        
        if (C === "[") {
            f_rem--
            // Balance checks here aren't symmetrical
            if (f_rem < 0) result += C
            
        } else if (C === "]") {
            f_rem++
            if (f_rem <= 0) result += C
        
        } else {
            result += C
        
        }
    }

    result += "]"
    console.log(`Output: ${result}`)
    return JSON.parse(result)
}
    
console.log(flatten([0, 1, 2, [3, 4]], 0))
console.log(flatten([0, 1, 2, [3, 4]], 1))
console.log(flatten([0, 1, 2, [[3, 4]]], 1))
console.log(flatten([0, 1, 2, [[3, 4]]], 2))
console.log(flatten([0, 1, [[[2, 3, 4]]]], 1))
console.log(flatten([[0, 1], 2, [[3, 4]]], 2))
console.log(flatten([[1], 1, [1], 1, [1], 1], 1))
console.log(flatten([[1], 1, [1], 1, [1], 1], 9))
console.log(flatten([[1], 1, [1], 1, [1], 1], 0))
console.log(flatten([[[[[[[[[[[[[[[[[9]]]]]]]]]]]]]]]]], 8))
console.log(flatten([[[[[[[[[[[[[[[[[9]]]]]]]]]]]]]]]]], 18))
"Input: [0,1,2,[3,4]] flatten_by: 0"
[0, 1, 2, [3, 4]]
"Input: [0,1,2,[3,4]] flatten_by: 1"
"Output: [0,1,2,3,4]"
[0, 1, 2, 3, 4]
"Input: [0,1,2,[[3,4]]] flatten_by: 1"
"Output: [0,1,2,[3,4]]"
[0, 1, 2, [3, 4]]
"Input: [0,1,2,[[3,4]]] flatten_by: 2"
"Output: [0,1,2,3,4]"
[0, 1, 2, 3, 4]
"Input: [0,1,[[[2,3,4]]]] flatten_by: 1"
"Output: [0,1,[[2,3,4]]]"
[0, 1, [[2, 3, 4]]]
"Input: [[0,1],2,[[3,4]]] flatten_by: 2"
"Output: [0,1,2,3,4]"
[0, 1, 2, 3, 4]
"Input: [[1],1,[1],1,[1],1] flatten_by: 1"
"Output: [1,1,1,1,1,1]"
[1, 1, 1, 1, 1, 1]
"Input: [[1],1,[1],1,[1],1] flatten_by: 9"
"Output: [1,1,1,1,1,1]"
[1, 1, 1, 1, 1, 1]
"Input: [[1],1,[1],1,[1],1] flatten_by: 0"
[[1], 1, [1], 1, [1], 1]
"Input: [[[[[[[[[[[[[[[[[9]]]]]]]]]]]]]]]]] flatten_by: 8"
"Output: [[[[[[[[[9]]]]]]]]]"
[[[[[[[[[9]]]]]]]]]
"Input: [[[[[[[[[[[[[[[[[9]]]]]]]]]]]]]]]]] flatten_by: 18"
"Output: [9]"
[9]

Algorithms: Search

A Needle refers to the Value, item, or Object one is searching for within a Haystack (the collection of items one is searching within).

Search Techniques

Breadth First Search (BFS) - graph search, sequential horizontal search (by row or width) of a node.

Depth First Search (DFS) - graph search, sequential vertical search (by column or full height) of a branch.

Sorted by Average Big O Time Complexity.

Hash Table - define a hashing method, each value is assigned a hash key that is unique to that value, then lookup a value using the hash key.

const hash = (needle, haystack) => {
  console.log((`Find: ${needle} in [${haystack}]`, "hashstart")

  let table = []
  for (let i = 0; i < haystack.length; i++) {
    table[i] = -1
  }

  let keyHash = 0

  const simpleHash = val => val % table.length

  for (let i = 0; i < haystack.length; i++) {
    let flag = haystack[i] == needle
    const currentHash = simpleHash(haystack[i])

    if (table[currentHash] === -1) {
      table[currentHash] = haystack[i]
      if (flag) keyHash = currentHash

    } else {
      const NEXT = table.indexOf(-1)
      table[NEXT] = haystack[i]
      if (flag) keyHash = NEXT

    }
  }

  console.log((`Hash Table: [${table}] - Length: ${table.length}`)

  const BEGIN = new Date()
  const result = table[keyHash]
  const indexOf = haystack.indexOf(needle)
  const END = new Date()

  console.log((`Hash: ${keyHash} - Value: ${result} - IndexOf ${indexOf} in unsorted haystack`)
  console.log(`Time taken: ${END - BEGIN}`)
}

Linear - iterate through n until k is found.

const linear = (needle, haystack) => {
  const BEGIN = new Date()
  let result = -1

  console.log(`Find: ${needle} in [${haystack}]`)

  for (let i = 0; i < haystack.length; i++) {
    if (needle === haystack[i]) {
      result = i;
      break;
    }
  }

  const indexOf = haystack.indexOf(needle);
  const END = new Date()
  console.log(`Index: ${result} - IndexOf: ${indexOf}`)
  console.log(`Time taken: ${END - BEGIN}`)
}

Binary- take a sorted Array and recursively divide in two comparing the Needle against values in each divided Array.

const binary = (needle, haystack) => {
  haystack.sort((a, b) => a - b)
  console.log(`Sorted haystack: ${haystack}`)

  let l = 0, r = haystack.length - 1

  while (l <= r) {
    const M = Math.floor((l + r) / 2)

    if (haystack[M] === needle) {
      console.log(`${haystack[M]} at sorted index ${M}`)
      break
    } 
    
    if (haystack[M] < needle) l = M + 1
    
    // haystack[M] > needle
    else r = M - 1
  }
}

Consult a clean implementation here: https://www.instagram.com/reel/CYjmjbFF_8g/?utm_source=ig_web_copy_link

  1. https://www.instagram.com/reel/CYjmjbFF_8g/?utm_source=ig_web_copy_link

Algorithms: Sort

Sorted by Average Big O Time Complexity.

Non-Comparison Sorts

Insertion Sort - use a second array to rebuild the first array in sorted order, loop through inserting the next lowest value into the second array.

https://github.com/Thoughtscript/sort_algos_2025/blob/main/noncomparison/insertion.js

Counting Sort - sort by statistical frequency using a buffer. (Frequency Sort)

https://github.com/Thoughtscript/sort_algos_2025/blob/main/noncomparison/frequency.js

Bucket Sort- sort an array using buckets (that divide across the range of the input array), can be a Counting Sort and/or Insertion Sort depending on setup.

https://github.com/Thoughtscript/sort_algos_2025/blob/main/noncomparison/bucket.js

Comparison Sorts

Heap Sort - properly sorts an array into a Binary Heap.

https://github.com/Thoughtscript/cplusplus-coursera/blob/master/course/12%20-%20Heap/main.cpp

Merge Sort - divide an array into halves until two elements exist in each array then recombine comparing elements along the way.

https://github.com/Thoughtscript/sort_algos_2025/blob/main/comparison/merge.js

Review: https://medium.com/analytics-vidhya/implement-merge-sort-algorithm-in-javascript-7402b7271887

Quick Sort - (recursively) specify a pivot point and swap values that are above and below the pivot point.

Helpful: https://www.geeksforgeeks.org/quick-sort-algorithm/

https://github.com/Thoughtscript/sort_algos_2025/blob/main/comparison/quick.js

Bubble Sort - loop through replacing sequential pairs (Swap) as necessary.

https://github.com/Thoughtscript/sort_algos_2025/blob/main/comparison/bubble.js

Selection Sort - loop through swapping the lowest number with the current index.

https://github.com/Thoughtscript/sort_algos_2025/blob/main/comparison/selection.js

Language Implementations

  1. Java uses a modified Merge Sort (by default).
  2. JavaScript uses a modified Quick Sort with Insertion Sort fallback (by default).
  1. https://v8.dev/blog/array-sort
  2. https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.sort
  3. https://docs.oracle.com/javase/6/docs/api/java/util/Collections.html#sort%28java.util.List%29
  4. https://medium.com/analytics-vidhya/implement-merge-sort-algorithm-in-javascript-7402b7271887
  5. https://www.geeksforgeeks.org/quick-sort-algorithm/

Code samples:

  1. https://github.com/Thoughtscript/sort_algos_2025/blob/main/comparison/bubble.js
  2. https://github.com/Thoughtscript/sort_algos_2025/blob/main/comparison/merge.js
  3. https://github.com/Thoughtscript/sort_algos_2025/blob/main/comparison/quick.js
  4. https://github.com/Thoughtscript/sort_algos_2025/blob/main/comparison/selection.js
  5. https://github.com/Thoughtscript/sort_algos_2025/blob/main/noncomparison/bucket.js
  6. https://github.com/Thoughtscript/sort_algos_2025/blob/main/noncomparison/frequency.js
  7. https://github.com/Thoughtscript/sort_algos_2025/blob/main/noncomparison/insertion.js
  8. https://github.com/Thoughtscript/cplusplus-coursera/blob/master/course/12%20-%20Heap/main.cpp

Algorithms: Recursion

Where a function repeatedly calls itself until some condition is met.

Solved Examples

  1. https://leetcode.com/problems/permutations/
  2. https://leetcode.com/problems/fibonacci-number/
  3. https://leetcode.com/problems/keys-and-rooms/
  4. https://leetcode.com/problems/deepest-leaves-sum/
  5. https://leetcode.com/problems/minimum-add-to-make-parentheses-valid/

Algorithms: Loop Recursion

A kind of Recursion problem where Recursion is called within a For-loop.

Useful for iterating through all permissible contiguous String subsequence "chunks".

  1. https://www.youtube.com/watch?v=DI6pH9Cx654 <- great example

Algorithms: Dynamic Programming

Breaking a problem down into multiple sub-problems where each step is stored (typically on the fly not Ahead-of-Time).

Often used with Memoization to reduce recursion footprint.

Solved Examples

  1. https://leetcode.com/problems/count-sorted-vowel-strings/ <- Using variables that are saved off each cycle
  2. https://leetcode.com/problems/product-of-array-except-self/ <- Bottom 50% time-complexity. Top .07% space-complexity.
  3. https://leetcode.com/problems/max-increase-to-keep-city-skyline/
  4. https://leetcode.com/problems/arithmetic-subarrays/
  5. https://leetcode.com/problems/pascals-triangle/

Algorithms: Memoization

Saving the state of an instruction set into an Array, Map, Stack, Dequeue, or Queue.

Often eliminates the need to recursively compute some value.

Solved Examples

  1. https://leetcode.com/problems/triangle/
  2. https://leetcode.com/problems/climbing-stairs/ <- Used a precomputed O(1) data set I generated.
  3. https://leetcode.com/problems/count-and-say/ <- Used a precomputed O(1) data set I generated.
  4. https://leetcode.com/problems/longest-nice-substring/

Algorithms: Sets

Power Set

Dynamic Solution:

/**
 * Review: https://stackoverflow.com/questions/24365954/how-to-generate-a-power-set-of-a-given-set
 *
 * Strategy is clean and elegant so I made a few tweaks and implemented it in JS from the above.
 * 
 * Add elements one at a time to a result array, also iterate over the result array adding elements to the existing ones.
 *
 * This accomplished what was done here: https://medium.com/leetcode-patterns/leetcode-pattern-3-backtracking-5d9e5a03dc26 
 * and here: https://jimmy-shen.medium.com/78-subsets-fa4f0b047664 without backtracking (those are excellent articles 
 * and implementations given the requirements!).
 */

const powerSet = arrSet => {
  let arrSets = []
  for (let i = 0; i < arrSet.length; i++) {
    let item = arrSet[i], origSets = [...arrSets]
    
    for (let j = 0; j < origSets.length; j++) {
      let nSet = origSets[j].concat(item)
      arrSets.push(nSet)
    }
    arrSets.push([item])
  }
  arrSets.push([])
  return arrSets.sort()
}

window.onload = () => {
  console.log(powerSet([4, 2, 3]))
  console.log(powerSet([5, 1, 4, 2, 3]))
}
[
  [],          [ 2 ],
  [ 2, 3 ],    [ 3 ],
  [ 4 ],       [ 4, 2 ],
  [ 4, 2, 3 ], [ 4, 3 ]
]

[
  [],             [ 1 ],
  [ 1, 2 ],       [ 1, 2, 3 ],
  [ 1, 3 ],       [ 1, 4 ],
  [ 1, 4, 2 ],    [ 1, 4, 2, 3 ],
  [ 1, 4, 3 ],    [ 2 ],
  [ 2, 3 ],       [ 3 ],
  [ 4 ],          [ 4, 2 ],
  [ 4, 2, 3 ],    [ 4, 3 ],
  [ 5 ],          [ 5, 1 ],
  [ 5, 1, 2 ],    [ 5, 1, 2, 3 ],
  [ 5, 1, 3 ],    [ 5, 1, 4 ],
  [ 5, 1, 4, 2 ], [ 5, 1, 4, 2, 3 ],
  [ 5, 1, 4, 3 ], [ 5, 2 ],
  [ 5, 2, 3 ],    [ 5, 3 ],
  [ 5, 4 ],       [ 5, 4, 2 ],
  [ 5, 4, 2, 3 ], [ 5, 4, 3 ]
]

Greedy Solution:

/**
 * One can approach this from a few different angles:
 * 1. Brute force.
 * 2. Binary counter.
 * 3. Use native abstractions.
 * ---
 * I'd prefer to use what I understand to be a novel approach by generating 
 * constraints AOT (ahead-of_time) so that power-set 
 * generation is linear for every subsequent run.
 * ---
 * We can then use these values to populate others by index (e.g. - 1 means in the subset, 0 not).
 * The upside is that this is superfast (most powerset implementations 
 * involve deep recursion and 2-3 nested loops).
 * ----
 * The downside of this approach is that only works if you know the desired 
 * set size beforehand. It's Greedy.
 */

const generateConstraints = () => {
  let result = [], current = []

  // Flattened nested loop...
  for (let i = 0, j = 0, k = 0, l = 0; i < 2 && j < 2 && k < 2 && l < 2; i) {
    current.push(i)
    current.push(j)
    current.push(k)
    current.push(l)
    result.push(current)
    current = []

    l++;
    if (l == 2) {
      k++
      l = 0
    }
    if (k == 2) {
      j++
      k = 0
    }
    if (j == 2) {
      i++
      j = 0
    }
  }

  return result
}

window.onload = () => {
  const aot = generateConstraints()
  console.log(aot)
}
[
  [],          [ 2 ],
  [ 2, 3 ],    [ 3 ],
  [ 4 ],       [ 4, 2 ],
  [ 4, 2, 3 ], [ 4, 3 ]
]

[
  [],             [ 1 ],
  [ 1, 2 ],       [ 1, 2, 3 ],
  [ 1, 3 ],       [ 1, 4 ],
  [ 1, 4, 2 ],    [ 1, 4, 2, 3 ],
  [ 1, 4, 3 ],    [ 2 ],
  [ 2, 3 ],       [ 3 ],
  [ 4 ],          [ 4, 2 ],
  [ 4, 2, 3 ],    [ 4, 3 ],
  [ 5 ],          [ 5, 1 ],
  [ 5, 1, 2 ],    [ 5, 1, 2, 3 ],
  [ 5, 1, 3 ],    [ 5, 1, 4 ],
  [ 5, 1, 4, 2 ], [ 5, 1, 4, 2, 3 ],
  [ 5, 1, 4, 3 ], [ 5, 2 ],
  [ 5, 2, 3 ],    [ 5, 3 ],
  [ 5, 4 ],       [ 5, 4, 2 ],
  [ 5, 4, 2, 3 ], [ 5, 4, 3 ]
]

Cartesian Multiplication

Original Generalized Dynamic Solution using the above Dynamic Power Set Solution as an inspiration:

const solve = (args) => {
    let last = []
    const L = args.length - 1
    
    for (let i = 0; i < args[L].length; i++) {
        last.push([args[L][i]])
    }

    for (let i = L - 1; i >= 0; i--) {
        let curr = args[i], temp = []
        
        for (let j = 0; j < curr.length; j++) {
            for (let k = 0; k < last.length; k++) {
                const v = [...last[k]]
                if (v.indexOf(curr[j]) === -1) v.push(curr[j])
                temp.push(v)
            }
        }
        
        last = temp
    }
  
    console.log(last)
} 

window.onload = () => {
  const argsA = [[1,2],[3,4],[5,6]]
  solve(argsA)

  const argsB = [[1,2,3],[3,4],[5,6,15]]
  solve(argsB)

  const argsC = [[1],[1],[1]]
  solve(argsC)
}

Note: the above implementation isn't order preserving (Sets don't preserve order anyway) and assumes no empty Array is passed (the Empty Set is assumed to be present in every Set so we'll just omit all empty Arrays/Empty Set or we would have to add it everywhere).

[
  [5, 3, 1], 
  [6, 3, 1], 
  [5, 4, 1], 
  [6, 4, 1], 
  [5, 3, 2], 
  [6, 3, 2], 
  [5, 4, 2], 
  [6, 4, 2]
]

[
  [5, 3, 1], 
  [6, 3, 1],
  [15, 3, 1], 
  [5, 4, 1], 
  [6, 4, 1], 
  [15, 4, 1], 
  [5, 3, 2], 
  [6, 3, 2], 
  [15, 3, 2], 
  [5, 4, 2], 
  [6, 4, 2], 
  [15, 4, 2],
  [5, 3], 
  [6, 3],
  [15, 3], 
  [5, 4, 3], 
  [6, 4, 3], 
  [15, 4, 3]
]

[
  [1]
]

Algorithms: Hash Maps and Counts

Typically used when a solution requires a unique answer or a deduplicated Set.

Also often used to track the frequency of some value (number of occurrences).

Technique: Hash Map

let M = {}; 

// ...

if (M[x] != undefined) M[x]++; 
else M[x] = 1;

Solved Examples

  1. https://leetcode.com/problems/isomorphic-strings/
  2. https://leetcode.com/problems/word-pattern/description/
  3. https://leetcode.com/problems/divide-array-into-increasing-sequences/
  4. https://leetcode.com/problems/longest-consecutive-sequence/
  5. https://leetcode.com/problems/minimum-number-of-steps-to-make-two-strings-anagram/
  6. https://leetcode.com/problems/check-if-all-characters-have-equal-number-of-occurrences/ <- Bottom 50% time-complexity.

Algorithms: Graph Relationship

Where a series of relationships are expressed using Arrays, Sets, or Maps.

Often a kind of Hash Counting Algorithm that requires Reverse Maps, Dual Mapping, Symmetric Maps and the like. Strong possibility that a solution can be achieved using a Maps of Maps.

Reverse Map

const A = {
    "AA": "BB",
    "CC":"DD"
}

const B = {
    "BB": "AA",
    "DD":"CC"
}

N-Tuple

Demonstrating a specific kind of this problem and how to index the relationships in multiple ways in O(N) time:

const Example = [
    [1, 2, 3], 
    [0, 3, 1], 
    [0, 4, 3], 
    [0, 5, 3], 
]

/*
 Where for each X in Example:
    1. X[1] is related to X[2] through relationship X[0].
    2. Where the relationship of X[1] to X[2] is symmetric (or not depending).
*/

const A = {
    "1": {
        "3": 0
    },
    "2": {
        "3": 1
    },
    "3": {
        "2": 1,
        "1": 0,
        "4": 0,
        "5": 0
    },
    "4": {
        "3": 0
    },
    "5": {
        "3": 0
    }
}
// Map of X[1] to X[2] and X[2] to X[1]

const B = {
    "1": {
        "3": {
            "2": true
        }
        "2": {
            "3": true
        }
    },
    "0": {
        "1": {
            "3": true
        },
        "3": {
            "1": true,
            "4": true,
            "5": true
        },
        "4": {
            "3": true
        },
        "5": {
            "3": true
        }
    }
}

// Map of X[0] to the relationship of X[2] to X[1] (and vice-versa)

Algorithms: Phone Dialer

Questions that use a 0-9 phone pad or phone numbers.

Solved Examples

  1. https://leetcode.com/problems/minimum-number-of-keypresses/
  2. https://www.codewars.com/kata/635b8fa500fba2bef9189473
  3. https://leetcode.com/problems/reformat-phone-number/
  4. https://leetcode.com/problems/letter-combinations-of-a-phone-number/
  5. https://leetcode.com/problems/knight-dialer/ <- Bit slow.

Algorithms: Text Representation

Technique: Unicode Char Codes

// JavaScript
const c = str.charCodeAt(i);

// Unicode numbers codes 48-57 inclusive
if (c >= 48 && c <= 57) console.log("I'm a number character")
// Unicode uppercased letters codes 65-90 inclusive 
if (c >= 65 && c <= 90) console.log("I'm an uppercased character")
// Unicode lowercased letters codes 97-122 inclusive 
if (c >= 97 && c <= 122) console.log("I'm an lowercased character")
// JavaScript
const c = str.charCodeAt(i);

if ((c >= 65 && c <= 90) || (c >= 97 && c <= 122)) {
    const isUpperVowel = [65, 69, 73, 79, 85].indexOf(c) === -1 
    const isLowerVowel = [97, 101, 105, 111, 117].indexOf(c) === -1
    if (isUpperVowel && isLowerVowel) console.log("I'm a consonant")
    else console.log("I'm a vowel")
} else console.log("I'm not a letter")

Review: https://tutorial.eyehunts.com/js/get-the-unicode-value-of-character-javascript-example-code/

Technique: Character Maps

Alphabet maps:

// JavaScript
const a = {"a":0,"e":0,"i":0,"o":0,"u":0,"b":0,"c":0,"d":0,"f":0,"g":0,"h":0,"j":0,"k":0,"l":0,"m":0,"n":0,"p":0,"q":0,"r":0,"s":0,"t":0,"v":0,"w":0,"x":0,"y":0,"z":0}
const A = {"A":0,"E":0,"I":0,"O":0,"U":0,"B":0,"C":0,"D":0,"F":0,"G":0,"H":0,"J":0,"K":0,"L":0,"M":0,"N":0,"P":0,"Q":0,"R":0,"S":0,"T":0,"V":0,"W":0,"X":0,"Y":0,"Z":0}

// As array mapped by index
const arr_a = Object.keys(a)
const arr_A = Object.keys(A)

Consonant maps:

// JavaScript
const c = {"b":0,"c":0,"d":0,"f":0,"g":0,"h":0,"j":0,"k":0,"l":0,"m":0,"n":0,"p":0,"q":0,"r":0,"s":0,"t":0,"v":0,"w":0,"x":0,"y":0,"z":0}
const C = {"B":0,"C":0,"D":0,"F":0,"G":0,"H":0,"J":0,"K":0,"L":0,"M":0,"N":0,"P":0,"Q":0,"R":0,"S":0,"T":0,"V":0,"W":0,"X":0,"Y":0,"Z":0}

// As array mapped by index
const arr_c = Object.keys(c)
const arr_C = Object.keys(C)

Vowel maps:

// JavaScript
const v = {"a":0,"e":0,"i":0,"o":0,"u":0}
const V = {"A":0,"E":0,"I":0,"O":0,"U":0}

// As array mapped by index
const arr_v = Object.keys(v)
const arr_V = Object.keys(V)

Number maps:

// JavaScript
const N = {"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0}

// As array mapped by index
const arr_N = Object.keys(N)

Technique: Check Character is Number

// Java
Character.isDigit(inputStr.charAt(i)); // true/false

Algorithms: Letter Chars and Word Dictionaries

Specific to the dictionary, String, and Character checking with a fixed, finite, alphabet.

Solved Examples

  1. https://leetcode.com/problems/expressive-words/
  2. https://leetcode.com/problems/string-without-aaa-or-bbb/ <- Bottom 50% time-complexity.
  3. https://leetcode.com/problems/maximum-number-of-words-you-can-type/
  4. https://leetcode.com/problems/check-if-all-characters-have-equal-number-of-occurrences/ <- Bottom 50% time-complexity.
  5. https://leetcode.com/problems/check-if-word-equals-summation-of-two-words/
  6. https://leetcode.com/problems/long-pressed-name/
  7. https://leetcode.com/problems/shortest-word-distance/
  8. https://leetcode.com/problems/keyboard-row/
  9. https://leetcode.com/problems/verifying-an-alien-dictionary/ <- Bottom 50% time-complexity.
  10. https://leetcode.com/problems/single-row-keyboard/
  11. https://leetcode.com/problems/remove-vowels-from-a-string/ <- Bottom 50% time-complexity.

Algorithms: Word Patterns, Anagrams, and Palindromes

Word pattern, anagram, and palindrome scenarios.

Solved Examples

  1. https://leetcode.com/problems/word-pattern/
  2. https://leetcode.com/problems/palindrome-number/
  3. https://leetcode.com/problems/valid-palindrome/ <- Below 50% time-complexity. Top 2.62% space-complexity.
  4. https://leetcode.com/problems/palindrome-linked-list/
  5. https://leetcode.com/problems/valid-palindrome-ii/
  6. https://leetcode.com/problems/palindromic-substrings/ <- Below 50% time-complexity. Brute-force.
  7. https://leetcode.com/problems/partition-labels/ <- Below 50% time-complexity.
  8. https://leetcode.com/problems/find-anagram-mappings/
  9. https://leetcode.com/problems/group-anagrams/ <- Below 50% time-complexity. Top .26% space-complexity.
  10. https://leetcode.com/problems/minimum-number-of-steps-to-make-two-strings-anagram/

Algorithms: Parentheses

Calculate the validity of various Strings or substrings containing parentheticals.

Similar to facing but typically with a narrower focus (balance).

Solved Examples

  1. https://leetcode.com/problems/remove-outermost-parentheses/
  2. https://leetcode.com/problems/valid-parentheses/
  3. https://leetcode.com/problems/longest-valid-parentheses/ <- Very slow.
  4. https://leetcode.com/problems/minimum-add-to-make-parentheses-valid/
  5. https://leetcode.com/problems/maximum-nesting-depth-of-the-parentheses
  6. https://www.codewars.com/kata/5426d7a2c2c7784365000783
  7. https://www.codewars.com/kata/5277c8a221e209d3f6000b56

Algorithms: Two Pointer

Typically used when working with Arrays or Strings.

Use two pointers left and right.

Check or compare the values of each cycle.

Technique: Left and Right Pointers

while (left < right) { 
    //... 
    left++; 
    right--;
}

Solved Examples

  1. https://leetcode.com/problems/guess-number-higher-or-lower/
  2. https://leetcode.com/problems/missing-number-in-arithmetic-progression/
  3. https://leetcode.com/problems/minimize-maximum-pair-sum-in-array/ <- Very slow. Brute-force.
  4. https://leetcode.com/problems/split-two-strings-to-make-palindrome/
  5. https://leetcode.com/problems/merge-two-sorted-lists/

Algorithms: Sliding Window

Often used to find unique subarrays, longest substrings, longest Strings with some property, etc.

This method is often used to reduce the time complexity of a solution from Quadratic to Linear time (when it can be applied).

Generally:

Solved Examples

  1. https://leetcode.com/problems/maximum-average-subarray-i/
  2. https://leetcode.com/problems/longest-subarray-of-1s-after-deleting-one-element/
  3. https://leetcode.com/problems/distinct-numbers-in-each-subarray/ <- Very slow.
  4. https://leetcode.com/problems/longest-common-subsequence-between-sorted-arrays/

Algorithms: Direction and Facing

Solved Examples

  1. https://leetcode.com/problems/robot-bounded-in-circle/ <- Very slow.
  2. https://leetcode.com/problems/robot-return-to-origin/
  3. https://github.com/Thoughtscript/bloomfire_test
  4. https://www.codewars.com/kata/550f22f4d758534c1100025a

Algorithms: Number Representation

Non-number type number-representation scenarios.

Technique: Fast Number Reversal

Old way:

const rev = num => {
    const numStr = `${num}`
    let str = ''

    for (let i = numStr.length - 1; i >= 0; i--) {
        str += numStr[i]
    }

    return parseInt(str)
}

Much faster than int to String and back conversion:

// Java
int reverse(int num) {
    int rev = 0;
    
    while(num > 0){
        int d = num % 10;
        rev = rev * 10 + d;
        num = num / 10;
    }
    
    return rev;
}
// Java
const reverse = num => {
    let rev = 0

    while(Math.floor(num) > 0) {
        const d = num % 10
        result = Math.floor(result * 10 + d)
        num = num / 10
    }

    return rev
}

JavaScript doesn't automatically round Numbers < 1 to 0 like Java does. So, use Math.floor().

Solved Examples

  1. https://projecteuler.net/problem=89
  2. https://www.codewars.com/kata/51b66044bce5799a7f000003
  3. https://www.codewars.com/kata/5324945e2ece5e1f32000370
  4. https://www.codewars.com/kata/525f4206b73515bffb000b21
  5. https://www.codewars.com/kata/5265326f5fda8eb1160004c8
  6. https://www.codewars.com/kata/54d7660d2daf68c619000d95
  7. https://leetcode.com/problems/thousand-separator/
  8. https://leetcode.com/problems/roman-to-integer/ <- Below 50% time-complexity. Top .01% space-complexity.
  9. https://leetcode.com/problems/integer-to-roman/
  10. https://leetcode.com/problems/integer-to-english-words/
  11. https://leetcode.com/problems/string-to-integer-atoi/
  12. https://leetcode.com/problems/add-strings/
  13. https://leetcode.com/problems/add-two-numbers/
  14. https://leetcode.com/problems/add-two-numbers-ii/ <- Below 50% time-complexity. Top 2.73% space-complexity.
  15. https://leetcode.com/problems/sum-of-two-integers/
  16. https://leetcode.com/problems/excel-sheet-column-number/ <- Not original, bijective base 26.

Algorithms: Number Theory

Implementations of arithmetic or number-theoretic scenarios.

Solved Examples

  1. https://leetcode.com/problems/happy-number/
  2. https://leetcode.com/problems/self-dividing-numbers/
  3. https://leetcode.com/problems/valid-perfect-square/
  4. https://projecteuler.net/problem=46
  5. https://leetcode.com/problems/power-of-two/
  6. https://leetcode.com/problems/sum-of-two-integers/
  7. https://leetcode.com/problems/fraction-addition-and-subtraction/
  8. https://leetcode.com/problems/fibonacci-number/
  9. https://projecteuler.net/problem=14
  10. https://leetcode.com/problems/add-strings/
  11. https://leetcode.com/problems/prime-arrangements/
  12. https://leetcode.com/problems/missing-number-in-arithmetic-progression/
  13. https://projecteuler.net/problem=32

Algorithms: Prime Numbers

Algorithms involving Prime Numbers.

Solved Examples

  1. https://projecteuler.net/problem=7
  2. https://www.codewars.com/kata/54d512e62a5e54c96200019e
  3. https://www.codewars.com/kata/5262119038c0985a5b00029f
  4. https://projecteuler.net/problem=35
  5. https://projecteuler.net/problem=41
  6. https://projecteuler.net/problem=37
  7. https://leetcode.com/problems/count-primes/ <- Very slow.

Algorithms: Path Compression and Merging

Used to combine multiple subarrays until they are all non-overlapping.

Used to merge Sets until they are Disjoint Sets.

Solved Examples

  1. https://leetcode.com/problems/sum-of-digits-of-string-after-convert/ <- top 98.6% answer, loosely a compression/merging problem since it involves repeatedly summing a number until it’s below 10 or k.
  2. https://leetcode.com/problems/merge-intervals/
  3. https://www.codewars.com/kata/5286d92ec6b5a9045c000087
  4. https://leetcode.com/problems/partition-labels/
  5. https://leetcode.com/problems/meeting-rooms/
  6. https://leetcode.com/problems/meeting-rooms-ii/ <- Very slow.
  7. https://www.codewars.com/kata/52b7ed099cdc285c300001cd
  8. https://leetcode.com/problems/summary-ranges/

Algorithms: Directory or Name Traversal

Directory name, IP Address, versioning, or URL context path operations.

Solved Examples

  1. https://leetcode.com/problems/simplify-path/
  2. https://leetcode.com/problems/validate-ip-address/
  3. https://leetcode.com/problems/defanging-an-ip-address
  4. https://www.codewars.com/kata/5286d92ec6b5a9045c000087
  5. https://leetcode.com/problems/compare-version-numbers/

Algorithms: Level Recursion

Recursion specific to iterating down a pyramidal data structure.

Technique: Queue

Use a Queue (nxt), use two alternating containers: level and nxt.

    level = [node]
    nxt = []
    
    while len(level) > 0:
        temp = []
        count = 0
        l = len(level)
        
        while count < l:
            if (len(level) > 0):
                c = level.pop(0)
                if c is None:
                    continue
                temp.append(c.value)
                nxt.append(c.left)
                nxt.append(c.right)
            count += 1
        
        if len(temp) > 0:
            for x in range(0, len(temp)):
                result.append(temp[x])

        level = nxt

Solved Examples

  1. https://www.codewars.com/kata/52bef5e3588c56132c0003bc
  2. https://leetcode.com/problems/binary-tree-level-order-traversal/
  3. https://leetcode.com/problems/n-ary-tree-level-order-traversal/
  4. https://leetcode.com/problems/binary-tree-level-order-traversal-ii/

Algorithms: Geometry

Implementations of geometry scenarios and problems.

Solved Examples

  1. https://leetcode.com/problems/get-biggest-three-rhombus-sums-in-a-grid/ <- Bottom 50% time-complexity.
  2. https://leetcode.com/problems/rectangle-overlap/
  3. https://leetcode.com/problems/angle-between-hands-of-a-clock/
  4. https://leetcode.com/problems/k-closest-points-to-origin/
  5. https://leetcode.com/problems/subrectangle-queries/
  6. https://leetcode.com/problems/number-of-rectangles-that-can-form-the-largest-square/

Algorithms: Islands

Problems representing connected sub-matrices.

Technique: Check and Recurse

const countIslands = mapStr => {
  const ARR = mapStr.split("\n"), cleanedArr = []
  
  for (let i = 0; i < ARR.length; i++) {
    cleanedArr.push(ARR[i].split(""))
  }
  
  let deepCopy = [...cleanedArr], cnt = 0, hasNext = findNext(deepCopy)
  
  while (hasNext !== false) {
    cnt++
    recurse(deepCopy, hasNext[0], hasNext[1])
    hasNext = findNext(deepCopy)
  }

  return cnt
}

const findNext = arr => {
  for (let i = 0; i < arr.length; i++) {
    for (let j = 0; j < arr[i].length; j++) {
      const I = arr[i][j]
      if (I === '0') {
        return [i, j]
      }
    }
  }  
  return false
}

const recurse = (arr, i, j) => {
  if (i >= arr.length || j >= arr[i].length || i <= -1 || j <= -1) {}
  else {
    arr[i][j] = '.'
    if (arr[i-1] !== undefined && arr[i-1][j] === '0') recurse(arr, i-1, j)    
    if (arr[i+1] !== undefined && arr[i+1][j] === '0') recurse(arr, i+1, j)
    if (arr[i][j-1] !== undefined && arr[i][j-1] === '0') recurse(arr, i, j-1)    
    if (arr[i][j+1] !== undefined && arr[i][j+1] === '0') recurse(arr, i, j+1)
  }
}

Interesting Technique

// Helpful comments from Sakashi to get in under the absolute time limit
// https://www.geeksforgeeks.org/problems/word-search/1

//...
boolean[][] seen = new boolean[mat.length][mat[0].length];
seen[r][c] = true; // Key insight here - allows reusing same deepcopy repeatedly!!!

//... Code here

seen[r][c] = false; // doesn't require deep copying each traversal!

https://github.com/Thoughtscript/java_algos/blob/main/src/main/java/io/thoughtscript/algos/gfg/arrays/WordSearch.java

Solved Examples

  1. https://www.codewars.com/kata/5611e038a1b7990def000076
  2. https://www.codewars.com/kata/55a4f1f67157d8cbe200007b
  3. https://leetcode.com/problems/island-perimeter/
  4. https://leetcode.com/problems/max-area-of-island/
  5. https://leetcode.com/problems/number-of-islands/
  6. https://leetcode.com/problems/flood-fill/
  7. https://leetcode.com/problems/minesweeper/
  8. https://leetcode.com/problems/word-search/submissions/1628987420/
  9. https://www.geeksforgeeks.org/problems/word-search/1

Code samples:

  1. https://github.com/Thoughtscript/java_algos/blob/main/src/main/java/io/thoughtscript/algos/gfg/arrays/WordSearch.java

Algorithms: Pathing

To find a path from some origin to some end point.

Solved Examples

  1. https://leetcode.com/problems/minimum-path-sum/
  2. https://leetcode.com/problems/unique-paths/
  3. https://leetcode.com/problems/unique-paths-ii/
  4. https://projecteuler.net/problem=67
  5. https://projecteuler.net/problem=18

Algorithms: Rotations, Spirals, Diagonals

Includes spirals or diagonally traversing an N x M Array or matrix, transposing matrices, rotations, etc.

Also often involves mod or Modulus concepts.

Used for ciphers or rotating an Array.

Solved Examples

  1. https://leetcode.com/problems/rotate-string/
  2. https://leetcode.com/problems/search-in-rotated-sorted-array/
  3. https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/
  4. https://leetcode.com/problems/rotate-array/
  5. https://codepen.io/thoughtscript/pen/poNQMaW
  6. https://leetcode.com/problems/spiral-matrix/
  7. https://leetcode.com/problems/matrix-diagonal-sum/
  8. https://leetcode.com/problems/sort-the-matrix-diagonally/
  9. https://leetcode.com/problems/diagonal-traverse/ <- Very slow.
  10. https://leetcode.com/problems/rotating-the-box/ <- Very slow.
  11. https://leetcode.com/problems/spiral-matrix-ii/
  12. https://www.codewars.com/kata/52fba2a9adcd10b34300094c

Algorithms: Coins and Make Bricks

Optimization scenarios involving fixed units of some value that need to be combined in some optimal way.

Solved Examples

  1. https://projecteuler.net/problem=31
  2. https://www.codewars.com/kata/564d0490e96393fc5c000029
  3. http://www.javaproblems.com/2013/11/java-logic-2-makebricks-codingbat.html
  4. https://leetcode.com/problems/coin-change-ii/ <- Not original.
  5. https://leetcode.com/problems/coin-change/ <- Not original. Slow.
  6. https://leetcode.com/problems/how-many-apples-can-you-put-into-the-basket/
  7. https://leetcode.com/problems/water-bottles/
  8. https://leetcode.com/problems/maximum-units-on-a-truck/ <- Below 50% time-complexity.

Algorithms: N-Sum

Triplet, 4-Sum, 3-Sum, and 2-Sum type problems.

Solved Examples

  1. https://leetcode.com/problems/two-sum/ <- Original solution was very slow but top 100% space-complexity.
  2. https://leetcode.com/problems/two-sum-less-than-k/
  3. https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/

Algorithms: Mountains, Peaks, and Stock Markets

Find a highest point in a sequence and the next highest or lowest point depending.

Solved Examples

  1. https://leetcode.com/problems/longest-mountain-in-array/ <- Very slow.
  2. https://leetcode.com/problems/trapping-rain-water/
  3. https://leetcode.com/problems/peak-index-in-a-mountain-array/
  4. https://leetcode.com/problems/best-time-to-buy-and-sell-stock/ <- Not original.
  5. https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/
  6. https://www.codewars.com/kata/597ef546ee48603f7a000057

Algorithms: Controlled Subsequences

Track things like substrings of a certain length, row or text justification/formatting, or repeated sub-patterns.

Use multiple pointers to track some value that gets reset every n-many loops.

Also includes "reverse loop in loop" (loop "backfilling") problems.

Solved Examples

  1. https://leetcode.com/problems/convert-1d-array-into-2d-array/
  2. https://leetcode.com/problems/string-without-aaa-or-bbb/
  3. https://leetcode.com/problems/text-justification/
  4. https://www.codewars.com/kata/537e18b6147aa838f600001b
  5. https://leetcode.com/problems/longest-subarray-of-1s-after-deleting-one-element/
  6. https://leetcode.com/problems/minimum-number-of-operations-to-move-all-balls-to-each-box/
  7. https://github.com/Thoughtscript/kin_insurance_js