dot-skills Algorithmic Complexity (Big-O) Best Practices
Find, classify, and fix algorithmic complexity (Big-O) problems in code — language-agnostic. The 39 rules across 8 categories cover the patterns responsible for the vast majority of accidental quadratic, exponential, and N+1 blowups in production code: nested iteration, loop-invariant I/O, data-structure mismatch, recursion explosions, redundant computation, collection-building anti-patterns, search/sort selection, and space traps.
When to Apply
Use this skill when:
- Reviewing a pull request or function for performance regressions
- Asked "why is this slow?" or "can we make this faster?"
- Refactoring a hot path or a function that handles user-scaled input
- Reading code that contains: nested loops,
.includes/.find/x in list inside iteration, ORM access in a loop, recursion without memoization, string/array building via += or spread, file/database I/O inside iteration
- Reviewing code that processes lists, trees, or streams whose size will grow
Workflow: Find, Classify, Fix
The skill is structured for a three-step workflow on any code under review:
1. Find — Scan for the Suspicion Patterns
Look for these structural signals first (highest hit rate):
| Signal |
Likely Category |
First Rule to Check |
Two nested for loops |
nested- |
nested-explicit-quadratic-loops |
.includes / .find / x in list inside a loop |
nested- |
nested-includes-in-loop |
ORM access inside a loop (for o in orders: o.customer.x) |
io- |
io-n-plus-one-query |
await fetch in for-of |
io- |
io-sequential-await-in-loop |
array.find to "join" two arrays |
ds- |
ds-hashmap-for-keyed-access |
| Recursive function with overlapping arguments |
rec- |
rec-memoize-overlapping-subproblems |
s = s + part or [...acc, x] in a loop |
build- |
build-avoid-quadratic-string-concat, build-avoid-spread-in-reducer |
sorted(...) called inside a loop |
search- |
search-sort-once-outside-loop |
readlines() / loading whole files |
space- |
space-stream-dont-load |
2. Classify — Derive the Big-O
Compute complexity from the code structure:
| Structure |
Complexity |
| Single loop over n items, O(1) body |
O(n) |
| Two nested loops over n / m items |
O(n*m) |
Loop calling an O(n) operation (.includes, .find, x in list) |
O(n*m), often misread as O(n) |
Recursive f(n) = f(n-1) + f(n-2) without memoization |
O(2ⁿ) |
Recursive f(n) = 2*f(n/2) + O(n) |
O(n log n) |
Recursive f(n) = 2*f(n/2) + O(1) |
O(n) (full tree traversal) |
Recursive f(n) = f(n/2) + O(1) |
O(log n) |
s = s + part in a loop |
O(n²) (string immutability) |
[...acc, x] in a reduce |
O(n²) (copy-on-spread) |
| Query/RPC inside loop over n items |
O(n) round trips |
When in doubt, ask: "As input doubles, does runtime roughly double (linear), quadruple (quadratic), or do something worse (exponential)?" That's the practical complexity class.
3. Fix — Apply the Pattern From the Matching Rule
Each reference file in references/ is a {category}-{slug}.md containing:
- WHY the pattern matters (the cascade effect)
- An Incorrect code example with the cost annotated
- A Correct example with the minimal diff
- When NOT to apply the fix (the rule has exceptions)
The minimal diff philosophy is intentional: the goal is for the agent to see exactly how few lines need to change to flip the complexity class.
Rule Categories by Priority
| # |
Category |
Prefix |
Impact |
Rules |
| 1 |
Nested Iteration Patterns |
nested- |
CRITICAL |
6 |
| 2 |
Loop-Invariant I/O and N+1 |
io- |
CRITICAL |
5 |
| 3 |
Data Structure Mismatch |
ds- |
HIGH |
6 |
| 4 |
Recursion Complexity |
rec- |
HIGH |
5 |
| 5 |
Redundant Computation |
compute- |
MEDIUM-HIGH |
5 |
| 6 |
Collection Building |
build- |
MEDIUM |
4 |
| 7 |
Search & Sort Selection |
search- |
MEDIUM |
4 |
| 8 |
Space Complexity Traps |
space- |
LOW-MEDIUM |
4 |
See references/_sections.md for the full ordering rationale.
Quick Reference
1. Nested Iteration Patterns (CRITICAL)
nested-explicit-quadratic-loops — Replace pairwise loops with hash-based single passes
nested-includes-in-loop — Avoid .includes() / .indexOf() inside a loop
nested-find-in-loop — Pre-index lookups instead of .find() per iteration
nested-cartesian-comparison — Group by key instead of cartesian comparison
nested-set-operations-on-arrays — Use sets for intersection, union, difference
nested-substring-search-in-loop — Tokenize once instead of re-scanning per pattern
2. Loop-Invariant I/O and N+1 Queries (CRITICAL)
io-n-plus-one-query — Eliminate N+1 queries by fetching related data in one round trip
io-sequential-await-in-loop — Run independent async operations in parallel
io-batch-instead-of-per-item — Use batch endpoints instead of per-item calls
io-file-read-in-loop — Read or stat files outside tight loops
io-missing-eager-load — Eager-load ORM relations you will access
3. Data Structure Mismatch (HIGH)
ds-hashmap-for-keyed-access — Store records keyed in a hashmap, not as parallel arrays
ds-heap-for-top-k — Use a heap for top-k, not full sort + slice
ds-deque-for-front-operations — Use a deque for front insertions and removals
ds-counter-for-histograms — Use Counter / multiset for frequency counting
ds-sorted-structure-for-range-queries — Use a sorted structure for range queries
ds-trie-for-prefix-search — Use a trie for prefix search
4. Recursion Complexity (HIGH)
rec-memoize-overlapping-subproblems — Memoize recursion with overlapping subproblems
rec-tabulate-bottom-up — Tabulate bottom-up to eliminate recursion overhead
rec-iterative-for-deep-recursion — Use an explicit stack instead of deep recursion
rec-prune-with-bounds — Prune recursive search with bounds and constraints
rec-share-memo-across-top-level-calls — Share memoization across top-level calls
5. Redundant Computation (MEDIUM-HIGH)
compute-hoist-loop-invariants — Hoist loop-invariant computation outside the loop
compute-precompile-regex — Pre-compile regex patterns
compute-cache-expensive-pure-results — Cache expensive pure-function results
compute-cache-property-lookup — Cache repeated property lookups in hot loops
compute-defer-or-short-circuit — Defer or short-circuit work you might not need
6. Collection Building (MEDIUM)
build-avoid-quadratic-string-concat — Build strings with joins or builders, not repeated concatenation
build-avoid-spread-in-reducer — Push to a mutable accumulator instead of spreading
build-avoid-immutable-object-spread — Use a plain object build phase, then freeze
build-presize-when-length-known — Pre-size collections when the length is known
7. Search & Sort Selection (MEDIUM)
search-binary-search-on-sorted — Use binary search on sorted data
search-sort-once-outside-loop — Sort once outside the loop, not on every iteration
search-quickselect-not-full-sort — Use quickselect for the k-th element, not full sort
search-build-index-once-amortize — Build the index once when queries dominate
8. Space Complexity Traps (LOW-MEDIUM)
space-stream-dont-load — Stream large inputs instead of loading them whole
space-generators-over-intermediate-lists — Pipe through generators instead of materializing intermediate lists
space-shallow-not-deep-copy — Use shallow copies (or no copy) instead of deep clones
space-release-retained-references — Release references that prevent garbage collection
How to Use
- Start with the Find signal table above to locate the most likely pattern.
- Open the matching reference file for the WHY and the minimal-diff fix.
- If you're classifying complexity from scratch, use the Classify table to derive Big-O from code structure.
- When proposing a fix, quote the rule by file path so reviewers can verify the reasoning.
- See
references/_sections.md for category ordering rationale, and assets/templates/_template.md when adding new rules.
Reference Files
| File |
Description |
| references/_sections.md |
Category definitions, impact levels, and ordering rationale |
| assets/templates/_template.md |
Template for adding new rules |
| metadata.json |
Discipline, type, and source references |
Related Skills
bug-review — Multi-pass PR bug review (this skill is a focused complement for performance issues specifically)
- A language-specific best-practices skill (React, Python, Go) — covers idioms beyond Big-O; pair with this skill for performance-critical reviews
1---2name: algorithmic-complexity-review3description: Algorithmic complexity (Big-O) review — finding nested loops, N+1 queries, exponential recursion, quadratic string builds, and other accidental complexity blowups. Covers Python, JavaScript/TypeScript, Java, Go, and similar languages. Use whenever writing, reviewing, or refactoring code where Big-O matters. Trigger even when the user doesn't mention "Big-O" explicitly — if they're reviewing code for performance, refactoring a hot path, asking "why is this slow," or working with data that scales (loops, recursions, collections, ORM access), apply this skill to classify the time/space complexity and suggest the fix. Especially trigger on tasks like "review for performance," "find slow code," "make this faster," "this code is O(n²)," or when reading code that processes collections.4---5# dot-skills Algorithmic Complexity (Big-O) Best Practices
6
7Find, classify, and fix algorithmic complexity (Big-O) problems in code — language-agnostic. The 39 rules across 8 categories cover the patterns responsible for the vast majority of accidental quadratic, exponential, and N+1 blowups in production code: nested iteration, loop-invariant I/O, data-structure mismatch, recursion explosions, redundant computation, collection-building anti-patterns, search/sort selection, and space traps.
8
9## When to Apply
10
11Use this skill when:
12
13- Reviewing a pull request or function for performance regressions
14- Asked "why is this slow?" or "can we make this faster?"
15- Refactoring a hot path or a function that handles user-scaled input
16- Reading code that contains: nested loops, `.includes`/`.find`/`x in list` inside iteration, ORM access in a loop, recursion without memoization, string/array building via `+=` or spread, file/database I/O inside iteration
17- Reviewing code that processes lists, trees, or streams whose size will grow
18
19## Workflow: Find, Classify, Fix
20
21The skill is structured for a three-step workflow on any code under review:
22
23### 1. Find — Scan for the Suspicion Patterns
24
25Look for these structural signals first (highest hit rate):
26
27| Signal | Likely Category | First Rule to Check |
28|--------|-----------------|---------------------|
29| Two nested `for` loops | `nested-` | [nested-explicit-quadratic-loops](references/nested-explicit-quadratic-loops.md) |
30| `.includes` / `.find` / `x in list` inside a loop | `nested-` | [nested-includes-in-loop](references/nested-includes-in-loop.md) |
31| ORM access inside a loop (`for o in orders: o.customer.x`) | `io-` | [io-n-plus-one-query](references/io-n-plus-one-query.md) |
32| `await fetch` in `for-of` | `io-` | [io-sequential-await-in-loop](references/io-sequential-await-in-loop.md) |
33| `array.find` to "join" two arrays | `ds-` | [ds-hashmap-for-keyed-access](references/ds-hashmap-for-keyed-access.md) |
34| Recursive function with overlapping arguments | `rec-` | [rec-memoize-overlapping-subproblems](references/rec-memoize-overlapping-subproblems.md) |
35| `s = s + part` or `[...acc, x]` in a loop | `build-` | [build-avoid-quadratic-string-concat](references/build-avoid-quadratic-string-concat.md), [build-avoid-spread-in-reducer](references/build-avoid-spread-in-reducer.md) |
36| `sorted(...)` called inside a loop | `search-` | [search-sort-once-outside-loop](references/search-sort-once-outside-loop.md) |
37| `readlines()` / loading whole files | `space-` | [space-stream-dont-load](references/space-stream-dont-load.md) |
38
39### 2. Classify — Derive the Big-O
40
41Compute complexity from the code structure:
42
43| Structure | Complexity |
44|-----------|------------|
45| Single loop over n items, O(1) body | O(n) |
46| Two nested loops over n / m items | O(n*m) |
47| Loop calling an O(n) operation (`.includes`, `.find`, `x in list`) | O(n*m), often misread as O(n) |
48| Recursive `f(n) = f(n-1) + f(n-2)` without memoization | O(2ⁿ) |
49| Recursive `f(n) = 2*f(n/2) + O(n)` | O(n log n) |
50| Recursive `f(n) = 2*f(n/2) + O(1)` | O(n) (full tree traversal) |
51| Recursive `f(n) = f(n/2) + O(1)` | O(log n) |
52| `s = s + part` in a loop | O(n²) (string immutability) |
53| `[...acc, x]` in a reduce | O(n²) (copy-on-spread) |
54| Query/RPC inside loop over n items | O(n) round trips |
55
56When in doubt, ask: **"As input doubles, does runtime roughly double (linear), quadruple (quadratic), or do something worse (exponential)?"** That's the practical complexity class.
57
58### 3. Fix — Apply the Pattern From the Matching Rule
59
60Each reference file in `references/` is a `{category}-{slug}.md` containing:
61- WHY the pattern matters (the cascade effect)
62- An **Incorrect** code example with the cost annotated
63- A **Correct** example with the minimal diff
64- When NOT to apply the fix (the rule has exceptions)
65
66The minimal diff philosophy is intentional: the goal is for the agent to see exactly how few lines need to change to flip the complexity class.
67
68## Rule Categories by Priority
69
70| # | Category | Prefix | Impact | Rules |
71|---|----------|--------|--------|-------|
72| 1 | Nested Iteration Patterns | `nested-` | CRITICAL | 6 |
73| 2 | Loop-Invariant I/O and N+1 | `io-` | CRITICAL | 5 |
74| 3 | Data Structure Mismatch | `ds-` | HIGH | 6 |
75| 4 | Recursion Complexity | `rec-` | HIGH | 5 |
76| 5 | Redundant Computation | `compute-` | MEDIUM-HIGH | 5 |
77| 6 | Collection Building | `build-` | MEDIUM | 4 |
78| 7 | Search & Sort Selection | `search-` | MEDIUM | 4 |
79| 8 | Space Complexity Traps | `space-` | LOW-MEDIUM | 4 |
80
81See [`references/_sections.md`](references/_sections.md) for the full ordering rationale.
82
83## Quick Reference
84
85### 1. Nested Iteration Patterns (CRITICAL)
86
87- [`nested-explicit-quadratic-loops`](references/nested-explicit-quadratic-loops.md) — Replace pairwise loops with hash-based single passes
88- [`nested-includes-in-loop`](references/nested-includes-in-loop.md) — Avoid `.includes()` / `.indexOf()` inside a loop
89- [`nested-find-in-loop`](references/nested-find-in-loop.md) — Pre-index lookups instead of `.find()` per iteration
90- [`nested-cartesian-comparison`](references/nested-cartesian-comparison.md) — Group by key instead of cartesian comparison
91- [`nested-set-operations-on-arrays`](references/nested-set-operations-on-arrays.md) — Use sets for intersection, union, difference
92- [`nested-substring-search-in-loop`](references/nested-substring-search-in-loop.md) — Tokenize once instead of re-scanning per pattern
93
94### 2. Loop-Invariant I/O and N+1 Queries (CRITICAL)
95
96- [`io-n-plus-one-query`](references/io-n-plus-one-query.md) — Eliminate N+1 queries by fetching related data in one round trip
97- [`io-sequential-await-in-loop`](references/io-sequential-await-in-loop.md) — Run independent async operations in parallel
98- [`io-batch-instead-of-per-item`](references/io-batch-instead-of-per-item.md) — Use batch endpoints instead of per-item calls
99- [`io-file-read-in-loop`](references/io-file-read-in-loop.md) — Read or stat files outside tight loops
100- [`io-missing-eager-load`](references/io-missing-eager-load.md) — Eager-load ORM relations you will access
101
102### 3. Data Structure Mismatch (HIGH)
103
104- [`ds-hashmap-for-keyed-access`](references/ds-hashmap-for-keyed-access.md) — Store records keyed in a hashmap, not as parallel arrays
105- [`ds-heap-for-top-k`](references/ds-heap-for-top-k.md) — Use a heap for top-k, not full sort + slice
106- [`ds-deque-for-front-operations`](references/ds-deque-for-front-operations.md) — Use a deque for front insertions and removals
107- [`ds-counter-for-histograms`](references/ds-counter-for-histograms.md) — Use Counter / multiset for frequency counting
108- [`ds-sorted-structure-for-range-queries`](references/ds-sorted-structure-for-range-queries.md) — Use a sorted structure for range queries
109- [`ds-trie-for-prefix-search`](references/ds-trie-for-prefix-search.md) — Use a trie for prefix search
110
111### 4. Recursion Complexity (HIGH)
112
113- [`rec-memoize-overlapping-subproblems`](references/rec-memoize-overlapping-subproblems.md) — Memoize recursion with overlapping subproblems
114- [`rec-tabulate-bottom-up`](references/rec-tabulate-bottom-up.md) — Tabulate bottom-up to eliminate recursion overhead
115- [`rec-iterative-for-deep-recursion`](references/rec-iterative-for-deep-recursion.md) — Use an explicit stack instead of deep recursion
116- [`rec-prune-with-bounds`](references/rec-prune-with-bounds.md) — Prune recursive search with bounds and constraints
117- [`rec-share-memo-across-top-level-calls`](references/rec-share-memo-across-top-level-calls.md) — Share memoization across top-level calls
118
119### 5. Redundant Computation (MEDIUM-HIGH)
120
121- [`compute-hoist-loop-invariants`](references/compute-hoist-loop-invariants.md) — Hoist loop-invariant computation outside the loop
122- [`compute-precompile-regex`](references/compute-precompile-regex.md) — Pre-compile regex patterns
123- [`compute-cache-expensive-pure-results`](references/compute-cache-expensive-pure-results.md) — Cache expensive pure-function results
124- [`compute-cache-property-lookup`](references/compute-cache-property-lookup.md) — Cache repeated property lookups in hot loops
125- [`compute-defer-or-short-circuit`](references/compute-defer-or-short-circuit.md) — Defer or short-circuit work you might not need
126
127### 6. Collection Building (MEDIUM)
128
129- [`build-avoid-quadratic-string-concat`](references/build-avoid-quadratic-string-concat.md) — Build strings with joins or builders, not repeated concatenation
130- [`build-avoid-spread-in-reducer`](references/build-avoid-spread-in-reducer.md) — Push to a mutable accumulator instead of spreading
131- [`build-avoid-immutable-object-spread`](references/build-avoid-immutable-object-spread.md) — Use a plain object build phase, then freeze
132- [`build-presize-when-length-known`](references/build-presize-when-length-known.md) — Pre-size collections when the length is known
133
134### 7. Search & Sort Selection (MEDIUM)
135
136- [`search-binary-search-on-sorted`](references/search-binary-search-on-sorted.md) — Use binary search on sorted data
137- [`search-sort-once-outside-loop`](references/search-sort-once-outside-loop.md) — Sort once outside the loop, not on every iteration
138- [`search-quickselect-not-full-sort`](references/search-quickselect-not-full-sort.md) — Use quickselect for the k-th element, not full sort
139- [`search-build-index-once-amortize`](references/search-build-index-once-amortize.md) — Build the index once when queries dominate
140
141### 8. Space Complexity Traps (LOW-MEDIUM)
142
143- [`space-stream-dont-load`](references/space-stream-dont-load.md) — Stream large inputs instead of loading them whole
144- [`space-generators-over-intermediate-lists`](references/space-generators-over-intermediate-lists.md) — Pipe through generators instead of materializing intermediate lists
145- [`space-shallow-not-deep-copy`](references/space-shallow-not-deep-copy.md) — Use shallow copies (or no copy) instead of deep clones
146- [`space-release-retained-references`](references/space-release-retained-references.md) — Release references that prevent garbage collection
147
148## How to Use
149
1501. Start with the **Find** signal table above to locate the most likely pattern.
1512. Open the matching reference file for the WHY and the minimal-diff fix.
1523. If you're classifying complexity from scratch, use the **Classify** table to derive Big-O from code structure.
1534. When proposing a fix, quote the rule by file path so reviewers can verify the reasoning.
1545. See [`references/_sections.md`](references/_sections.md) for category ordering rationale, and [`assets/templates/_template.md`](assets/templates/_template.md) when adding new rules.
155
156## Reference Files
157
158| File | Description |
159|------|-------------|
160| [references/_sections.md](references/_sections.md) | Category definitions, impact levels, and ordering rationale |
161| [assets/templates/_template.md](assets/templates/_template.md) | Template for adding new rules |
162| [metadata.json](metadata.json) | Discipline, type, and source references |
163
164## Related Skills
165
166- `bug-review` — Multi-pass PR bug review (this skill is a focused complement for performance issues specifically)
167- A language-specific best-practices skill (React, Python, Go) — covers idioms beyond Big-O; pair with this skill for performance-critical reviews