For your GitHub Profile: Which three of the following are part of a high quality README?
#1, #2, #4 : EXPLANATION
The README for your project should be about the project. Therefore, your personal bio belongs elsewhere.
What does "MVP" stand for in the context of planning and documenting the work in your github repo?
#4 EXPLANATION
Your MVP is the minimum viable product that it takes to "go to market", even if "market" just means sharing it with other people.
What is "starring" at GitHub?
#2 EXPLANATION
Look at the top of the repository pages. Those stars mean popularity! Don't you want to be popular? Get people to "star" your repository for fame and success! (:shrug:)
Which three of the following are ways App Academy students and grads bolster their perceived understanding of the software engineering world via GitHub?
#1, #2, #4 :EXPLANATION
Having a single repository is like showing up for school without being prepared. Many focused repositories, even if they're old, can show that you're interested in this craft of software engineering.
Which represents correct markdown syntax for adding a multiline code snippet to your README?
#2 EXPLANATION
It's all about the backticks. Those indicate that it should be considered code.
What is the main reason for having a strong GitHub profile?
#3 EXPLANATION
If code is about people, then GitHub is the social platform on which that happens. Your profile on GitHub speaks about who you are, what your interests are in, and shows the type of code you can create.
Order the common complexity classes according to their growth rate:
Name | Big O Notation |
---|---|
Linear Logorithmic | O(1) |
Factorial | O(n) |
Polynomial | O(log(n)) |
Linear | O(n!) |
Constant | O(mn) |
Exponential | O(n*log(n)) |
Logarithmic | O(nm) |
ANSWER
Name | Big O Notation |
---|---|
Constant | O(1) |
Logarithmic | O(log(n)) |
Linear | O(n) |
Linear Logarithmic | O(n*log(n)) |
Polynomial | O(nm) |
Exponential | O(mn) |
Factorial | O(n!) |
What is the Big-O notation for the Polynomial complexity class?
O(nm)
What is the Big-O notation for the Exponential complexity class?
O(mn)
What is the Big-O notation for the Logarithmic complexity class?
O(log(n))
What is the Big-O notation for the Linear complexity class?
O(n)
What is the Big-O notation for the Loglinear complexity class?
O(n*log(n))
What is the Big-O notation for the Constant complexity class?
O(1)
Order the following complexity classes from most efficient to most complex:
What is the time complexity of the following code?
function myFunction(n) {
return n * 2 + 1;
}
Constant : O(1)
What is the time complexity of the following code?
function myFunction(n) {
for (let i = 1; i <= 100; i++) {
console.log(i);
}
}
O(1) : Constant; Why? Because there are a fixed number of loops in the for loop. The for loop is not dependent upon n.
What is the time complexity of the following code?
function myFunction(n) {
if (n <= 1) return;
myFunction( n / 2);
}
logarithmic: O(log(n)) : because the recursion will half the size of n each time
What is the time complexity of the following code?
function myFunction(n) {
let i = n;
while (i > 1) {
i /= 2;
}
}
logarithmic: O(log(n)) : Because the while loop will half the size of n each time.
What is the time complexity of the following code?
function myFunction(n) {
for (let i = 1; i <= n; i++) {
console.log(i);
}
}
Linear : O(n) : Because the for loop will iterate n times
What is the time complexity of the following code?
function myFunction(n) {
if (n===1) return;
myFunction(n - 1)
}
Linear : O(n) : Because the recursive call will be made n times.
What is the time complexity of the following code?
function myFunction(n) {
if (n <= 1) return;
for (let i = 1; i <= n; i++) {
console.log(i);
}
myFunction(n/2);
myFunction(n/2);
}
O(n * log(n)) : LogLinear because the for loop will run n times; then the myFunction will be called recursively 2(log(n)) so we can drop the constant and consider log(n). Combining the for loop time complexity of O(n) and the recursive calls of log(n) we have O(n*log(n));
What is the time complexity of the following code?
function myFunction(n) {
for (let i = 1; i <= n; i++) {
for (let j = 1; j <= n; j++) {}
}
}
Polynomial : O(n2) : The outer loop will run n times; but for every time the outler loop runs, the inner loop will run n times; n * n = n2 so we have O(n2)
What is the time complexity of the following code?
function myFunction(n) {
for (let i = 1; i <= n; i++) {
for (let j = 1; j <= n; j++) {
for (let k = 1; k <= n; k++) {}
}
}
}
Polynomial O(n3) : Because the outer for (i) will run n times, and for each time the outer loop runs the inner (j) will run n times - which is n * n - and there's another inner loop (k) that will run n times - so we have n*n*n which is n3 so we have O(n3)
What is the time complexity of the following code?
function myFunction(n) {
if (n === 1) return;
myFunction(n - 1);
myFunction(n - 1);
}
Exponential : O(2n) : Because each call will make two more recursive calls so they will run a total of 2n times, or O(2n)
What is the time complexity of the following code?
function myFunction(n) {
if (n === 0) return;
myFunction(n - 1);
myFunction(n - 1);
myFunction(n - 1);
}
Exponential : O(3n) : Because each call will make 3 more recursive calls, n times.
What is the time complexity of the following code?
function myFunction(n) {
if (n === 1) return;
for (let i = 1; i <= n; i++) {
myFunction(n - 1);
}
}
Factorial : O(n!) : The code is recursive, but the number of recursive calls made in a a single stack frame depends on the input. So in this case, the for loop executes n times; but within the for loop the recursive call is made n-1 times. So you have n * n-1 * n-2 * n-3 ... or O(n!);
Identify the type of sort, the time complexity, and the space complexity of the following code:
function swap(array, idx1, idx2) {
[array[idx1], array[idx2]] = [array[idx2], array[idx1]]
}
function whichSort(array) {
let swapped = true;
while (swapped) {
swapped = false;
for (let i = 0; i < array.length; i++) {
if (array[i] > array[i + 1]) {
swap(array, i, i + 1);
swapped = true;
}
}
}
}
Bubble Sort. Time complexity O(n2); Space Complexity of O(1)
Identify the type of sort as well as the time and space complexity of the following code:
function swap(arr, index1, index2) {
[arr[index1], arr[index2]] =arr[index2], arr[index1]];
}
function whichSort(list) {
for (let i = 0; i < list.length; i++) {
let min = i;
for (let j = i+1; j < list.length; j++) {
if (list[j] < list[min]) {
min = j;
}
}
if (min !== i) {
swap(list, i, min);
}
}
}
Selection Sort : Time complexity O(n2) and O(1) space complexity
Identify the type of sort, as well as the time and space complexity of the following code:
function mySort(list) {
for (let i = 1; i < list.length; i++) {
value = list[i];
hole = i;
while (hole > 0 && list[hole - 1] > value) {
list[hole] = list[hole - 1];
hole--;
}
list[hole] = value;
}
}
Insertion Sort. Time Complexity: O(n2), Space complexity: O(1)
Identify the type of sort, as well as its time and space complexity for the code below:
function doSomething(array1, array2) {
let result = []
while (array1.length && array2.length) {
if (array1[0] < array2[0]) {
result.push(array1.shift());
} else {
result.push(array2.shift());
}
}
return [...result, ...array1, ...array2];
}
function sortSomething(array) {
if (array.length <= 1) return array;
const mid = Math.floor(array.length / 2);
const left = sortSomething(array.slice(0, mid));
const right = sortSomething(array.slice(mid));
return doSomething(left, right);
}
Merge Sort : Time Complexity O(n log(n)) since we split the array in half each time, the number of calls is O(log(n). The while loop inside the doSomething (aka merge) method will go through all of the array - n times. So it's O(n * log(n));
Space complexity is O(n), because we are copying the array n times. [Yes, there are two copies, but each is half of the array.]
Identify the type of sort, the time and space complexity of the sort in the following code:
function mySort(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 = mySort(left);
let sortedRight = mySort(right);
return [...sortedLeft, pivot, ...sortedRight];
}
QuickSort: Time complexity of O(n2) because sort on the left is O(n) and sort on the right is O(n).
Space complexity of Quick Sort is O(n);
Identify the type of sort below, and it's time and space complexities:
function anotherSearch(list, target) {
if (list.length === 0) return false;
let mid = Math.floor(list.length / 2);
if (list[mid] === target) {
return true;
} else if (list[mid] > target) {
return anotherSearch(list.slice(0, mid), target);
} else {
return anotherSearch(list.slice(mid + 1), target);
}
}
Binary Search - Time complexity O(log(n));
Space complexity O(n)
Transform the following fibonacci function to use memoization to reduce the time complexity from polynomial time:
const fibonacci = (n) => {
if ((n === 1) || (n === 2)) {
return 1;
}
return fibonacci(n-1) + fibonacci(n - 2);
}
const fibonacci = (n, memo = {0: 0, 1:1} ) => {
if (n in memo) return memo[n];
memo[n] = fibonacci(n-1, memo) + fibonacci(n - 2, memo);
return memo[n];
};
Apply tabulation to the iterative version of fibonacci to make it less than polynomial time:
function fibonacci(n) {
let previouspreviousNumber = 0;
let previousNumber = 0;
let currentNumber = 1;
for (let i = 1; i < n; i++) {
previouspreviousNumber = previousNumber;
previousNumber = currentNumber;
currentNumber = previouspreviousNumber + previousNumber;
}
return currentNumber;
}
function fibonacci(n) {
let table = new Array(n);
table[0] = 0;
table[1] = 1;
for (let i = 2; i <= n; i += 1) {
table[i] = table[i-1] + table[i-2];
}
return table[n];
}
Explain the complexity of and write a function that performs insertion sort on an array of numbers
Time complexity: O(n2); The outer loop i contributes O(n) in isolation. The inner while loop will contribute roughly O(n/2) on average. The two loops are nested so our total time complexity is O(n * n / 2) = O(n2).
Space Complexity: O(1); We use the same amount of memory and create the same amount of variables regardless of the size of our input.
function insertionSort(list) {
for (let i = 1; i < list.length; i++) {
value = list[i];
hole = i;
while (hole > 0 && list[hole - 1] > value) {
list[hole] = list[hole - 1];
hole--;
}
list[hole] = value;
}
}
Explain the complexity of and write a function that performs merge sort on an array of numbers.
Time Complexity: O(n * log(n)); Since we split the array in half each time, the number of recursive calls is O(log(n)). The while loop within the merge function contributes O(n) in isolation and we call that for every recursive mergeSort call.
Space Complexity: O(n) : We will create a new subarray for each element in the original input.
function merge(array1, array2) {
let result = [];
while (array1.length && array2.length) {
if (array1[0] < array2[0]) {
result.push(array1.shift());
} else {
result.push(array2.shift());
}
}
return [...result, ...array1, ...array2];
}
function mergeSort(array) {
if (array.length <= 1) return array;
const mid = Math.floor(array.length / 2);
const left = mergeSort(array.slice(0, mid));
const right = mergeSort(array.slice(mid));
return merge(left, right);
}
Explain the complexity of and write a function that performs quick sort on an array of numbers.
Time Complexity: Avg Case: O(n log(n)) : The partition step alone is O(n). We are lucky and always choose the median as the pivot. This will halve the array length at every step of the recursion for O(log(n)).
Worst Case: O(n2): We are unlucky and always choose the min or max as the pivot. This means one partition will contain everything, and the other partition is empty, yielding O(n).
Space Complexity: O(n) : Our implementation of quickSort uses O(n) space because of the partition arrays we create.
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];
}
Explain the complexity of and write a function that performs a binary search on a sorted array of numbers.
Time Complexity: O(log(n)) : The number of recursive calls is the number of times we must halve the array until it's length becomes 0.
Space Complexity: O(n) : Our implementation uses n space due to half arrays we create using slice.
function binarySearch(list, target) {
if (list.length === 0) return false;
let mid = Math.floor(list.length / 2;
if (list[mid] === target) {
return true;
} else if (list[mid] > target) {
return binarySearch(list.slice(0, mid, target);
} else {
return binarySearch(list.slice(mid+1), target);
}
}
For a linked list comprised of a Node class and a List class, what properties will the list and node require?
List: head, tail; length;
Node: value; next;
For a linked list class implementation, what methods will the linked list class require?
What type of data structure is a stack?
LIFO : Last in (goes on top of the stack), Last out (removed from top of the stack)
When implementing a stack, define the properties needed on both the Node and Stack classes.
Node: value; next;
Stack: top; length;
When implementing a stack, define the methods you will need for the stack.
What type of data structure is a queue?
FIFO : First in First Out;
What properties would you need on the Node and Queue classes?
Node: value; next;
Queue: front; back; length;
What methods would you need on the queue class?
Explain in words the algorithm for bubbleSort
bubbleSort will look at every element of the array, comparing it to the next element. If the next element is smaller, we will swap that element. We continue that to the end of the array. Each time we swap we set swapped to true. We continue iterating through the array until we've made it all the way through the array without swapping any elements.
Explain in words how the selection sort works.
Selection Sort is very similar to Bubble Sort. The major difference between the two is that Bubble Sort bubbles the largest elements up to the end of the array, while Selection Sort selects the smallest elements of the array and directly places them at the beginning of the array in sorted position. Selection sort will utilize swapping just as bubble sort did.
Explain in words what insertion sort does.
Insertion Sort is similar to Selection Sort in that it gradually builds up a larger and larger sorted region at the left-most end of the array. However, Insertion Sort differs from Selection Sort because this algorithm does not focus on searching for the right element to place (the next smallest in our Selection Sort) on each pass through the array. Instead, it focuses on sorting each element in the order they appear from left to right, regardless of their value, and inserting them in the most appropriate position in the sorted region.
Describe merge sort in words
Merge sort is based on the premise that it's easy to merge elements of two sorted arrays into a single sorted array. This screams recursion, with your base case being an empty array. Also, if there's only one element in the array you can consider that array as sorted.
Describe the merge sort high-level steps
Describe binary search in words
Binary search only works on sorted trees or lists. Cut the list in half, look at the end element of the left half and if it's greater than what you're looking for, choose your next search for the right element. Otherwise, choose your lefthalf for your next search. Rinse and repeat.
Take for example, using the binary search algorithm on an array of integers:
Looking for the element 5, will cut your search space in 1/2 with each attempt: