Wikis (Pre-Project)
Best Practices for Wiki Creation:
MVP
: Minimum Viable Product - Outline of your project’s features on your Repo Wiki.
README FIles (Post-Project)
markdown
.Github
is a community of developers, and is a place to share, build, and discover software (also VC).Big O helps gives us a precise vocabulary to talk about how our code performs.
An Example: Comparing two functions that calculate the sum of all numbers from 1 up to n.
Number of operations will grow with n. Would be O(n) or Linear Time.
Has three simple operations: 1 Multiplication 1 Addition 1 Division. (Regardless of n) Would be O(1) or Constant Time.
First we need to consider what makes one implementation better than the other?
How can we measure speed?
function countUpAndDown(n) {
console.log('going up!');
for (let i = 0; i < n; i++) {
console.log(i);
}
console.log('at the top, going down!');
for (let j = n - 1; j >=0; j--) {
console.log(j);
}
console.log('Back down, bye!);
}
Both loops are O(n) but since we just want the big picture, this entire function would be O(n);
function printAllPairs(n) {
for (var i = 0; i < n; i++) {
for (var j = 0; j < n; j++) {
console.log(i, j);
}
}
}
Nested loops are never a good thing when trying to write fast code. O(n^2) or Quadratic Time.
Constants don’t matter in big O & Smaller Terms don’t matter
Big O Shorthands
Additional Examples
O(n) Linear Time
O(1) Constant Time.
Curating Complexity: A Guide to Big-O Notation
Why is looking at runtime not a reliable method of calculating time complexity?
The real question we need to answering is: How does our performance scale?
.
Big O Notation
Smaller
Big O is better (lower time complexity)Simplifying Math Terms
We can use the following rules to simplify the our Big O functions:
Simplify Products
: If the function is a product of many terms, we drop the terms that don’t depend on n.Simplify Sums
: If the function is a sum of many terms, we drop the non-dominant terms.n
: size of the inputT(f)
: unsimplified math functionO(f)
: simplified math function.
Simplifying a Product
| Unsimplified | Big-O Simplified | | ——————- | ——————— | | T(5 _ n^2) | O(n^2) Quadratic | | T(100000 _ n) | O(n) Linear | | T( n / 12) | O (n) Linear | | T( 42 _ n _ log(n)) | O(nlog(n)) Log Linear | | T(12) | O(1) Constant |
Simplifying a Sum
| Unsimplified | Big-O Simplified | | —————- | —————— | | T( n3 + n2 + n ) | O(n^3) | | T( log(n) + 2n ) | O(2^n) Exponential | | T( n + log(n) ) | O(n) Linear | | T( n! + 10n ) | O(n!) Polynomial |
Putting it all together
Unsimplified | Big-O Simplified |
---|---|
T( 5n2 + 99n ) | O(n^2) Quadratic |
T( 2n + nlog(n) ) | O(nlog(n)) Log Linear |
T( 2n + 5n1000) | O(2^n) Exponential |
Common Complexity Classes
There are 7 major classes in Time Complexity
Big O | Complexity Class Name |
---|---|
O(1) | Constant |
O(log(n)) | Logarithmic |
O(n) | Linear |
O(nlog(n)) | Loglinear, Linearithmetic, Quasilinear |
O(nc) - O(n2), O(n3), etc. | Polynomial |
O(cn) - O(2n), O(3n), etc. | Exponential |
O(n!) | Factorial |
O(1) Constant
O(log(n)) Logarithmic
O(n) Linear
O(nlog(n)) Log Linear Time
// O(n * log(n))
function loglinear(n) {
if (n <= 1) return;
for (let i = 1; i <= n; i++) {
console.log(i);
}
loglinear(n / 2);
loglinear(n / 2);
}
O(nc) Polynomial
// O(n^2)
function quadratic(n) {
for (let i = 1; i <= n; i++) {
for (let j = 1; j <= n; j++) {}
}
}
// O(n^3)
function cubic(n) {
for (let i = 1; i <= n; i++) {
for (let j = 1; j <= n; j++) {
for (let k = 1; k <= n; k++) {}
}
}
}
Example of Quadratic and Cubic runtime.
O(c^n) Exponential
// O(2^n)
function exponential2n(n) {
if (n === 1) return;
exponential_2n(n - 1);
exponential_2n(n - 1);
}
// O(3^n)
function exponential3n(n) {
if (n === 0) return;
exponential_3n(n - 1);
exponential_3n(n - 1);
exponential_3n(n - 1);
}
O(n!) Factorial
Memoizing Factorial
let memo = {};
function factorial(n) {
// if this function has calculated factorial(n) previously,
// fetch the stored result in memo
if (n in memo) return memo[n];
if (n === 1) return 1;
// otherwise, it havs not calculated factorial(n) previously,
// so calculate it now, but store the result in case it is
// needed again in the future
memo[n] = n * factorial(n - 1);
return memo[n];
}
factorial(6); // => 720, requires 6 calls
factorial(6); // => 720, requires 1 call
factorial(5); // => 120, requires 1 call
factorial(7); // => 5040, requires 2 calls
memo; // => { '2': 2, '3': 6, '4': 24, '5': 120, '6': 720, '7': 5040 }
Memoizing Fibonacci
The Memoization Formula
Rules
Things to remember
function fastFib(n, memo = {}) {
if (n in memo) return memo[n];
if (n === 1 || n === 2) return 1;
memo[n] = fastFib(n - 1, memo) + fastFib(n - 2, memo);
return memo[n];
}
fastFib(6); // => 8
fastFib(50); // => 12586269025
function fib(n) {
let mostRecentCalcs = [0, 1];
if (n === 0) return mostRecentCalcs[0];
for (let i = 2; i <= n; i++) {
const [secondLast, last] = mostRecentCalcs;
mostRecentCalcs = [last, secondLast + last];
}
return mostRecentCalcs[1];
}
function search(array, term) {
for (let i = 0; i < array.length; i++) {
if (array[i] === term) {
return i;
}
}
return -1;
}
function binarySearch(arr, x, start, end) {
if (start > end) return false;
let mid = Math.floor((start + end) / 2);
if (arr[mid] === x) return true;
if (arr[mid] > x) {
return binarySearch(arr, x, start, mid - 1);
} else {
return binarySearch(arr, x, mid + 1, end);
}
}
function merge(leftArray, rightArray) {
const sorted = [];
while (letArray.length > 0 && rightArray.length > 0) {
const leftItem = leftArray[0];
const rightItem = rightArray[0];
if (leftItem > rightItem) {
sorted.push(rightItem);
rightArray.shift();
} else {
sorted.push(leftItem);
leftArray.shift();
}
}
while (leftArray.length !== 0) {
const value = leftArray.shift();
sorted.push(value);
}
while (rightArray.length !== 0) {
const value = rightArray.shift();
sorted.push(value);
}
return sorted;
}
function mergeSort(array) {
const length = array.length;
if (length === 1) {
return array;
}
const middleIndex = Math.ceil(length / 2);
const leftArray = array.slice(0, middleIndex);
const rightArray = array.slice(middleIndex, length);
leftArray = mergeSort(leftArray);
rightArray = mergeSort(rightArray);
return merge(leftArray, rightArray);
}
function bubbleSort(items) {
var length = items.length;
for (var i = 0; i < length; i++) {
for (var j = 0; j < length - i - 1; j++) {
if (items[j] > items[j + 1]) {
var tmp = items[j];
items[j] = items[j + 1];
items[j + 1] = tmp;
}
}
}
}
Bubbling Up
: Term that infers that an item is in motion, moving in some direction, and has some final resting destination.
Bubble sort, sorts an array of integers by bubbling the largest integer to the top.
// Bubble Sort
function bubble(array) {
let sorted = true;
for (let i = 0; i < array.length; i++) {
let num1 = array[i];
let num2 = array[i + 1];
if (num1 > num2) {
array[i + 1] = num1;
array[i] = num2;
sorted = false;
}
}
if (sorted) {
return array;
} else {
return bubble(array);
}
}
let selectionSort = (arr) => {
let len = arr.length;
for (let i = 0; i < len; i++) {
let min = i;
for (let j = i + 1; j < len; j++) {
if (arr[min] > arr[j]) {
min = j;
}
}
if (min !== i) {
let tmp = arr[i];
arr[i] = arr[min];
arr[min] = tmp;
}
}
return arr;
};
Time Complexity
: Quadratic O(n^2)
Space Complexity
: O(1)
Class Solution
function swap(array, idx1, idx2) {
[array[idx1], array[idx2]] = [array[idx2], array[idx2]];
}
function selectionSort(array) {
for (let i = 0; i < array.length; i++) {
let lowest = i;
for (let j = i + 1; j < array.length; j++) {
if (list[j] < list[lowest]) {
lowest = j;
}
}
if (place !== i) {
swap(array, i, lowest);
}
}
}
Alt Solution
function selectionSort(array) {
for (let i = 0; i < array.length; i++) {
let lowest = i;
for (let j = 0; j < array.length; j++) {
if (array[j] < array[i]) {
lowest = j;
}
}
if (lowest !== i) {
let temp = array[i];
array[i] = array[lowest];
array[lowest] = temp;
}
}
return array;
}
Time Complexity
: Quadratic O(n^2)
Space Complexity
: O(n)
Class Solution
function insertionSort(array) {
for (let i = 1; i < array.length; i++) {
let value = list[i];
let hole = i;
while (hole > 0 && list[hole - 1] > value) {
list[hole] = list[hole - 1];
hole--;
}
list[hole] = value;
}
return array;
}
Alt Solution
function insertionSort(arr) {
for (let i = 1; i < arr.length; i++) {
let current = arr[i];
let j = i - 1;
while (j > -1 && current < arr[j]) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = current;
}
return arr;
}
Time Complexity
: Log Linear O(nlog(n))
Space Complexity
: O(n)Class Solution
function merge(arr1, arr2) {
let result = [];
while (arr1.length && arr2.length) {
if (arr1[0] < arr2[0]) {
result.push(arr1.shift());
} else {
result.push(arr2.shift());
}
}
return [...result, ...arr1, ...arr2];
}
function mergeSort(arr) {
if (arr.length <= 1) return arr;
const mid = Math.floor(arr.length / 2);
const left = mergeSort(arr.slice(0, mid));
const right = mergeSort(arr.slice(mid));
return merge(left, right);
}
Time Complexity
: Quadratic O(n^2)
Space Complexity
: O(n)
function quickSort(array) {
if (array.length <= 1) return array;
let pivot = array.shift();
let left = array.filter((x) => x < pivot);
let right = array.filter((x) => x >= pivot);
let sortedLeft = quickSort(left);
let sortedRight = quickSort(right);
return [...sortedLeft, pivot, ...sortedRight];
}
Time Complexity
: Log Time O(log(n))
Space Complexity
: O(1)
Recursive Solution
function binarySearch(array, target) {
if (array.length === 0) return false;
let midPt = Math.floor(array.length / 2);
if (array[midPt] === target) {
return true;
} else if (list[midPt] > target) {
return binarySearch(list.slice(0, mid), target);
} else {
return binarySearch(list.slice(midPt + 1), target);
}
}
Min Max Solution
function binarySearch(array, target) {
let start = 0;
let end = array.length - 1;
while (start <= end) {
let midpoint = Math.floor((start + end) / 2);
if (target === array[midpoint]) {
return midpoint;
}
if (target > array[midpoint]) {
start = midpoint + 1;
}
if (target < array[midpoint]) {
end = midpoint - 1;
}
}
return -1;
}
let insertionSort = (inputArr) => {
let length = inputArr.length;
for (let i = 1; i < length; i++) {
let key = inputArr[i];
let j = i - 1;
while (j >= 0 && inputArr[j] > key) {
inputArr[j + 1] = inputArr[j];
j = j - 1;
}
inputArr[j + 1] = key;
}
return inputArr;
};
const merge = (arr1, arr2) => {
let sorted = [];
while (arr1.length && arr2.length) {
if (arr1[0] < arr2[0]) sorted.push(arr1.shift());
else sorted.push(arr2.shift());
}
return sorted.concat(arr1.slice().concat(arr2.slice()));
};
const mergeSort = (arr) => {
if (arr.length <= 1) return arr;
let mid = Math.floor(arr.length / 2),
left = mergeSort(arr.slice(0, mid)),
right = mergeSort(arr.slice(mid));
return merge(left, right);
};
function quick_Sort(origArray) {
if (origArray.length <= 1) {
return origArray;
} else {
var left = [];
var right = [];
var newArray = [];
var pivot = origArray.pop();
var length = origArray.length;
for (var i = 0; i < length; i++) {
if (origArray[i] <= pivot) {
left.push(origArray[i]);
} else {
right.push(origArray[i]);
}
}
return newArray.concat(quick_Sort(left), pivot, quick_Sort(right));
}
}
binary search
const binarySearch = (array, target) => {
let startIndex = 0;
let endIndex = array.length - 1;
while(startIndex <= endIndex) {
let middleIndex = Math.floor((startIndex + endIndex) / 2);
if(target === array[middleIndex) {
return console.log("Target was found at index " + middleIndex);
}
if(target > array[middleIndex]) {
console.log("Searching the right side of Array")
startIndex = middleIndex + 1;
}
if(target < array[middleIndex]) {
console.log("Searching the left side of array")
endIndex = middleIndex - 1;
}
else {
console.log("Not Found this loop iteration. Looping another iteration.")
}
}
console.log("Target value not found in array");
}
linked list
represents a linear sequence of ‘vertices’ or ‘nodes’ and tracks three properties.
Head
: The first node in the list.Tail
: The last node in the list.Length
: The number of nodes in the list; the list’s length.Nodes
: Simpler, smaller data structure that connects the linked list.Value
: THe actual value this node represents.Next
: The next node in the list (relative to this node).Previous
: The previous node in the list (relative to this node).