Iteration Patterns
Master the loop patterns that form the backbone of every algorithm: single passes, nested loops, two-pointer scans, accumulators, and early termination strategies.
Learn & Reference
Understanding the Pattern
Iteration Patterns
Every algorithm ultimately boils down to how you loop through data. Understanding common iteration patterns lets you decompose problems into familiar building blocks instead of reinventing the wheel each time.
Core Loop Types
Single Pass (Linear Scan)
The most common pattern: iterate through an array once, building up a result. Used for sums, max/min, counting, filtering, and transformations.
Nested Loops
When you need to compare every pair of elements, or process a 2D structure. The key is knowing when O(n²) is unavoidable vs. when a hash map or sorting can eliminate the inner loop.
Accumulator Pattern
Carry a running value through the loop — a sum, product, max, or any aggregate. Initialize before the loop, update inside, return after.
Early Termination
Break out of a loop as soon as you find your answer. Don't scan the remaining elements if you already know the result.
Enumerate / Index Tracking
Often you need both the element AND its position. Use enumerate() (Python), index-based for loops, or range with index.
Zip / Parallel Iteration
Process two sequences in lockstep. Useful for comparing arrays element-by-element, merging sorted lists, or pairing related data.
Key Principles
- Choose the simplest loop — a single
forloop is clearer thanwhilewith manual index management - Avoid unnecessary work — if you can break early or skip irrelevant elements, do it
- Track what you need — decide upfront whether you need the index, the value, or both
- Watch boundary conditions — off-by-one errors are the #1 loop bug. Always verify the first and last iterations manually
Common Mistakes
- Off-by-one errors: Using
<vs<=, or starting at 0 vs 1. Always trace through the first and last iterations - Modifying a collection while iterating: Adding or removing elements during a for-each loop causes bugs. Build a new collection instead
- Unnecessary nested loops: Many O(n²) solutions can be reduced to O(n) with a hash map or sorting
- Forgetting to initialize the accumulator: Starting a sum at 0, a product at 1, or a min at infinity
- Infinite loops: Forgetting to update the loop variable in a while loop, or using the wrong termination condition
When to Use
Template
1# Iteration Patterns2# for x in arr: — iterate values3# for i, x in enumerate: — index + value4# for a, b in zip(l1, l2): — parallel iteration56def solve(arr):7result = 08for x in arr:9result += x10return result
Syntax Reference
1# === Basic for loop ===2for x in arr: # iterate values3for i in range(len(arr)): # iterate indices4for i, x in enumerate(arr): # both index and value56# === While loop ===7i = 08while i < len(arr):9i += 11011# === Range variations ===12range(5) # 0, 1, 2, 3, 413range(2, 8) # 2, 3, 4, 5, 6, 714range(0, 10, 2) # 0, 2, 4, 6, 815range(5, 0, -1) # 5, 4, 3, 2, 11617# === Zip (parallel iteration) ===18for a, b in zip(list1, list2): # pairs from two lists19for i, (a, b) in enumerate(zip(l1, l2)): # with index2021# === List comprehensions ===22[x * 2 for x in arr] # transform23[x for x in arr if x > 0] # filter24[x * 2 for x in arr if x > 0] # both2526# === Built-in aggregates ===27sum(arr) # sum of elements28max(arr) # maximum29min(arr) # minimum30any(x > 0 for x in arr) # True if any match31all(x > 0 for x in arr) # True if all match
Common Recipes
1# --- Running Sum ---2def running_sum(arr):3result = []4total = 05for x in arr:6total += x7result.append(total)8return result910# --- Zip Two Lists ---11def zip_merge(a, b):12return [[x, y] for x, y in zip(a, b)]1314# --- Sliding Window Average ---15def sliding_avg(arr, k):16result = []17window_sum = sum(arr[:k])18result.append(window_sum / k)19for i in range(k, len(arr)):20window_sum += arr[i] - arr[i - k]21result.append(window_sum / k)22return result2324# --- Pascal's Triangle ---25def pascal(n):26tri = [[1]]27for i in range(1, n):28prev = tri[-1]29row = [1]30for j in range(1, i):31row.append(prev[j-1] + prev[j])32row.append(1)33tri.append(row)34return tri
Complexity
| Pattern | Time | Notes |
|---|---|---|
| Single pass | O(n) | One loop through the data |
| Nested loops (all pairs) | O(n²) | Every pair of elements |
| Triple nested | O(n³) | Rare — usually avoidable |
| Accumulator (sum/max/min) | O(n) | Single pass with running value |
| Zip / parallel scan | O(min(m,n)) | Stops at shorter sequence |
| Sliding window (fixed) | O(n) | Maintain window sum/state |
| Build 2D (n rows, m cols) | O(n×m) | E.g., Pascal triangle, matrix |
Watch Out
- ✗Off-by-one errors: Using `<` vs `<=`, or starting at 0 vs 1. Always trace through the first and last iterations
- ✗Modifying a collection while iterating: Adding or removing elements during a for-each loop causes bugs. Build a new collection instead
- ✗Unnecessary nested loops: Many O(n²) solutions can be reduced to O(n) with a hash map or sorting
- ✗Forgetting to initialize the accumulator: Starting a sum at 0, a product at 1, or a min at infinity
- ✗Infinite loops: Forgetting to update the loop variable in a while loop, or using the wrong termination condition