Code-Alongs - Web Unit 3 Sprint 12
Code-Along Overview
In these code-along sessions, you'll work through practical examples and implementations of the concepts covered in the modules. These hands-on experiences will reinforce your learning and provide you with real-world problem-solving skills essential for technical interviews and professional development.
Code-Along Sessions
1. Big O Analysis and Caching
Learn how to analyze algorithm complexity and implement caching strategies through practical examples.
Key Concepts Covered:
- Identifying time and space complexity of algorithms
- Optimizing performance through caching
- Implementing memoization for recursive functions
- Comparing algorithms with different complexity classes
Code Example - Fibonacci with Caching:
// Naive recursive implementation - O(2^n) time complexity
function fibonacciSlow(n) {
if (n <= 1) return n;
return fibonacciSlow(n - 1) + fibonacciSlow(n - 2);
}
// Optimized implementation with caching - O(n) time complexity
function fibonacciFast(n, memo = {}) {
// Check if we've already calculated this value
if (n in memo) return memo[n];
// Base cases
if (n <= 1) return n;
// Calculate and cache the result
memo[n] = fibonacciFast(n-1, memo) + fibonacciFast(n-2, memo);
return memo[n];
}
// Performance comparison
console.time('Slow Fibonacci');
console.log(fibonacciSlow(30)); // Very slow!
console.timeEnd('Slow Fibonacci');
console.time('Fast Fibonacci');
console.log(fibonacciFast(30)); // Much faster!
console.timeEnd('Fast Fibonacci');
2. Linked Lists Implementation
Follow along as we implement a linked list data structure from scratch and explore common operations.
Key Concepts Covered:
- Understanding linked list structure and properties
- Implementing node creation and linking
- Adding, removing, and finding elements
- Traversing a linked list
- Comparing linked lists with arrays
Code Example - Linked List Implementation:
class Node {
constructor(value) {
this.value = value;
this.next = null;
}
}
class LinkedList {
constructor() {
this.head = null;
this.tail = null;
this.length = 0;
}
append(value) {
const newNode = new Node(value);
if (!this.head) {
this.head = newNode;
this.tail = newNode;
} else {
this.tail.next = newNode;
this.tail = newNode;
}
this.length++;
return this;
}
prepend(value) {
const newNode = new Node(value);
if (!this.head) {
this.head = newNode;
this.tail = newNode;
} else {
newNode.next = this.head;
this.head = newNode;
}
this.length++;
return this;
}
delete(value) {
if (!this.head) return null;
if (this.head.value === value) {
this.head = this.head.next;
this.length--;
if (this.length === 0) {
this.tail = null;
}
return true;
}
let current = this.head;
while (current.next && current.next.value !== value) {
current = current.next;
}
if (current.next) {
if (current.next === this.tail) {
this.tail = current;
}
current.next = current.next.next;
this.length--;
return true;
}
return false;
}
find(value) {
if (!this.head) return null;
let current = this.head;
while (current) {
if (current.value === value) {
return current;
}
current = current.next;
}
return null;
}
toArray() {
const array = [];
let current = this.head;
while (current) {
array.push(current.value);
current = current.next;
}
return array;
}
}
// Usage example
const list = new LinkedList();
list.append(10).append(20).append(30).prepend(5);
console.log(list.toArray()); // [5, 10, 20, 30]
list.delete(20);
console.log(list.toArray()); // [5, 10, 30]
console.log(list.find(10)); // Node { value: 10, next: Node }