Nine of the most common algorithms - now in your hands. Run each one yourself: press play, watch it think, and master every step one decision at a time. What you see in action, you never forget - start exploring now!
Neighbors compare, swap, and settle - repeatedly - until order emerges.
Learn more โHalve the field of search every time. Fast, but only on sorted ground.
Learn more โRipple outward from a starting point, one ring of neighbors at a time.
Learn more โOne pointer from each end, closing in - the workhorse of sorted-array problems.
Learn more โSlide a fixed-size frame across the array instead of recomputing from scratch.
Learn more โA tortoise and a hare on a linked list - if there's a loop, they will meet.
Learn more โRunning totals, stored as you go, turn subarray questions into lookups.
Learn more โWalk down the row. Compare two neighbors. If the left one is bigger, swap them. By the end of one pass, the largest value has "bubbled" to the far end. Repeat until nothing needs swapping.
Learn more โ1def bubble_sort(arr):2 n = len(arr)3 for i in range(n - 1):4 for j in range(n - 1 - i):5 if arr[j] > arr[j+1]:6 arr[j], arr[j+1] = \arr[j+1], arr[j]7 return arr
On a row that's already sorted, look at the middle value. Too small? The answer must be to the right - discard the left half. Too big? Discard the right half. Repeat: the search space halves every step.
Learn more โ1def binary_search(arr, target):2 lo, hi = 0, len(arr) - 13 while lo <= hi:4 mid = (lo + hi) // 25 if arr[mid] == target:6 return mid7 elif arr[mid] < target:8 lo = mid + 19 else:10 hi = mid - 111 return -1
Start at one node. Visit every direct neighbor first - that's ring one. Then every neighbor-of-a-neighbor - ring two. A queue keeps the order fair: first discovered, first explored.
Learn more โ1def bfs(graph, start):2 visited = {start}3 queue = deque([start])4 while queue:5 node = queue.popleft()6 for neighbor in graph[node]:7 if neighbor not in visited:8 visited.add(neighbor)9 queue.append(neighbor)10 return visited
On a sorted array, place one pointer at each end. If the pair sums too small, the only fix is to move the left pointer up. Too big, move the right pointer down. Every LeetCode problem titled "pair sum" or "container with most water" is this pattern.
Learn more โ1def two_sum_sorted(arr, target):2 left, right = 0, len(arr) - 13 while left < right:4 s = arr[left] + arr[right]5 if s == target:6 return [left, right]7 elif s < target:8 left += 19 else:10 right -= 111 return []
Instead of recomputing a sum for every possible window, keep a running total: drop the value that just left the frame, add the value that just entered. One frame, sliding - not thousands of frames, recomputed.
Learn more โ1def max_sum_subarray(arr, k):2 window_sum = sum(arr[:k])3 max_sum = window_sum4 for i in range(k, len(arr)):5 window_sum += arr[i] - arr[i - k]6 max_sum = max(max_sum, window_sum)7 return max_sum
Two pointers walk the same linked list - one node at a time, and two nodes at a time. If the list loops back on itself, the fast pointer eventually laps the slow one and they land on the same node. If the list ends, the fast pointer simply runs off the end.
Learn more โ1def has_cycle(head):2 slow, fast = head, head3 while fast and fast.next:4 slow = slow.next5 fast = fast.next.next6 if slow is fast:7 return True8 return False
Keep a running total as you scan. At each position, ask: "have I seen the running total minus k before?" If so, everything between that earlier position and here sums to exactly k. A hash map turns that question into an O(1) lookup.
Learn more โ1def subarray_sum(arr, k):2 count, total = 0, 03 seen = {0: 1}4 for num in arr:5 total += num6 need = total - k7 count += seen.get(need, 0)8 seen[total] = seen.get(total, 0) + 19 return count
Climbing n stairs, one or two steps at a time - how many distinct ways? Rather than re-deriving the answer for every n from scratch, build a table left to right: the answer for n is just the answer for nโ1 plus the answer for nโ2, already sitting in the table.
Learn more โ1def climb_stairs(n):2 if n <= 2:3 return n4 dp = [0] * (n + 1)5 dp[1], dp[2] = 1, 26 for i in range(3, n + 1):7 dp[i] = dp[i-1] + dp[i-2]8 return dp[n]
Commit to one path and follow it as far as it goes. Only when you hit a dead end do you back up to the last fork and try the next branch. A stack remembers where to return - the exact opposite discipline to BFS's queue.
Learn more โ1def dfs(graph, start):2 visited = set()3 stack = [start]4 while stack:5 node = stack.pop()6 if node in visited:7 continue8 visited.add(node)9 for nb in reversed(graph[node]):10 if nb not in visited:11 stack.append(nb)12 return visited
| Specimen | Best case | Worst case | Space | Requires |
|---|---|---|---|---|
| Bubble Sort | O(n) | O(nยฒ) | O(1) | nothing - works on any order |
| Binary Search | O(1) | O(log n) | O(1) | a sorted array |
| Breadth-First Search | O(V+E) | O(V+E) | O(V) | an adjacency list & a queue |
| Two Pointers | O(n) | O(n) | O(1) | a sorted array |
| Sliding Window | O(n) | O(n) | O(1) | a contiguous window, fixed or growable |
| Fast & Slow Pointers | O(n) | O(n) | O(1) | a linked structure to walk |
| Prefix Sum + Hash Map | O(n) | O(n) | O(n) | a hash map of running totals |
| 1D Dynamic Programming | O(n) | O(n) | O(n) | overlapping subproblems |
| Depth-First Search | O(V+E) | O(V+E) | O(V) | an adjacency list & a stack (or recursion) |
This guide is a first look. When you're ready to go further, these are the resources worth your time - all free to start, none of them filler.