DSA CONCEPTS - rs-hash/GETTHATJOB GitHub Wiki
π Big O Notation Cheatsheet
Big O notation describes the time or space complexity of an algorithm in terms of how it scales with input size n.
π Common Complexities
| Complexity | Name | Description | Example Use Cases |
|---|---|---|---|
O(1) |
Constant | Executes in the same time regardless of n |
Accessing array element |
O(log n) |
Logarithmic | Cuts problem size in half each step | Binary search |
O(n) |
Linear | Grows proportionally with input size | Looping through an array |
O(n log n) |
Linearithmic | Slightly worse than linear | Merge sort, Quicksort (avg case) |
O(nΒ²) |
Quadratic | Nested loops over the same input | Bubble sort, selection sort |
O(2^n) |
Exponential | Doubles with each addition to input | Recursive Fibonacci |
O(n!) |
Factorial | All permutations of input | Traveling salesman, brute-force |
π§ Quick Rules
- Drop constants β
O(2n + 5)βO(n) - Keep highest-order term β
O(nΒ² + n)βO(nΒ²) - Micro-optimizations < Algorithm design
π Real-World Examples
| Algorithm | Time Complexity |
|---|---|
| Array indexing | O(1) |
| Hash map lookup | O(1) (avg), O(n) (worst) |
| Linear search | O(n) |
| Binary search | O(log n) |
| Merge sort | O(n log n) |
| Bubble sort | O(nΒ²) |
| Recursive Fibonacci | O(2^n) |
| Traveling salesman | O(n!) |
π Growth Comparison
n |
O(1) |
O(log n) |
O(n) |
O(n log n) |
O(nΒ²) |
O(2^n) |
O(n!) |
|---|---|---|---|---|---|---|---|
| 10 | 1 | 3.3 | 10 | 33 | 100 | 1024 | 3,628,800 |
| 100 | 1 | 6.6 | 100 | 660 | 10,000 | 1.27e30 | ~9e157 |
| 1,000 | 1 | 9.9 | 1,000 | 9,900 | 1,000,000 | β | β |
π© When to Worry
- Avoid
O(nΒ²)or worse for large datasets - Prefer
O(log n)orO(n)for scalability - Watch out for hidden costs: API calls, recursion, memory
π§Ύ Notations Reference
- O β Upper bound (worst-case)
- Ξ© (Omega) β Lower bound (best-case)
- Ξ (Theta) β Tight bound (average-case)
π Tip: Use tools like Big-O Cheat Sheet to compare algorithms visually.
π Big O Notation with JavaScript Code Examples
This guide provides common time complexities using Big O notation and example JavaScript functions. Perfect for interviews, notes, or GitHub Wiki use.
π© O(1) - Constant Time
The runtime does not increase with input size.
function getFirstItem(arr) {
return arr[0];
}
π© O(log n) β Logarithmic Time (Binary Search)
The array size is halved each time (n β n/2 β n/4 β ...).
function binarySearch(arr, target) {
let left = 0; // O(1) - initialize left pointer
let right = arr.length - 1; // O(1) - initialize right pointer
// The loop runs while there's a search space to consider
// Each iteration halves the remaining array β O(log n)
while (left <= right) {
const mid = Math.floor((left + right) / 2); // O(1) - find midpoint
if (arr[mid] === target) return mid; // O(1) - compare with target
if (arr[mid] < target) left = mid + 1; // O(1) - search in right half
else right = mid - 1; // O(1) - search in left half
}
return -1; // O(1) - target not found
}
π© Merge Sort β O(n log n)
log n recursion levels (dividing array in half each time)
n work per level (merging all elements back together)
β Total = O(n log n)
function mergeSort(arr) {
if (arr.length <= 1) return arr; // Base case β O(1)
const mid = Math.floor(arr.length / 2); // Divide β O(1)
const left = mergeSort(arr.slice(0, mid)); // Recurse left β O(log n)
const right = mergeSort(arr.slice(mid)); // Recurse right β O(log n)
return merge(left, right); // Merge two halves β O(n)
}
function merge(left, right) {
const result = []; // O(1)
// While both arrays have elements
while (left.length && right.length) {
// Push the smaller element and remove it from its array β O(1)
result.push(left[0] < right[0] ? left.shift() : right.shift());
}
// Concatenate leftover elements β O(n)
return result.concat(left, right);
}
π© O(2βΏ) β Exponential Time
he recursion tree grows exponentially β each level doubles the number of calls
function fibonacci(n) {
// Each call generates two more calls β exponential growth
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2); // O(2βΏ)
}
π©O(n!) β Factorial Time
For a string of length n, we generate n! permutations.
function getPermutations(str) {
// Base case: a single permutation
if (str.length <= 1) return [str];
const result = [];
// Generate all permutations
for (let i = 0; i < str.length; i++) {
const char = str[i];
const remaining = str.slice(0, i) + str.slice(i + 1);
const subPerms = getPermutations(remaining); // O((n-1)!)
for (const perm of subPerms) {
result.push(char + perm); // Combine permutations
}
}
return result; // Total permutations = n!
}
π© O(nΒ²) β Quadratic Time
For each element, we loop over the entire array again.
function printAllPairs(arr) {
// Nested loop β O(nΒ²)
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr.length; j++) {
console.log(arr[i], arr[j]); // O(1) per pair
}
}
}
π© O(n) β Linear Time
The function processes every element exactly once
function printAllItems(arr) {
// Visit each element once β O(n)
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]); // O(1) per item
}
}