Fundamentals
fundamentals
Foundations
Algorithms and Efficiency
You already know how to write code that works. But here is a question most beginners never ask: *does it matter how you solve it?* If two programs both give the correct answer, are they equally good? The answer, it turns out, is a decisive no -- and understanding why is the foundation of everything in this course. **Algorithms and Efficiency** is the opening lesson of the DSA Foundations track. Rather than jumping straight into notation or formulas, it starts with a simple, concrete idea: different solutions to the same problem can do very different amounts of work, and that gap in effort becomes enormous once your input is large. You will see two approaches to finding the maximum number in a list, watch the operation counts diverge as the list grows, and come away with a clear intuition for what "efficiency" means in practice. No O() notation yet -- just the honest, visual realization that some code does way more work than it needs to. This lesson bridges everything you already know about writing code to the new skill of *reasoning about* code. You can write loops, call functions, and store values in variables -- that is all you need. By the end, you will have a concrete sense of what engineers mean when they say one algorithm is "better" than another, and you will understand exactly why input size is the key variable in that judgment. Next up is **Counting Operations** (lesson 2), where you will formalize the intuition you build here by learning to count steps precisely as a function of the input size `n`. From there, the track moves into Asymptotic Analysis and Big-O Notation -- the symbolic language the entire industry uses to express these ideas.
Not Started
0%
Asymptotic Analysis Fundamentals
How can you tell which of two algorithms will scale to a million inputs without ever running them on real hardware? Wall-clock timing fails this test because it depends on your CPU, your language, and even what other apps are open, so we need a more durable measure of efficiency. The word *asymptotic* looks intimidating, but the idea behind it is simple: it describes how a function behaves as its input grows very large. **Asymptotic Analysis Fundamentals** uses that idea to build a hardware-independent measure of efficiency — by counting how the number of operations an algorithm performs grows as the input size `n` increases, you get a yardstick that works regardless of your CPU, language, or environment. You will see why basic operation counting beats stopwatch timing, how growth rates rank from constant to exponential, why constant factors and lower-order terms drop out of the analysis, and what it really means for `n` to represent the size of an input. In **Counting Operations**, you built the habit of tracing through code and tallying how many steps it performs as input size `n` grows. Every operation count you produced there — a loop running `n` times, nested loops running `n * n` times — becomes exactly the formula this lesson formalizes. Asymptotic analysis is the language that turns those raw counts into a precise, hardware-independent way to compare algorithms. Once you are comfortable thinking in growth rates, you will be ready for **Big-O Notation (Upper Bound)**, the formal symbolic language (think `O(n)`, `O(n^2)`, `O(log n)`) used everywhere in textbooks, interviews, and engineering documentation to express the ideas you build here.
Not Started
0%
Big-O Notation (Upper Bound)
How do you compare two solutions to the same problem without ever running them on real hardware? Big-O is the symbolic shorthand that the entire industry uses to do exactly that, and it is the single most referenced notation in textbooks, technical interviews, and engineering documentation. **Big-O Notation (Upper Bound)** turns the growth-rate ideas you have been thinking about into precise notation. You will see what `O(f(n))` formally means as an upper bound, walk through the seven complexity classes you will meet again and again (`O(1)`, `O(log n)`, `O(n)`, `O(n log n)`, `O(n^2)`, `O(2^n)`, `O(n!)`), and learn the rules for reading Big-O straight from code: single loops, nested loops, sequential blocks, conditional branches, and inputs with multiple variables like `O(n + m)` and `O(n * m)`. You will also meet best, worst, and average case analysis so you know which scenario a Big-O statement is describing. In **Asymptotic Analysis Fundamentals**, you saw why we count operations as a function of input size `n`, why constants and lower-order terms drop away, and how growth rates rank from constant to exponential. Big-O is the formal language for everything you reasoned about there: each growth-rate intuition becomes a concrete `O(...)` expression. Once you can classify code by sight, you will be ready for **Time Complexity Analysis Techniques**, where you will apply these rules to longer, more realistic snippets and develop a systematic analysis workflow.
Not Started
0%
Combinatorics Basics
How many ways can you arrange `n` items? How many subsets does a set of size `n` have? Questions like these are not idle puzzles, they are exactly the questions you have to answer to know whether a brute-force solution will run in milliseconds or in millennia. **Combinatorics Basics** gives you the counting tools that turn vague statements like "try every possibility" into precise complexity claims. This lesson covers the four counting ideas you will rely on throughout DSA. The **rule of sum** and **rule of product** let you decompose multi-step processes and count outcomes; **permutations** count ordered arrangements (`n!` for arranging all of them, `nPr` for choosing `r` in order); **combinations** count unordered selections (`nCr`, also written as binomial coefficients); and **Pascal's triangle** plus a first look at **basic probability** tie everything together. You will see why a set of size `n` has `2^n` subsets, why generating all permutations of an array is `O(n!)`, and how counting principles directly produce the time complexity of backtracking algorithms. This lesson builds on **Discrete Mathematics Basics**, where you formalized sets, set operations, and logic. Combinatorics is what happens when you start asking "how many?" about those sets, ordered or unordered, with or without repetition. With the counting toolkit in place you will continue the math track in **Number Theory Fundamentals**, picking up primes, divisibility, and `gcd`, the other half of the math you need for hashing, cryptography-style problems, and modular arithmetic.
Not Started
0%
Counting Operations
In **Algorithms and Efficiency** you saw the core question: when two programs solve the same problem, how do you know which one scales better? The answer lies in *counting*. Before any formal notation, before any mathematical symbols, there is a hands-on skill that every strong programmer develops: looking at a piece of code and tallying the work it performs as the input grows. **Counting Operations** teaches exactly that skill. You will learn what counts as a single operation, how to trace a loop and tally its iterations, how to build an operations table that reveals the relationship between input size and work, and what happens when loops are nested. By the end of this lesson you will be able to look at a code snippet and say: "for input size n = 10 this runs about 10 steps; for n = 100, about 100 steps; for n = 1000, about 1000 steps" and mean it precisely. You will also compare two solutions to the same problem side by side -- counting operations for each as n grows -- and experience the lightbulb moment: when inputs are small both solutions feel fine, but as n climbs the difference becomes impossible to ignore. That concrete, tangible understanding of scaling behaviour is the foundation everything else rests on. In the next lesson, **Asymptotic Analysis Fundamentals**, you will take exactly these operation counts and formalize them with the mathematical framework that makes comparison rigorous. Everything you practice counting here becomes the raw material for the O() notation and growth-rate rankings you will learn there.
Not Started
0%
Debugging by Tracing
Most beginners debug by staring at their code and hoping the bug reveals itself. Engineers who ship working software do something different: they trace execution one line at a time, watch each variable, and pinpoint the exact moment the program's state stops matching their mental model. That motion is a learnable, repeatable skill. **Debugging by Tracing** turns that skill into a structured workflow. You will define what program state actually is (the values of every variable plus the current line of execution), practice walking through a function step by step recording each change, and learn to use loop invariants (conditions that must hold before and after every iteration) to verify correctness without running the code. You will work through a systematic process of reproduce, trace, locate, fix, and verify, and you will see the most common beginner pitfalls including off-by-one errors, uninitialized variables, and misordered swaps. In **How to Read Code (JS & Python)**, you practiced tracing variables through `for` and `while` loops and stepping through function calls on the call stack. This lesson takes that same tracing motion and aims it at a specific goal: finding the line where a bug first introduces wrong state, instead of just understanding what correct code is doing. With Tier 1 essentials behind you, you will be ready to dive into the data structures track starting with **Arrays & Strings**, where every algorithm you write will benefit from being traceable and provably correct.
Not Started
0%
Discrete Mathematics Basics
Almost every conditional you have ever written is a tiny piece of propositional logic, and almost every collection you have ever stored is, mathematically, a set. **Discrete Mathematics Basics** makes that connection explicit, giving you the formal vocabulary that data structures, graph algorithms, database queries, and correctness arguments all sit on top of. This lesson walks you through three pillars of discrete math used throughout DSA. First, **sets** and the operations on them: union, intersection, difference, complement, subset, and membership, the same ideas baked into hash sets and array problems. Second, **propositional logic**: the operators `AND`, `OR`, `NOT`, and implication, plus truth tables for evaluating compound expressions; this is the math behind every Boolean condition in your code. Third, **binary relations** and their properties (reflexive, symmetric, transitive), which generalize the way edges connect nodes in graphs and rows connect in databases. Along the way you will get a first taste of formal proof: how to argue that two sets are equal or that a logical equivalence always holds. This lesson assumes only basic programming familiarity, so no specific DSA prerequisite is required. If you have written `if (x && !y)` or used a hash set, you already have informal intuition for everything we will formalize here. From here you will move into **Combinatorics Basics**, where you will use these set and counting foundations to count permutations, combinations, and arrangements (the math behind backtracking and many complexity proofs).
Not Started
0%
Logarithms & Exponentiation
How can a search through a million sorted items finish in roughly twenty comparisons? The answer is `log_2(n)`, and once you internalize what that expression really means, an entire family of fast algorithms (binary search, balanced trees, divide-and-conquer) suddenly stops feeling like magic. **Logarithms & Exponentiation** builds your intuition for the math behind `O(log n)`. You will start from a concrete framing (a logarithm answers the question "how many times can I halve `n` before reaching 1?") and work through the powers-of-2 sequence (1, 2, 4, 8, 16, ...) that appears constantly in computer science. You will pick up the three logarithm properties you actually need (`log(a * b) = log(a) + log(b)`, `log(a^n) = n * log(a)`, and `log(1) = 0`), see why the base does not matter inside Big-O, meet fast exponentiation as a preview of `O(log n)` in action, and trace why every halving loop produces logarithmic complexity. In **Big-O Notation (Upper Bound)**, you learned that `O(log n)` sits between `O(1)` and `O(n)` in the hierarchy and is associated with algorithms that halve their work each step. This lesson supplies the mathematical reason that pattern produces a logarithm, so the complexity class stops being something you memorize and starts being something you can derive. Once logarithms feel comfortable, you will be ready for **Mathematical Sequences**, where you will study arithmetic sums, geometric series, and Fibonacci patterns that explain the running times of everything from nested loops to recursive algorithms.
Not Started
0%
Mathematical Sequences
Why is a triangular nested loop that does `1 + 2 + 3 + ... + n` units of work classified as `O(n^2)` rather than `O(n)`? Because the closed form of that sum is `n(n+1)/2`, which grows quadratically. The same kind of summation argument explains why merge sort is `O(n log n)`, why a doubling array gives amortized `O(1)` insertions, and why naive recursive Fibonacci is exponentially slow. **Mathematical Sequences** equips you with the essential sequences and summation formulas behind algorithm analysis. You will work with arithmetic sequences (where each term adds a constant) and the formula `1 + 2 + ... + n = n(n+1)/2`, geometric sequences (where each term multiplies by a constant ratio) and their geometric-series sum, and the Fibonacci sequence defined by `F(n) = F(n-1) + F(n-2)`. You will then connect these formulas back to code: triangular nested loops, halving-and-doubling patterns, and the canonical recursive Fibonacci that motivates dynamic programming. In **Big-O Notation (Upper Bound)**, you learned to spot dominant terms and to drop constants and lower-order terms. This lesson supplies the closed-form summations that turn a step count like `1 + 2 + ... + n` into a precise polynomial you can simplify with confidence. With these summation tools in hand, you will be ready for **Debugging by Tracing**, where you will sharpen the step-by-step execution skills you need to verify that the algorithms you analyze actually behave the way your formulas predict.
Not Started
0%
Memory Models
Why does a deeply recursive function crash with a stack overflow while an equivalent loop happily processes a million elements? Why does passing an array into a function sometimes mutate the caller's data and sometimes not? The answers all live one level below your code, in the runtime **memory model** that decides where every variable, object, and function call physically lives. This lesson opens up that model. You will see the difference between the **stack** (small, fast, organized into per-call frames) and the **heap** (larger, manually or garbage-collected, where objects and arrays actually live), watch how every function call pushes a stack frame and every `return` pops one, and trace how recursion stacks frames on top of frames until the base case unwinds them. You will also meet references and pointers conceptually, learn what triggers a stack overflow, and get a working mental model of garbage collection and memory leaks. This lesson builds on **Space Complexity Fundamentals**, where you learned to count auxiliary versus total space and saw why some algorithms claim `O(1)` space while others need `O(n)`. Memory Models gives you the underlying picture: those `O(...)` numbers describe stack frames, heap allocations, and reference graphs that you can now visualize concretely. Next, you will pivot to the mathematical side of the foundations track with **Discrete Mathematics Basics**, picking up the sets, relations, and logic vocabulary that algorithm analysis depends on.
Not Started
0%
Number Theory Fundamentals
Why are hash table sizes almost always prime? Why does the Euclidean algorithm for `gcd` run in `O(log(min(a, b)))` time despite using only subtraction or remainders? **Number Theory Fundamentals** is the branch of math that answers these questions and quietly powers a surprising amount of practical software, from hashing and cryptography to scheduling and competitive programming shortcuts. This lesson introduces the core building blocks. You will study **prime numbers** and how to test primality efficiently, the **divisibility** relation and quick rules for spotting divisors, **GCD** (greatest common divisor) and **LCM** (least common multiple) with the identity `lcm(a, b) = a * b / gcd(a, b)`, and the **Euclidean algorithm** for computing `gcd` in logarithmic time. You will also do **prime factorization** by trial division (`O(sqrt(n))`) and see how factorizations make divisor counting, simplification, and periodicity arguments straightforward. This lesson builds on **Discrete Mathematics Basics**, where you learned how to reason precisely about sets, relations, and logical claims. Number theory uses that same proof-style reasoning, but applied to the integers and their multiplicative structure. With primes, `gcd`, and factorization in your toolkit, you will be ready to take the premium step into **Modular Arithmetic**, where you will reuse all of these ideas to work with `mod`, modular inverses, and Fermat's Little Theorem.
Not Started
0%
Space Complexity Fundamentals
An algorithm that runs in `O(n)` time but allocates a fresh array of size `n^2` will not fit in memory long before it would have finished computing. Memory is finite, and many algorithms quietly trade it for speed; the only way to make that trade-off visible is to analyze space the same way you analyze time. **Space Complexity Fundamentals** extends the Big-O lens from operation counting to memory usage. You will see why we draw a line between auxiliary space (the extra storage an algorithm allocates) and total space (auxiliary plus the input itself), and you will classify common algorithms as `O(1)` constant, `O(n)` linear, or `O(n^2)` quadratic in space. You will meet the in-place vs out-of-place distinction that interviewers love to probe, and you will study a first space-time trade-off where caching results turns repeated work into stored data. In **Big-O Notation (Upper Bound)**, you learned to read complexity classes from loop structure and to recognize that `O(c * n)` collapses to `O(n)`. The same vocabulary and the same simplification rules apply here, but the resource being counted is bytes of allocated memory rather than units of work. Once you can reason about both axes at once, you will be ready for **Logarithms & Exponentiation**, where you will build the mathematical intuition behind `O(log n)`, the complexity class that powers binary search, balanced trees, and most efficient divide-and-conquer algorithms.
Not Started
0%
Data Structures
Arrays & Strings
Reading `arr[1000000]` takes the same amount of time as reading `arr[0]`, because an array's contiguous memory layout lets the runtime compute the address of any element with a single multiplication. That single property is what makes **Arrays & Strings** the workhorse data structure of nearly every program you will ever write. This lesson walks through array declaration and indexing in JavaScript and Python, the cost of inserts and deletes that force shifting, slicing and subarray patterns, and the basic string operations every interview problem assumes you know. You will also see why strings behave as immutable character arrays in both languages and what that means for performance when you build strings inside a loop. In **How to Read Code (JS & Python)**, you practiced tracing programs line by line; that habit is exactly how you will reason about loop indices and slice boundaries here. **Big-O Notation (Upper Bound)** gave you the language to express scaling behavior, and arrays are where you will first see `O(1)` access sit next to `O(n)` insertion in the same data structure. Once array fundamentals are second nature, **Matrix/Grid Fundamentals** extends the same indexing intuition into two dimensions, where row and column traversal patterns power BFS, DFS, and dynamic programming on grids.
Not Started
0%
Linked Lists (Singly)
Inserting at the front of an array of one million items forces every existing element to slide one slot to the right. A **Linked List** sidesteps that copy entirely: a head insertion is two pointer assignments and nothing else, no matter how many nodes follow. In this lesson, each node holds a value and a `next` reference, and you chain those nodes into a singly linked list with explicit head and optional tail pointers. You will implement traversal, head and tail and middle insertion, deletion by value and by position, and linear search, and you will analyze each operation precisely so the trade-off against arrays becomes concrete: `O(1)` insertion at the head, `O(n)` access by index, and per-node memory overhead for the pointer. In **Arrays & Strings**, the `O(n)` cost of inserting near the front came from shifting; the linked list was invented to remove that shift. **Memory Models** introduced the difference between a contiguous block on the stack or heap and scattered allocations connected by references, and that mental model is exactly how a node-based structure lives in memory. Once you are comfortable manipulating `next` pointers, **Stack (LIFO)** uses a linked list (or a dynamic array) as its underlying storage and adds a strict push, pop, peek discipline on top.
Not Started
0%
Matrix/Grid Fundamentals
Picture an image as a grid of pixels, a chessboard as an 8 by 8 array of squares, or a maze as a rectangle of walls and corridors. Each of these is a **Matrix/Grid**: a two-dimensional array indexed by `(row, column)` where the right traversal order can turn a hard problem into a single nested loop. This lesson covers how to allocate and initialize 2D arrays in JavaScript and Python, how row-major storage maps a `[i][j]` access to a contiguous memory offset, and the standard traversal patterns: row by row, column by column, and along the two diagonals. You will also practice boundary checks, the most common source of off-by-one bugs in grid problems, and implement a transpose to see how index swaps reshape data in place. In **Arrays & Strings**, you saw that a one-dimensional array gives `O(1)` indexed access through a single offset calculation. A grid is just nested arrays sharing that same property along two axes, so every shifting and bounds idea you used there carries over directly. Once you can move confidently through a grid, **Linked Lists (Singly)** shifts the focus to a very different memory layout: pointer-based nodes with no contiguous block at all.
Not Started
0%
Algorithms
Introduction to Algorithms
Two recipes can both bake the same cake, yet one calls for thirty minutes and the other for three hours. The same is true of code: a problem like sorting a list or finding the largest number in an array has many valid solutions, and the choice between them is exactly what an algorithm captures. This lesson defines what an algorithm actually is, naming the five characteristics every algorithm shares (input, output, definiteness, finiteness, effectiveness). It separates the abstract steps of a method from the concrete code that implements it, and walks through how to judge whether a procedure is _correct_ before worrying about whether it is fast. You will also build a first informal sense of efficiency, the way work grows as inputs get bigger, without any formal notation yet. In **How to Read Code (JS & Python)**, you practiced tracing variables, loops, and function calls in two languages. **Introduction to Algorithms** zooms out from individual lines to the recipe as a whole, treating those traces as evidence that a method does what it claims. From here you will move into **Iteration Patterns on Arrays/Strings**, where these abstract ideas about correctness and efficiency get applied to concrete traversal templates.
Not Started
0%
Recursion Fundamentals
The mathematical definition `factorial(n) = n * factorial(n - 1)` defines a function in terms of itself, with `factorial(0) = 1` as the stopping point. That two-line definition is also a complete program if your language lets a function call itself. Recursion is what turns self-referential definitions into runnable code, and many problems (tree traversal, graph search, divide and conquer, dynamic programming) describe themselves most naturally that way. **Recursion Fundamentals** breaks down how that machinery actually works. You will learn to identify a base case (when the recursion stops) and a recursive case (how the problem reduces to a smaller instance), trace the call stack as frames are pushed and popped, and reason about return values flowing back up the chain. Examples run through factorial, naive Fibonacci, sum of an array, and integer power, plus a first look at recursion-tree intuition, tail recursion, stack overflow, and the `O(depth)` space cost of deep recursion. In **How to Read Code (JS & Python)**, you saw functions call other functions. **Debugging by Tracing** taught you to follow those calls step by step. Recursion is the case where the function on the call stack is the same function, again and again, with smaller inputs each time. Next, **Backtracking (Intro)** extends recursion with an explicit undo step to systematically explore combinatorial search spaces.
Not Started
0%
Question Banks
Amortized Analysis Quick Quiz
Short drills on amortized cost for dynamic arrays, hash table rehashing, and the aggregate method. Good for solidifying the gap between worst-case and average-case-per-operation.
Array Fundamentals Quiz
Quick prompts on indexing, in-place mutation, and the cost of common array operations. Good for warming up before sliding-window or two-pointer drills.
Hash Table Basics Quiz
Short prompts on hash table lookup cost, collision handling, and when to reach for a Set vs a Map. Builds the mental model before harder hashing problems.
Linked List Basics Quiz
Short prompts on singly vs doubly linked lists, traversal, length, and the everyday operations that come up before cycle detection or in-place reversal.
Binary Tree Basics Quiz
Short prompts on node anatomy, depth vs height, and leaf counting. Foundation drills before tackling traversal, BSTs, or balanced tree problems.
Binary Search Tree Basics
Quick drills on the BST ordering invariant, in-order traversal yielding sorted output, and the most common search and insert operations.
String Basics Quiz
Three short prompts on JavaScript string immutability, slicing, and char codes. Good warm-up before tackling sliding-window or palindrome problems.
Two-Pointer Warm-Up
Four short prompts covering pair sums, in-place dedupe, and palindrome checks with two pointers. Great preparation before sliding-window drills.
Big-O Complexity Quiz
Four short prompts on identifying time complexity from JavaScript code: nested loops, halving, recursion, and a bug-by-complexity hunt.
Space Complexity Quiz
Three short prompts on space accounting: stack vs heap usage, recursion depth, and an in-place vs out-of-place comparison.
Stack and Queue Fundamentals
Four short prompts on LIFO vs FIFO behavior, balanced parentheses, and a bug hunt in a circular queue. Good warm-up before monotonic-stack drills.
Graph Representation Quiz
Short drills on adjacency list vs adjacency matrix, edge-weight storage, and the memory trade-offs between the two formats.
Sorting Algorithm Speed Round
Quick drills on quicksort, mergesort, heapsort, and counting sort: best / average / worst times, stability, and when each one wins.
Dynamic Programming Warm-Up
Memoization, tabulation, and writing transitions for classic 1D DP. Code stems are Python.
Greedy Algorithms Warm-Up
Identify when a greedy choice is correct and when it fails. Drills cover activity selection, coin change with canonical denominations, and Huffman intuition.
Floating Point and Precision
Hard drills on IEEE-754 representation, equality pitfalls, accumulation drift, and safe comparison patterns. Includes one Kahan-summation walk and a 0.1 + 0.2 trace.
Promises and async/await Basics
Beginner drills on Promise resolution order, async/await semantics, and the microtask queue. Three short JavaScript snippets you can predict line-by-line.
JavaScript Coercion and Equality Code Traces
Six output traces drilling on `==` vs `===`, unary `+`, falsy values, and chained relational coercion. Sharpens the rules JS applies before comparing.
JavaScript `typeof`, NaN, and Number Quirks Traces
Six traces covering the `typeof` chain, `isNaN` vs `Number.isNaN`, `parseInt` with `map`, the comma operator, `Object.is`, and `Number()` vs `new Number()`.
JavaScript Array and Object Fundamentals Quiz
Test the day-one moves for working with arrays and objects: type-checking, copying, deduping, and the gotchas hiding under shallow vs deep clones.
let, var, const, and Hoisting Conceptual Quiz
Walk through the scoping, redeclaration, and hoisting rules for `var`, `let`, and `const`, plus the TDZ trap that shows up in nearly every interview.
JavaScript Control Flow and Conditional Quiz
Read JavaScript's small but treacherous control-flow rules: switch fall-through, ASI biting return statements, and short-circuit logical chains.
JavaScript Tooling and Build Trivia
Three quick-fire build-pipeline questions: transpiler vs polyfill, Babel vs SWC, and what source maps actually do.
JavaScript Function Fundamentals Quiz
Four day-one essentials about functions: how to define them, when to choose declaration vs expression vs arrow, default parameters, and rest/spread.
React Component Communication Quiz
Four quick checks on how React components pass data down via props and notify parents via callbacks, plus when render-props become a better tool than another layer of props.
CSS Layout Fundamentals Quiz
Four drills on the foundational CSS layout primitives: the display property, positioning modes, a sticky footer pattern, and the z-index stacking context.
Array Higher-Order Methods Quiz (map / filter / reduce / find)
Four drills on the core array higher-order methods: reduce for aggregation, filter plus reduce (or Math.max) for selection, find for first-match lookup, and flatMap for one-step map-and-flatten.
JavaScript Variable Hoisting: var vs let/const Explanations Quiz
Two seeded explanations (var hoisting and the let/const TDZ) plus two companion drills covering function-declaration hoisting and a common interview trap.
JavaScript FizzBuzz: Two Implementations Quiz
Two seeded FizzBuzz implementations (modulo branching and order-sensitive variant) plus two companion drills covering a generalized N-divisors version and a micro-benchmark.
JavaScript Count Backward by Evens: Two Approaches Quiz
Two seeded approaches to enumerate even numbers descending from n (filter-on-step-1 vs step-2 loop), plus two companions on Array.from and an odd-start edge case.
JavaScript Object Values to Array: Two Approaches Quiz
Two seeded approaches to convert an object's values to an array (Object.values spread vs Object.keys.map) plus two companions on Object.entries and ordering pitfalls.
JavaScript X and O Balance: Two Approaches Quiz
Check whether a string contains an equal count of `x` and `o` (case-insensitive), two ways (regex match-array length and filter + length), plus companions on counting any pair of characters and treating empty input.
JavaScript Spread Operator Refactor: Two Explanations Quiz
Refactor a manual `sum(nums[0], nums[1], nums[2])` call with the spread operator, two equivalent shapes (spread shortcut and the older `apply(null, nums)` form), plus companions on rest parameters and array-spread vs concat.
JavaScript find vs filter for Student Lookup Quiz
Two seeded approaches to look up students by name: `find` returns the first match, `filter` returns every match. Two companions cover return-type pitfalls and short-circuit semantics.
JavaScript String Lengths Array: Four Approaches Quiz
Four seeded ways to turn an array of strings into an array of their lengths (map, for-loop with push, reduce, for-of), plus one companion on a recursive variant.
React Stateful vs Stateless Components: Two Explanations Quiz
Two explanations of the stateful/stateless (smart vs presentational) split, plus companions on hooks-era state in function components and on testability trade-offs.
Community
Python Decorators Explained with Five Real Examples
Decorators stop being magic the moment you see five real ones in a row: timing, caching, auth, retry, and rate limiting. Here is the pattern, the gotchas, and the line where I stop reaching for them.
Pure vs Tail Recursion and Why JavaScript Doesn't Care
What pure recursion vs tail recursion actually means, why tail-call optimisation matters, why mainstream JS engines refuse to ship it, and the iterative rewrite I default to when stack depth scales with input.
The Honest Guide to Amortized Analysis
Why amortized O(1) is not the same as worst-case O(1), the three accounting methods, and the real situations where the average bound stops being good enough.
Generators, yield, and Lazy Pipelines
Generators turn a 4GB log-processing job into a 50MB one without changing the consumer code. Here is the mental model, the pipeline pattern I reuse, and the four traps that make hand-rolled generators leak.
Space Complexity, the Other Half of the Story
Auxiliary vs input space, the recursion-stack trap, the time-vs-space trade, and the two questions I added to my code-review template after one OOM in production.
Type Hints, mypy, and the Runtime Truth
Python type hints are documentation that a static checker reads. The runtime ignores them. Here is what hints do, what mypy adds, and the libraries that validate at runtime on purpose.
Hash Tables: The Most Useful Data Structure
Why hash tables earn their reputation, where collisions and load factor actually bite, and the language-specific quirks (JS Map vs Object, Python dict, Java HashMap) that change the game.
Core Data Structures Warmup
Two quick whiteboard questions on array vs linked list complexity and hash-map two-sum. Five minutes each.
Context Managers Beyond with open(...)
The `with` statement is a setup-teardown primitive, not a file-handling shortcut. Five context managers I write or use weekly, plus the gotcha that turns a class-based manager into a leak.
P, NP, and Why You Rarely Care at Work
P, NP, NP-hard, NP-complete in working-engineer language: what each one means, why the open question matters less than the recognition signal it gives you, and what I do tell juniors about NP.
Valid Anagram
Decide whether two strings are anagrams of each other in O(n) using a frequency map.
The GIL: What It Actually Blocks
The GIL blocks parallel Python bytecode and nothing else. I/O, well-behaved C extensions, and multiprocessing all sidestep it. Here is how I tell GIL-bound code from code that just feels slow.
Find Pivot Index
Find the leftmost index where the sum of elements to its left equals the sum to its right.
Stacks and Queues Cheat Sheet
LIFO vs FIFO, the operations that matter, and the language-specific footguns (JS shift, Python list.pop(0), Java Stack vs Deque) that turn O(1) into O(n).
Garbage Collection in V8 Without the Mystique
The working engineer's tour of V8 GC: generational hypothesis, Scavenger for young space, Mark-Sweep-Compact for old, incremental marking, Orinoco's concurrent collector, and what application code can actually do.
Generics in TypeScript: From Confused to Confident
What a type variable actually is, when constraints earn their place, the keyof T pattern that makes pluck type-safe, and the three-question test I run before introducing a generic.
Understanding Event Propagation: Capturing, Bubbling, and More
The three-phase event model in the DOM, why bubbling is the default for historical reasons, when capturing pays off, and how event delegation falls out of the same mechanic.
WeakMap and WeakSet: When They Actually Help
The narrow but exact problems weak collections solve: associating metadata with objects you do not own, memoizing on object identity, and seen-tracking without rooting. Plus the misuses that turn them into ineffective leak-papering.
Hoisting: The Mental Model That Finally Stuck
The two-phase entry into every scope: creation phase creates every declaration's binding, execution phase runs the code. Once that order is fixed in your head, var/let/const/TDZ behaviour is mechanical.
Mastering Closures in JavaScript
What a closure actually captures (variable bindings, not values), why the loop-with-var bug exists, and the real-world patterns that lean on closures: module pattern, currying, and React useCallback.
Recursion Demystified
How to read recursion as a contract instead of a stack trace, the four parts of every recursive function, and where iteration beats it in practice.
Move Zeroes
Move every zero to the end of the array in place while keeping the relative order of the non-zero elements.
Modular Arithmetic for the Working Programmer
Modulo without the math-class baggage: the four laws that matter, the negative-number trap that ruins hash and rotation code, modular inverses, and where I actually use this in production.
Python Packaging in 2026: pyproject, uv, and pipx
Python packaging finally converged. pyproject.toml is the source of truth, uv replaced pip plus venv plus pip-tools, and pipx owns global CLIs. The modern toolchain and the migration order that does not blow up CI.
Reverse String
Reverse a character array in place using two pointers, no extra buffer allowed.
Linked Lists Explained
What linked lists actually buy you in modern code, the operations that make them shine, and why the answer is usually "use an array" anyway.
Loop Invariants in Real Code, Not Textbook Code
What a loop invariant actually is, the three things it has to claim, how to use them in a code review (not a proof), and the bug a one-line invariant comment would have caught for me.
List Comprehensions and When to Stop Using Them
Comprehensions are the fastest way to express a simple transform-and-filter, but they decay into write-only code the moment you nest them or sneak side effects in. Here is the line I draw.
The JavaScript Event Loop: Tasks, Microtasks, and Rendering
A trace-by-hand walkthrough of the event loop: pick a macrotask, drain microtasks to empty, then optionally render. Worked example interleaves setTimeout, Promise, queueMicrotask, await, and requestAnimationFrame.
Running Sum of 1d Array
Build the prefix-sum array in place: each output index holds the cumulative sum of nums up to that index.
Bit Manipulation Tricks I Keep Forgetting
A working programmer's cheat sheet of bitwise operations: the moves I look up every six months, what each one does, real production uses, and the ones that look clever but I avoid.
Sort Array By Parity
Rearrange the array so that every even integer appears before every odd integer; any valid arrangement is accepted.
Two Pointers Technique
The three sub-patterns (opposite ends, same direction, fast-slow), the canonical problems each one solves, and why recognizing the shape is the entire skill.
Module Systems: CJS, ESM, and the Interop Pain
Four sources of CJS/ESM interop pain (file extensions, bundlers, runtime, tooling), the dual-publish problem with module-level state, and what tsx, ts-node, esbuild, and bun do differently.
Debounce, Throttle, and the Difference People Miss
Debounce settles, throttle paces. The visual difference, the canonical implementations of both (with leading-edge and trailing-call variants), and the three edge cases that bite hand-rolled wrappers.
Prototypes vs Classes: What Is Actually Happening
The contrarian take that classes are no longer just syntactic sugar over prototypes. Walks the prototype chain, what new actually does, and the five things class adds that pure-prototype code cannot replicate without contortion.
Understanding Big-O Notation
What Big-O actually measures, why constants still matter at small N, and the four traps that catch even strong engineers in code review.
TypeScript Utility Types I Use Every Week
The seven utility types that show up in every PR (Partial, Required, Pick, Omit, Record, Readonly, ReturnType), plus the three I keep on standby (Awaited, Parameters, NonNullable/Exclude/Extract). When to derive instead of restate.
