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 - As…

) # compile each iter\n if pattern.match(line.upper()) and os.environ.get('STRICT') == '1':\n ...\n# 100,000 lines × ~10μs regex compile = 1 second of compilation alone\n```\n\n**Correct (compute once, reference inside):**\n\n```python\nimport os, re\npattern = re.compile(r'^\\s*(WARN|ERROR)\\s+(.*)

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 - As…

)\nstrict = os.environ.get('STRICT') == '1'\nfor line in lines:\n if pattern.match(line.upper()) and strict:\n ...\n# Compile + env lookup happen once\n```\n\n**Alternative (loop-invariant DOM in browser code):**\n\n```javascript\n// Avoid: each .className access does a string allocation and DOM read\nfor (const el of nodes) {\n if (el.className.includes('active')) { ... } // DOM property read\n}\n\n// Better: convert to a Set once, drop DOM lookups inside the loop\nconst active = new Set(document.querySelectorAll('.active'));\nfor (const el of nodes) {\n if (active.has(el)) { ... }\n}\n```\n\n**When NOT to use this pattern:**\n- When the expression appears to be invariant but actually mutates (subtle aliasing). Verify with a test.\n- When hoisting hurts readability and the loop is cold — premature optimization. Profile before refactoring obscure code.\n\nReference: [Wikipedia — loop-invariant code motion (compiler optimization)](https://en.wikipedia.org/wiki/Loop-invariant_code_motion)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2469,"content_sha256":"169928683e95ebf82953e62f4ad48f28aab90010203dffb792be500f4def06dc"},{"filename":"references/compute-precompile-regex.md","content":"---\ntitle: Compile Regex Patterns Once at Module Level\nimpact: MEDIUM\nimpactDescription: 5-50× per regex use — compilation typically dominates matching for short inputs\ntags: compute, regex, precompile, hoisting, caching\n---\n\n## Compile Regex Patterns Once at Module Level\n\nRegex compilation walks the pattern, parses it, builds an NFA/DFA, and allocates. Matching is the cheap part — for short inputs, matching against a precompiled regex can be 10-50× faster than the equivalent `re.match(r'...', s)` call. Python's `re` module caches the last ~512 patterns automatically, so the impact is smaller there than people fear, but you still pay a dict lookup; in JavaScript, `new RegExp(pattern)` in a hot path has no module-level cache and recompiles every time. The portable rule: compile any regex used more than once into a module-level constant.\n\n**Incorrect (recompile per call):**\n\n```javascript\nfunction isEmail(s, locale) {\n // Pattern built from a string — V8 cannot cache this across calls\n const pattern = `^[^@]+@[^@]+\\\\.[^@]+\\\\.${locale} algorithmic-complexity-review — Skillopedia ;\n return new RegExp(pattern).test(s); // compile every call\n}\n// 1,000,000 validations → 1,000,000 compilations\n```\n\n**Correct (compile once at module level, or cache by locale):**\n\n```javascript\nconst EMAIL_RE_BY_LOCALE = new Map();\n\nfunction isEmail(s, locale) {\n let re = EMAIL_RE_BY_LOCALE.get(locale);\n if (!re) {\n re = new RegExp(`^[^@]+@[^@]+\\\\.[^@]+\\\\.${locale} algorithmic-complexity-review — Skillopedia );\n EMAIL_RE_BY_LOCALE.set(locale, re);\n }\n return re.test(s);\n}\n// N distinct locales → N compilations total, regardless of call count\n```\n\n**Alternative (Python — module-level constant or `re.compile`):**\n\n```python\nimport re\n_EMAIL_RE = re.compile(r'^[^@]+@[^@]+\\.[^@]+

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 - As…

)\n\ndef is_email(s):\n return bool(_EMAIL_RE.match(s))\n```\n\n**When NOT to use this pattern:**\n- When the pattern is genuinely dynamic per call (built from user input) — you must compile each time. Cache compiled patterns in a dict if the *set* of dynamic patterns is small.\n- For one-off matches outside any loop — inline regex is clearer and the cost is negligible.\n\nReference: [Python `re` module — performance considerations](https://docs.python.org/3/library/re.html#re.compile)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2232,"content_sha256":"2c0af5887f07a5ffb989c2dcf780742a11f4034059cef9b5b03c1765252c4ca2"},{"filename":"references/ds-counter-for-histograms.md","content":"---\ntitle: Use Counter / Multiset for Frequency Counting\nimpact: MEDIUM-HIGH\nimpactDescription: O(n²) to O(n) — and replaces 5-10 lines with one\ntags: ds, counter, multiset, histogram, frequency\n---\n\n## Use Counter / Multiset for Frequency Counting\n\nFrequency counting (\"how many times does each value appear?\") and the related most-common / top-k questions are common enough that the standard library has a primitive for them: `collections.Counter` (Python), `MultiSet` in Apache Commons (Java), `lodash.countBy` / `Map` (JS). The manual implementation — initialize a dict, check `if key not in counts`, increment — works but is verbose, easy to get wrong (forgetting the default), and slower than the C-optimized Counter. The Counter primitive also exposes `most_common(k)`, which uses a bounded heap internally and is the right structure for top-k frequency questions.\n\n**Incorrect (manual increment — O(n) but error-prone, no top-k helper):**\n\n```python\ncounts = {}\nfor word in words:\n if word in counts:\n counts[word] += 1\n else:\n counts[word] = 1\n\n# Now find the top 10 words — manual sort, full O(n log n):\ntop_10 = sorted(counts.items(), key=lambda kv: -kv[1])[:10]\n```\n\n**Correct (`Counter`):**\n\n```python\nfrom collections import Counter\ncounts = Counter(words) # O(n), C-optimized\ntop_10 = counts.most_common(10) # O(n log 10) via internal heap\n```\n\n**Alternative (JavaScript):**\n\n```javascript\n// Map preserves insertion order, supports any key type\nconst counts = new Map();\nfor (const w of words) counts.set(w, (counts.get(w) ?? 0) + 1);\n```\n\n**When NOT to use this pattern:**\n- When you need a sliding-window count over a stream — a `Counter` rebuilt per window is wasteful; maintain it incrementally with add/remove deltas.\n\nReference: [Python `collections.Counter` — frequency dictionary subclass](https://docs.python.org/3/library/collections.html#collections.Counter)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":1935,"content_sha256":"4275ac73b98ef2017e12e7da61ab7aaeb9c2372477c3b0435a918c00879b9793"},{"filename":"references/ds-deque-for-front-operations.md","content":"---\ntitle: Use a Deque for Front Insertions and Removals\nimpact: HIGH\nimpactDescription: O(n) per op to O(1) — flips queue/sliding-window code from quadratic to linear\ntags: ds, deque, queue, sliding-window, front-insert\n---\n\n## Use a Deque for Front Insertions and Removals\n\n`list.pop(0)`, `list.insert(0, x)`, `Array.prototype.shift`, and `Array.prototype.unshift` all run in O(n) because the underlying contiguous array must memmove every element one slot. Used inside a loop — say, a BFS dequeue or a sliding-window slide — they turn an O(n) algorithm into O(n²). A double-ended queue (`collections.deque` in Python, `ArrayDeque` in Java, `LinkedList` or a ring buffer in JS) supports both ends in O(1).\n\n**Incorrect (list as a queue — O(n²) for n dequeues):**\n\n```python\nqueue = list(initial_items)\nwhile queue:\n item = queue.pop(0) # O(n) shift of remaining elements\n for child in children(item):\n queue.append(child)\n# n items dequeued → O(n²) total\n```\n\n**Correct (deque — O(n) total):**\n\n```python\nfrom collections import deque\nqueue = deque(initial_items)\nwhile queue:\n item = queue.popleft() # O(1)\n for child in children(item):\n queue.append(child)\n```\n\n**Alternative (sliding window over a stream):**\n\n```python\nfrom collections import deque\nwindow = deque(maxlen=K) # auto-evicts the oldest on append when full\nfor value in stream:\n window.append(value) # O(1) — old element drops out for free\n process(window)\n```\n\n**When NOT to use this pattern:**\n- When the queue is provably tiny (≲ ~30 items) and bounded — the constant factors of `deque` and `list` are similar; choose for readability.\n- In JavaScript, when you need random access by index frequently — a deque library may not match `Array`'s indexed access; consider a ring buffer or two stacks if appropriate.\n\nReference: [Python `collections.deque` — O(1) appends and pops from either end](https://docs.python.org/3/library/collections.html#collections.deque)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2029,"content_sha256":"0da8ae77eae08ddee4e8fb080a797faedce58ac821d3b1763452f06a71844449"},{"filename":"references/ds-hashmap-for-keyed-access.md","content":"---\ntitle: Store Records Keyed in a Hashmap, Not as Parallel Arrays\nimpact: HIGH\nimpactDescription: O(n) per lookup to O(1) — flips entire access patterns linear\ntags: ds, hashmap, indexing, dictionary, lookup\n---\n\n## Store Records Keyed in a Hashmap, Not as Parallel Arrays\n\nIf callers will retrieve records by an ID, store them in a `Map`/`dict` keyed by that ID. The mistake is keeping the result of an API call or query as a flat array and reaching for `.find` every time you need one entry — each lookup is O(n), so any code that touches the collection more than once silently scales as O(n²). The fix is a one-time O(n) reshape after the data arrives. This is the same idea as [`nested-find-in-loop`](nested-find-in-loop.md), but framed as a data-modeling decision at the boundary where the collection enters the system, not a refactor at the loop.\n\n**Incorrect (array storage, repeated find — O(n) per access):**\n\n```typescript\nconst users: User[] = await api.getUsers();\n\nfunction getName(id: string) {\n return users.find(u => u.id === id)?.name; // O(n) every call\n}\n\n// 1,000 page renders × find on 50,000 users = 50,000,000 comparisons\n```\n\n**Correct (hashmap storage — O(1) per access):**\n\n```typescript\nconst userArray = await api.getUsers();\nconst users = new Map(userArray.map(u => [u.id, u])); // O(n) once\n\nfunction getName(id: string) {\n return users.get(id)?.name; // O(1)\n}\n```\n\n**Alternative (when iteration order matters):**\n\n```typescript\n// JS Map preserves insertion order — supports both random access and ordered iteration\nconst users = new Map(userArray.map(u => [u.id, u]));\nfor (const user of users.values()) { ... } // ordered iteration\nusers.get(id); // O(1) random access\n```\n\n**When NOT to use this pattern:**\n- When the collection is iterated once and never looked up again — the hashmap conversion is wasted work.\n- When IDs are not stable (e.g., transient queue messages) — a hashmap of moving keys still works but offers no real advantage.\n\nReference: [JavaScript `Map` — ECMAScript spec mandates sublinear average access (amortized O(1))](https://tc39.es/ecma262/#sec-map-objects)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2197,"content_sha256":"624f9a88454a8c6af2c43cf327e5b25394e34948d697de059e9565697a2fa33a"},{"filename":"references/ds-heap-for-top-k.md","content":"---\ntitle: Use a Heap for Top-K, Not Full Sort + Slice\nimpact: HIGH\nimpactDescription: O(n log n) to O(n log k) — 10-1000× speedup when k \u003c\u003c n\ntags: ds, heap, top-k, priority-queue, partial-sort\n---\n\n## Use a Heap for Top-K, Not Full Sort + Slice\n\n\"Find the top 10 scores from a million entries\" doesn't need a full sort. A sort is O(n log n) and produces a fully ordered list you immediately throw 999,990 elements of. A bounded min-heap of size k visits each element once, pushing if it's larger than the current minimum — O(n log k) total, which is dramatically faster when k is small relative to n. The Python `heapq.nlargest`, JS `priority-queue` libraries, and Java `PriorityQueue` all implement this directly.\n\n**Incorrect (sort everything then take k — O(n log n)):**\n\n```python\ntop_10 = sorted(scores, reverse=True)[:10]\n# 1,000,000 scores: full sort touches every element, O(n log n) ≈ 20M ops\n```\n\n**Correct (bounded heap — O(n log k)):**\n\n```python\nimport heapq\ntop_10 = heapq.nlargest(10, scores)\n# 1,000,000 scores: O(n log 10) ≈ 3.3M ops, plus much less memory churn\n```\n\n**Alternative (when items have a key function):**\n\n```python\ntop_10_users = heapq.nlargest(10, users, key=lambda u: u.score)\n```\n\n**When NOT to use this pattern:**\n- When k is close to n (e.g., top 90% of 100 items) — the heap saves nothing; a full sort is clearer.\n- When you also need the remaining items in some order — you'll sort anyway; combine the two passes.\n\nReference: [Python `heapq.nlargest` — runs in O(n log k)](https://docs.python.org/3/library/heapq.html#heapq.nlargest)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":1593,"content_sha256":"0c0a7a2c8d395665f96a5172430471a08731e8dfcd50ef548f72302afe8cca88"},{"filename":"references/ds-sorted-structure-for-range-queries.md","content":"---\ntitle: Use a Sorted Structure for Range Queries\nimpact: HIGH\nimpactDescription: O(n) per range query to O(log n + k) — k = result size\ntags: ds, sorted-set, tree-map, range-query, balanced-tree\n---\n\n## Use a Sorted Structure for Range Queries\n\n\"Give me every event between t₁ and t₂\" against an unsorted list forces a full scan — O(n) per query. A balanced binary search tree (`TreeMap` in Java, `std::map` in C++, `sortedcontainers.SortedDict` in Python) finds the lower bound in O(log n) and walks forward until t₂ — O(log n + k) where k is the result count. The same applies to \"smallest item ≥ x,\" \"largest ≤ x,\" and \"k-th order statistic\" — questions that are answered in microseconds against a sorted structure and seconds against a list.\n\n**Incorrect (linear scan per query — O(n) each):**\n\n```python\nevents = [...] # 500,000 events, unsorted by timestamp\n\ndef events_in_range(t1, t2):\n return [e for e in events if t1 \u003c= e.timestamp \u003c= t2] # O(n)\n\n# 1,000 queries × 500,000 = 500,000,000 comparisons\n```\n\n**Correct (sorted structure — O(log n + k) per query):**\n\n```python\nfrom sortedcontainers import SortedDict\nevents_by_ts = SortedDict()\nfor e in events:\n events_by_ts[e.timestamp] = e # O(n log n) once\n\ndef events_in_range(t1, t2):\n return list(events_by_ts.irange(t1, t2)) # O(log n + k)\n```\n\n**Alternative (when range queries are rare but inserts are frequent):**\n\n```python\n# If reads are bursty after a load phase, sort once and use bisect\nimport bisect\nevents.sort(key=lambda e: e.timestamp)\ntimestamps = [e.timestamp for e in events]\n\ndef events_in_range(t1, t2):\n lo = bisect.bisect_left(timestamps, t1)\n hi = bisect.bisect_right(timestamps, t2)\n return events[lo:hi] # O(log n + k)\n```\n\n**When NOT to use this pattern:**\n- When ranges almost always cover most of the data — the structural advantage shrinks; a plain sorted list with `bisect` is simpler.\n- When you also need approximate-membership queries on a stream — consider a Bloom filter or count-min sketch instead.\n\nReference: [`sortedcontainers.SortedDict` — exposes `irange` and `irange_key` in O(log n + k)](http://www.grantjenks.com/docs/sortedcontainers/sorteddict.html)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2245,"content_sha256":"64a1d33360b85b6c6b9309fa729d9f99834bb087cabf06c6d693675dab975b99"},{"filename":"references/ds-trie-for-prefix-search.md","content":"---\ntitle: Use a Trie for Prefix Search\nimpact: MEDIUM-HIGH\nimpactDescription: O(n*L) per query to O(L + k) — k = matches, L = query length\ntags: ds, trie, prefix-tree, autocomplete, string-search\n---\n\n## Use a Trie for Prefix Search\n\nAutocomplete and prefix-match queries against a list of strings are O(n*L) — for every one of n entries, check whether its first L characters match. A trie indexes by character, so a prefix query walks L levels down the tree and then enumerates only matching leaves — O(L + k) where k is the result count. For a dictionary of 100,000 words, prefix lookup is microseconds against a trie versus tens of milliseconds against a list. The same structure also accelerates \"is X a prefix of any stored word?\" — a single tree walk gives a yes/no answer.\n\n**Incorrect (linear scan per query — O(n*L)):**\n\n```python\ndef autocomplete(prefix, words):\n return [w for w in words if w.startswith(prefix)]\n# 100,000 words × ~8-char prefix check = ~800K character comparisons per keystroke\n```\n\n**Correct (trie — O(L + k) per query):**\n\n```python\n# Tiny trie sketch — production: use `pygtrie`, `marisa-trie`, or build with classes\ntrie = {}\nfor word in words:\n node = trie\n for ch in word:\n node = node.setdefault(ch, {})\n node['

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 - As…

] = word # mark word boundary\n\ndef autocomplete(prefix, trie):\n node = trie\n for ch in prefix:\n if ch not in node:\n return []\n node = node[ch]\n return _collect(node) # DFS from current node — O(k)\n\ndef _collect(node):\n out = []\n if '

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 - As…

in node: out.append(node['

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 - As…

])\n for ch, child in node.items():\n if ch != '

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 - As…

: out.extend(_collect(child))\n return out\n```\n\n**Alternative (sorted array + binary search for static dictionaries):**\n\n```python\nimport bisect\nwords.sort()\ndef autocomplete(prefix):\n lo = bisect.bisect_left(words, prefix)\n out = []\n while lo \u003c len(words) and words[lo].startswith(prefix):\n out.append(words[lo]); lo += 1\n return out\n# O(log n + k) per query — simpler than a trie, similar perf for static data\n```\n\n**When NOT to use this pattern:**\n- When the dictionary is small (≲ 1,000 words) and queries are infrequent — the constant factors dominate.\n- When you also need fuzzy matching — reach for BK-trees, Levenshtein automata, or n-gram indexes instead.\n\nReference: [Trie (NIST DADS) — prefix-tree data structure](https://xlinux.nist.gov/dads/HTML/trie.html)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2482,"content_sha256":"2cc18015788a95d1a0af316147acead7fce3e8d9ed864f4690d491a40ce86bab"},{"filename":"references/io-batch-instead-of-per-item.md","content":"---\ntitle: Use Batch Endpoints Instead of Per-Item Calls\nimpact: CRITICAL\nimpactDescription: N calls to 1 batched call — 10-100× latency reduction\ntags: io, batching, bulk-api, network, dataloader\n---\n\n## Use Batch Endpoints Instead of Per-Item Calls\n\nMost well-designed APIs expose batch variants (`/users?ids=1,2,3`, `INSERT ... VALUES (...), (...), (...)`, `mset`, `multiGet`) precisely because individual calls amortize poorly: each one pays TLS, auth, framing, and routing overhead regardless of payload size. A single batched call typically handles 100-1000 items for less wall-clock time than two individual calls, because the cost is dominated by round trips, not per-item work. Reach for the batch variant whenever the loop body is \"send one thing over the wire\" and the call sites are inside the same logical operation.\n\n**Incorrect (per-item calls — N round trips):**\n\n```python\n# Redis client — one round trip per key\nfor user_id in user_ids: # 500 ids\n pipe.append(redis.get(f\"user:{user_id}\")) # 500 round trips\n```\n\n**Correct (single batch call):**\n\n```python\nkeys = [f\"user:{uid}\" for uid in user_ids]\nvalues = redis.mget(keys) # 1 round trip\n```\n\n**Alternative (auto-batching with DataLoader / accumulator):**\n\n```javascript\n// GraphQL / Node — DataLoader collects calls in one tick, batches them\nimport DataLoader from 'dataloader';\nconst userLoader = new DataLoader(ids => fetchUsersByIds(ids));\n\n// Each call looks individual but is auto-batched per event-loop tick\nconst u1 = await userLoader.load(1);\nconst u2 = await userLoader.load(2);\n// Underlying call: fetchUsersByIds([1, 2]) — one round trip\n```\n\n**When NOT to use this pattern:**\n- When the API has a hard batch-size limit and N >> limit — chunk into batches of `limit` and `Promise.all` the chunks; see [`io-sequential-await-in-loop`](io-sequential-await-in-loop.md).\n- When per-item operations need independent error handling — a partial-failure batch API helps; otherwise consider `Promise.allSettled` over individual calls.\n\nReference: [graphql/dataloader — batching and caching](https://github.com/graphql/dataloader)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2182,"content_sha256":"d32c44390d690c61d6b05c4a3ea284bb3c6ef7c1d3157b8859a547b0732d37eb"},{"filename":"references/io-file-read-in-loop.md","content":"---\ntitle: Read or Stat Files Outside Tight Loops\nimpact: HIGH\nimpactDescription: O(n) syscalls eliminated — 10-100× speedup on disk-bound code\ntags: io, filesystem, syscall, caching, batching\n---\n\n## Read or Stat Files Outside Tight Loops\n\nEvery `open()`, `read()`, `stat()`, `exists()` is a kernel transition. On a hot path, syscalls dominate runtime even when the data is in OS page cache — the user→kernel→user trip costs microseconds that add up to seconds at N=100k. The right pattern is one of: (1) read the file once outside the loop, (2) bulk-walk the directory with a single `os.scandir` / `fs.readdir`, or (3) memoize the result if it can't change during the run. The wrong pattern is \"re-check the config file\" or \"open this template\" inside each iteration of a request handler.\n\n**Incorrect (re-read per iteration — N syscalls):**\n\n```python\n# Render each row through the same template — file read N times\nfor row in rows: # 50,000 rows\n with open('template.txt') as f: # syscall per row\n template = f.read()\n print(template.format(**row))\n```\n\n**Correct (hoist the read — 1 syscall):**\n\n```python\nwith open('template.txt') as f: # once\n template = f.read()\nfor row in rows:\n print(template.format(**row))\n```\n\n**Alternative (caching when reads must respect mtime):**\n\n```python\nfrom functools import lru_cache\nimport os\n\n@lru_cache(maxsize=128)\ndef _load_template(path, mtime):\n with open(path) as f:\n return f.read()\n\ndef load_template(path):\n return _load_template(path, os.stat(path).st_mtime)\n# First load: 2 syscalls (stat + read). Subsequent: 1 syscall (stat only).\n```\n\n**When NOT to use this pattern:**\n- When the file is genuinely expected to change during the loop (log tail, control file). Then the per-iteration cost is intrinsic — consider inotify/FSEvents instead of polling.\n\nReference: [Python `os.scandir` is faster than `listdir`+`stat` because it avoids the per-entry syscall](https://docs.python.org/3/library/os.html#os.scandir)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2072,"content_sha256":"74e107a708671ea09269e9fa2e077c91729059c081980219cea39b5572f8254d"},{"filename":"references/io-missing-eager-load.md","content":"---\ntitle: Declare Eager-Loading for ORM Relations You Will Access\nimpact: CRITICAL\nimpactDescription: N+1 to 1-2 queries — same as N+1 but framed at the schema-traversal level\ntags: io, eager-loading, orm, prefetch, select-related\n---\n\n## Declare Eager-Loading for ORM Relations You Will Access\n\nMost ORMs lazy-load relations: accessing `order.customer.address.city` issues a query the first time each `.` is dereferenced. Inside a loop, this hides N+1 (then N+1+N, then N+1+N+M…) behind property accesses. Declare upfront which relations the code path needs (`select_related`, `prefetch_related`, `Include`, `JOIN FETCH`) so the ORM emits one or two joined queries instead of a fan-out. This is the same problem as [`io-n-plus-one-query`](io-n-plus-one-query.md) but framed at the schema-graph level: you must tell the ORM *how deep* you intend to traverse.\n\n**Incorrect (lazy chains issue queries on every dot):**\n\n```python\n# Django — 1 + N + N queries for a 2-deep traversal\norders = Order.objects.all()\nfor order in orders:\n print(order.customer.name) # query 1\n print(order.customer.address.city) # query 2\n# 200 orders → 401 queries\n```\n\n**Correct (declare the traversal upfront):**\n\n```python\norders = Order.objects.select_related('customer__address').all()\nfor order in orders:\n print(order.customer.name) # already joined\n print(order.customer.address.city) # already joined\n# 200 orders → 1 query\n```\n\n**Alternative (collection relations use prefetch):**\n\n```python\n# Many line items per order — JOIN would explode rows; use a 2-query plan\norders = (\n Order.objects\n .select_related('customer')\n .prefetch_related('line_items__product')\n)\n```\n\n**Detection:**\nThe Django debug toolbar (or `django.db.connection.queries`) shows query counts per request. Any controller whose query count scales with rendered items is missing an eager load. Sequelize has `logging`, Active Record has `ActiveSupport::Notifications`, Hibernate has SQL logging.\n\nReference: [Hibernate — `JOIN FETCH` for eager loading](https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#fetching)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2207,"content_sha256":"d89968adea6eb3b9f5c26a049aa0363ace015906498d5f3a3ccd9da2378434a4"},{"filename":"references/io-n-plus-one-query.md","content":"---\ntitle: Eliminate N+1 Queries by Fetching Related Data in One Round Trip\nimpact: CRITICAL\nimpactDescription: N+1 round trips to 1-2 — typical 10-100× wall-clock speedup\ntags: io, n-plus-one, orm, batching, database\n---\n\n## Eliminate N+1 Queries by Fetching Related Data in One Round Trip\n\nThe N+1 problem: 1 query to fetch a list, then N queries to fetch each item's related data. Each extra round trip pays the network/parsing cost regardless of how trivial the SQL is. At 200 items and 5ms per query, that's a full second of latency that vanishes if you fetch all related rows in a single query with `IN (...)` or a join. The pattern is universal across ORMs (Active Record, Django, Sequelize, Hibernate, SQLAlchemy) because the lazy-loading default makes the bug invisible at the call site.\n\n**Incorrect (N+1 — one query per item):**\n\n```python\n# Django — issues 1 + len(orders) queries\norders = Order.objects.filter(status='paid') # 1 query\nfor order in orders:\n print(order.customer.name) # 1 query each\n# 200 orders → 201 queries → 201 round trips\n```\n\n**Correct (eager load related rows in one query):**\n\n```python\norders = (\n Order.objects.filter(status='paid')\n .select_related('customer') # JOIN customer in\n)\nfor order in orders:\n print(order.customer.name) # already loaded\n# 200 orders → 1 query\n```\n\n**Alternative (when relation is many-to-many or reverse FK):**\n\n```python\n# Use prefetch_related for collections — 2 queries total, joined in Python\norders = Order.objects.filter(status='paid').prefetch_related('line_items')\n```\n\n**Detection:**\nEnable query logging in development. Any view that issues queries proportional to the number of items rendered has an N+1 — see the framework's debug toolbar or `django.db.connection.queries`.\n\nReference: [Django — `select_related` and `prefetch_related`](https://docs.djangoproject.com/en/stable/ref/models/querysets/#select-related)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2012,"content_sha256":"48b02e8cc277f92e2cdce4f3646a000f99335fc4fd2aecedfafd38e198a7fa59"},{"filename":"references/io-sequential-await-in-loop.md","content":"---\ntitle: Run Independent Async Operations in Parallel\nimpact: CRITICAL\nimpactDescription: sum(latencies) to max(latencies) — typical 5-20× wall-clock speedup\ntags: io, async, promise-all, asyncio-gather, parallelism\n---\n\n## Run Independent Async Operations in Parallel\n\n`for (const x of xs) { await fetch(x) }` runs the requests strictly one after another — total latency is the sum of all request latencies. When the operations don't depend on each other, this serial execution is purely wasteful: every request after the first is waiting on the previous response for no logical reason. `Promise.all` (JS) / `asyncio.gather` (Python) / `errgroup` (Go) issue them concurrently, so total latency collapses to roughly the slowest single request. The complexity class doesn't change but the wall-clock improvement is typically the most visible perf win in any service that fans out to external APIs.\n\n**Incorrect (sequential — Σ latencies):**\n\n```javascript\nconst results = [];\nfor (const id of userIds) {\n results.push(await fetchUser(id)); // each await blocks the next\n}\n// 50 users × 80ms = 4 seconds\n```\n\n**Correct (parallel — max latency):**\n\n```javascript\nconst results = await Promise.all(\n userIds.map(id => fetchUser(id)) // fires all at once\n);\n// 50 users in ~80ms (slowest single request)\n```\n\n**Alternative (bounded concurrency for rate-limited APIs):**\n\n```javascript\nimport pLimit from 'p-limit';\nconst limit = pLimit(10); // at most 10 in flight\nconst results = await Promise.all(\n userIds.map(id => limit(() => fetchUser(id)))\n);\n```\n\n**When NOT to use this pattern:**\n- When operations depend on each other (need the result of step `i` to issue step `i+1`) — that data dependency forces sequencing.\n- When the downstream system is rate-limited or fragile — use bounded concurrency (`p-limit`, `asyncio.Semaphore`) rather than unbounded `Promise.all`.\n\nReference: [MDN — `Promise.all`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2039,"content_sha256":"931c6584396c07a23098113e5c11a77760fe549f319b6c7ffb19090daca3b46d"},{"filename":"references/nested-cartesian-comparison.md","content":"---\ntitle: Group by Key Instead of Cartesian Comparison\nimpact: CRITICAL\nimpactDescription: O(n²) to O(n) — \"find duplicates / similar pairs\" is the canonical case\ntags: nested, grouping, hashmap, deduplication, equivalence-class\n---\n\n## Group by Key Instead of Cartesian Comparison\n\n\"For each pair (i, j), check if they share property X\" is O(n²) by construction — but the question is almost always equivalent to \"group items by property X, then look at groups with more than one member,\" which is O(n). The pairwise version inspects n(n-1)/2 pairs; the grouped version walks the list once. The trick is recognizing that the inner condition (`a.email == b.email`) defines an equivalence class on a hashable key — and equivalence classes are exactly what `defaultdict(list)` builds for free.\n\n**Incorrect (compare every pair — O(n²)):**\n\n```python\nduplicates = []\nfor i in range(len(records)):\n for j in range(i + 1, len(records)):\n if records[i].email == records[j].email:\n duplicates.append((records[i], records[j]))\n# 10,000 records → ~50,000,000 comparisons\n```\n\n**Correct (group by key — O(n)):**\n\n```python\nfrom collections import defaultdict\nbuckets = defaultdict(list)\nfor r in records:\n buckets[r.email].append(r) # O(1)\nduplicates = [bucket for bucket in buckets.values() if len(bucket) > 1]\n# 10,000 records → 10,000 inserts + one walk over buckets\n```\n\n**When NOT to use this pattern:**\n- When the equivalence relation is non-transitive (e.g., \"names within edit-distance 2 of each other\") — grouping by key doesn't apply; reach for clustering, blocking, or locality-sensitive hashing.\n- When you need every pair (not just the existence of one) for downstream pairwise scoring — then the n² work is intrinsic.\n\nReference: [NIST DADS — equivalence relation](https://xlinux.nist.gov/dads/HTML/equivalenceRel.html)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":1885,"content_sha256":"16b02907c3b57ca449d8c0f7b2936c19dce541f9b9d677f1d454299c14b3337d"},{"filename":"references/nested-explicit-quadratic-loops.md","content":"---\ntitle: Replace Pairwise Loops With Hash-Based Single Passes\nimpact: CRITICAL\nimpactDescription: O(n²) to O(n) — 100× faster at n=10,000\ntags: nested, quadratic, hash-set, deduplication, single-pass\n---\n\n## Replace Pairwise Loops With Hash-Based Single Passes\n\nTwo nested loops over the same collection — even when the inner loop starts at `i+1` — produce O(n²) work. At n=10,000 that's 100 million comparisons; at n=1,000,000 it's a trillion. The pattern is almost always avoidable by passing through the data once and remembering what was seen in a hash set or map. The key insight: \"have I seen X before?\" is an O(1) question when you maintain the right index, not an O(n) re-scan.\n\n**Incorrect (pairwise comparison — O(n²)):**\n\n```python\nduplicates = set()\nfor i, a in enumerate(items):\n for j, b in enumerate(items):\n if i != j and a == b:\n duplicates.add(a)\n# 10,000 items → 100,000,000 iterations, ~seconds of CPU\n```\n\n**Correct (single pass with a set — O(n)):**\n\n```python\nseen = set()\nduplicates = set()\nfor item in items:\n if item in seen: # O(1) lookup\n duplicates.add(item)\n seen.add(item)\n# 10,000 items → 10,000 iterations, ~milliseconds\n```\n\n**When NOT to use this pattern:**\n- When `n` is provably tiny (\u003c ~30) and bounded — the hash overhead may dominate, and a nested loop is clearer.\n- When the comparison requires fuzzy matching (similarity, distance) where no hash key applies — consider blocking, LSH, or a spatial index instead.\n\nReference: [Python Time Complexity — set lookup is O(1) amortized](https://wiki.python.org/moin/TimeComplexity)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":1634,"content_sha256":"664a745d5bfd7436bd9772ebae20a54d408217998c43a2d439e2e80014fee529"},{"filename":"references/nested-find-in-loop.md","content":"---\ntitle: Index Lookups Once Instead of `.find()` per Iteration\nimpact: CRITICAL\nimpactDescription: O(n*m) to O(n+m) — application-side join speedup of 50-1000×\ntags: nested, lookup, map, join, pre-index\n---\n\n## Index Lookups Once Instead of `.find()` per Iteration\n\nJoining two collections in application code — \"for each order, find its user\" — naturally invites `.find()` in a `.map()`. Each `.find()` is O(users), making the whole join O(orders × users). Building a `Map` keyed by the join field once is O(users); subsequent lookups are O(1). The complexity flips from quadratic to linear, and the diff is two lines.\n\n**Incorrect (application-side join via `.find()` — O(orders × users)):**\n\n```javascript\nconst enriched = orders.map(o => ({\n ...o,\n user: users.find(u => u.id === o.userId), // scans users each call\n}));\n// 5,000 orders × 20,000 users = 100,000,000 comparisons\n```\n\n**Correct (build index once — O(orders + users)):**\n\n```javascript\nconst userById = new Map(users.map(u => [u.id, u])); // O(users)\nconst enriched = orders.map(o => ({\n ...o,\n user: userById.get(o.userId), // O(1)\n}));\n// 5,000 + 20,000 = 25,000 operations\n```\n\n**Alternative (database-side join):**\n\nIf both collections originate from the same data source, push the join down to SQL or to your ORM's eager-loading mechanism — see [`io-missing-eager-load`](io-missing-eager-load.md). Application-side joins are appropriate when the two sources are different (e.g., DB rows + external API responses).\n\nReference: [MDN — `Map.prototype.get` runs in sublinear average time](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":1694,"content_sha256":"4d943a0b310f7994a699bc4d272cbc8f7f76302696d0a45c0986aa45a0536c2d"},{"filename":"references/nested-includes-in-loop.md","content":"---\ntitle: Avoid `.includes()` / `.indexOf()` Inside a Loop\nimpact: CRITICAL\nimpactDescription: O(n*m) to O(n+m) — typical 50-500× speedup\ntags: nested, hidden-quadratic, set, includes, indexof\n---\n\n## Avoid `.includes()` / `.indexOf()` Inside a Loop\n\n`Array.prototype.includes`, `indexOf`, `find`, and Python's `x in list` all scan linearly — O(n) per call. Calling any of them inside a loop over another collection produces O(n*m) complexity that reads like O(n). This is the single most common hidden-quadratic pattern in production code because the call site looks innocuous: one method call per iteration, no visible nesting. The fix is to pre-build a `Set` (or `Map`) once and convert each membership test from O(n) to O(1).\n\n**Incorrect (looks linear, runs quadratic — O(n*m)):**\n\n```javascript\n// Filter sign-ups that aren't already users\nconst newSignups = recentSignups.filter(s =>\n !existingUsers.includes(s.email) // O(existingUsers) per signup\n);\n// 1,000 signups × 50,000 existing users = 50,000,000 comparisons\n```\n\n**Correct (set membership — O(n+m)):**\n\n```javascript\nconst known = new Set(existingUsers); // O(m) once\nconst newSignups = recentSignups.filter(s =>\n !known.has(s.email) // O(1) per signup\n);\n// 1,000 + 50,000 = 51,000 operations total\n```\n\n**When NOT to use this pattern:**\n- When `existingUsers` is genuinely small (≲ 50) and the inner code is hot enough that hashing the key costs more than scanning — measure first.\n- When elements are not hashable (mutable objects without stable identity); use a `WeakSet` for object identity or extract a stable key.\n\nReference: [MDN — `Set.prototype.has` runs in average O(1)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set#description)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":1817,"content_sha256":"5d7296f3b9394c7bc7c6bc9bdaaf47e9375dfe1f1d9f104a37b989aac7527761"},{"filename":"references/nested-set-operations-on-arrays.md","content":"---\ntitle: Use Sets for Intersection, Union, and Difference\nimpact: CRITICAL\nimpactDescription: O(n*m) to O(n+m) — typical 100× speedup on large lists\ntags: nested, set-operations, intersection, union, difference\n---\n\n## Use Sets for Intersection, Union, and Difference\n\nComputing `A ∩ B`, `A ∪ B`, or `A \\ B` with list-based membership tests (`x in list`, `Array.includes`) is O(|A| × |B|). Converting the inner collection to a hash set once is O(|B|); subsequent membership tests are O(1), and the whole operation drops to O(|A| + |B|). Python, JavaScript, Java, and Go all expose hash sets in the standard library with this exact use case in mind — there is essentially no reason to compute set operations against an unhashed list.\n\n**Incorrect (list-based membership — O(n*m)):**\n\n```python\n# Intersection: items in both A and B\ncommon = [x for x in list_a if x in list_b] # `x in list_b` scans list_b\n# Difference: items in A not in B\nonly_in_a = [x for x in list_a if x not in list_b]\n```\n\n**Correct (hash set — O(n+m)):**\n\n```python\nb_set = set(list_b) # O(m) once\ncommon = [x for x in list_a if x in b_set] # O(1) per check\nonly_in_a = [x for x in list_a if x not in b_set]\n```\n\n**Alternative (when order doesn't matter):**\n\n```python\ncommon = set(list_a) & set(list_b) # O(n + m)\nonly_in_a = set(list_a) - set(list_b)\n```\n\n**When NOT to use this pattern:**\n- When elements are unhashable (e.g., dicts, lists). Either extract a hashable key (`tuple(sorted(d.items()))`) or accept the quadratic cost when n is small.\n- When you need duplicates preserved — sets collapse them; use `collections.Counter` for multiset semantics.\n\nReference: [Python Time Complexity — set operations](https://wiki.python.org/moin/TimeComplexity)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":1792,"content_sha256":"234752b03a423fa0dd85239eb2874b0f3f3fbdab4a4e4c74d4de9b1b9593f7bc"},{"filename":"references/nested-substring-search-in-loop.md","content":"---\ntitle: Tokenize Once Instead of Re-scanning a String per Pattern\nimpact: CRITICAL\nimpactDescription: O(p*L) to O(L+p) per document — across D docs, O(D*p*L) drops to O(D*(L+p))\ntags: nested, string-search, tokenize, hidden-quadratic, aho-corasick\n---\n\n## Tokenize Once Instead of Re-scanning a String per Pattern\n\n`pattern in text` (Python) or `text.includes(pattern)` (JS) scans the full text — O(L) where L is text length. Looping over p patterns and running this check produces O(p*L) per document, which is fine for tiny p but catastrophic when you scan thousands of keywords against thousands of documents. When patterns are whole tokens, the rewrite is trivial: tokenize the text once into a set, then each membership test is O(1). When patterns are arbitrary substrings, use a multi-pattern algorithm (Aho-Corasick) that scans the text once and matches all patterns in a single pass — O(L + p + matches).\n\nNote: the tokenize approach changes matching semantics from substring to whole-token — `\"cat\" in \"concatenate\"` is true for `in`, false after tokenization. For substring matching across multiple patterns, use Aho-Corasick.\n\n**Incorrect (re-scan per pattern — O(p*L)):**\n\n```python\nflagged = []\nfor keyword in BANNED_KEYWORDS: # p ~ 5,000\n for doc in documents: # d ~ 10,000\n if keyword in doc.body: # O(L)\n flagged.append((doc, keyword))\n# 5,000 × 10,000 × avg_doc_length scans\n```\n\n**Correct (tokenize once when patterns are whole tokens — O(L + p)):**\n\n```python\nbanned = set(BANNED_KEYWORDS) # O(p)\nflagged = []\nfor doc in documents:\n tokens = set(doc.body.split()) # O(L) once per doc\n for hit in tokens & banned: # O(min(L, p))\n flagged.append((doc, hit))\n```\n\n**Alternative (Aho-Corasick for arbitrary substrings):**\n\n```python\nimport ahocorasick\nA = ahocorasick.Automaton()\nfor kw in BANNED_KEYWORDS:\n A.add_word(kw, kw)\nA.make_automaton()\n\nfor doc in documents:\n for end_idx, kw in A.iter(doc.body): # one scan finds all patterns\n flagged.append((doc, kw))\n```\n\n**When NOT to use this pattern:**\n- When p is small (≲ 10) and L is large — the per-pattern scan is already cheap and a tokenize-then-set conversion may not pay for itself.\n- When patterns include regex (anchors, alternation, lookaround) — switch to a single combined regex with alternation, or a regex-trie library.\n\nReference: [Aho–Corasick algorithm — NIST DADS](https://xlinux.nist.gov/dads/HTML/AhoCorasick.html)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2541,"content_sha256":"8b96c496d4af9d98e3a9161689a58fb8f5f1072dca0bbb910f626545cc259be0"},{"filename":"references/rec-iterative-for-deep-recursion.md","content":"---\ntitle: Use an Explicit Stack Instead of Deep Recursion\nimpact: HIGH\nimpactDescription: Prevents stack overflow on n > ~1,000; modest perf win from removing frames\ntags: rec, stack-overflow, iterative, explicit-stack, tail-call\n---\n\n## Use an Explicit Stack Instead of Deep Recursion\n\nRecursion is bounded by the language's call-stack depth — typically ~1,000 frames in CPython (default `sys.setrecursionlimit(1000)`), ~10,000 in V8. Algorithms with recursion depth proportional to input size (linked-list traversal, deeply nested JSON walking, naive tree walks on degenerate trees) crash at scale even when their Big-O is fine. Converting to an explicit stack/queue eliminates the depth limit and removes per-call frame overhead. Crucially, neither CPython nor mainstream JS engines perform tail-call optimization — writing tail-recursive code does **not** save the stack.\n\n**Incorrect (recursion depth = list length — crashes at ~1,000 nodes):**\n\n```python\ndef sum_list(node):\n if node is None:\n return 0\n return node.value + sum_list(node.next)\n# 5,000-node list → RecursionError: maximum recursion depth exceeded\n```\n\n**Correct (iterative with explicit loop — unlimited depth):**\n\n```python\ndef sum_list(node):\n total = 0\n while node is not None:\n total += node.value\n node = node.next\n return total\n```\n\n**Alternative (tree traversal with explicit stack):**\n\n```python\ndef walk(root):\n stack = [root]\n while stack:\n node = stack.pop()\n process(node)\n stack.extend(node.children) # pushes are O(1)\n# Depth is now limited by heap, not call stack\n```\n\n**When NOT to use this pattern:**\n- When recursion depth is provably O(log n) (balanced tree traversal) — stack depth is tiny and recursion is much clearer.\n- In Scheme, Scala, or other languages with guaranteed tail-call optimization — tail-recursive form is idiomatic and safe.\n\nReference: [CPython `sys.setrecursionlimit` — default 1000, not optimized for deep recursion](https://docs.python.org/3/library/sys.html#sys.setrecursionlimit)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2084,"content_sha256":"b5d4938261625a77a6b37be96d076d65f186aa6cc23d9ecfbc15378ed98e4329"},{"filename":"references/rec-memoize-overlapping-subproblems.md","content":"---\ntitle: Memoize Recursion With Overlapping Subproblems\nimpact: CRITICAL\nimpactDescription: O(2ⁿ) to O(n) — 1,000,000× faster at n=30\ntags: rec, memoization, dynamic-programming, exponential, lru-cache\n---\n\n## Memoize Recursion With Overlapping Subproblems\n\nA recursive function that calls itself with arguments it has already computed for is doing the same work many times — and the count of repeat computations grows exponentially with depth. Fibonacci is the canonical example: `fib(30)` makes over 2.6 million calls to compute 31 distinct values. The structural fix is memoization — cache the result keyed by the arguments, return it on the next call. The recursion shape doesn't change; the cache turns an exponential tree into a linear DAG.\n\nThe signal: a recursion whose subcalls overlap (same arguments reached via different paths) is always worth memoizing.\n\n**Incorrect (exponential — O(2ⁿ)):**\n\n```python\ndef fib(n):\n if n \u003c 2:\n return n\n return fib(n - 1) + fib(n - 2)\n# fib(30) → 2,692,537 function calls\n# fib(40) → 331,160,281 calls (~3 seconds in CPython)\n```\n\n**Correct (memoized — O(n)):**\n\n```python\nfrom functools import lru_cache\n\n@lru_cache(maxsize=None)\ndef fib(n):\n if n \u003c 2:\n return n\n return fib(n - 1) + fib(n - 2)\n# fib(30) → 31 calls, fib(40) → 41 calls (microseconds)\n```\n\n**Alternative (manual memo when key is non-hashable):**\n\n```python\ndef edit_distance(a, b, memo=None):\n memo = memo if memo is not None else {}\n if (len(a), len(b)) in memo:\n return memo[(len(a), len(b))]\n # ... compute ...\n memo[(len(a), len(b))] = result\n return result\n```\n\n**When NOT to use this pattern:**\n- When subproblems are unique (no overlap) — memoization adds bookkeeping for no benefit. Example: tree traversal where every subtree is visited exactly once.\n- When cache size would exceed memory — bound `maxsize` or switch to tabulation; see [`rec-tabulate-bottom-up`](rec-tabulate-bottom-up.md).\n\nReference: [Python `functools.lru_cache` — memoization decorator](https://docs.python.org/3/library/functools.html#functools.lru_cache)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2129,"content_sha256":"b4608c511dda7d0c0d9693ed7418a963c274f2a4acfca05abce6b2e9760b4329"},{"filename":"references/rec-prune-with-bounds.md","content":"---\ntitle: Prune Recursive Search With Bounds and Constraints\nimpact: HIGH\nimpactDescription: Worst-case exponential, practical 10-1000× speedup\ntags: rec, branch-and-bound, backtracking, pruning, search\n---\n\n## Prune Recursive Search With Bounds and Constraints\n\nCombinatorial search problems — subset sum, knapsack, traveling salesman, constraint solving, AI search — are exponential in worst case, but most real instances admit massive pruning. A best-so-far bound that compares against the current partial solution lets you abandon branches that cannot possibly improve it; constraint propagation eliminates entire subtrees before exploring them. The general pattern: track an upper/lower bound, cheaply estimate the best possible completion at each node, prune branches that can't beat the current best. The Big-O stays exponential but constant factors collapse — what was 2⁴⁰ becomes a few million nodes.\n\n**Incorrect (brute-force enumeration — O(2ⁿ) every time):**\n\n```python\ndef subset_sum(nums, target):\n \"\"\"Does any subset sum to target?\"\"\"\n def helper(i, current):\n if current == target:\n return True\n if i == len(nums):\n return False\n # Try both: include nums[i], or skip it\n return helper(i + 1, current + nums[i]) or helper(i + 1, current)\n\n return helper(0, 0)\n# n=30 → 2^30 ≈ 1 billion calls in worst case\n```\n\n**Correct (prune when partial sum overshoots or sort by largest first):**\n\n```python\ndef subset_sum(nums, target):\n nums = sorted(nums, reverse=True) # largest first → fast overflow\n # Precompute suffix sums once — sum(nums[i:]) is O(1) via lookup, not O(n)\n suffix = [0] * (len(nums) + 1)\n for i in range(len(nums) - 1, -1, -1):\n suffix[i] = suffix[i + 1] + nums[i]\n\n def helper(i, current):\n if current == target:\n return True\n if current > target: # PRUNE: overshot\n return False\n if i == len(nums):\n return False\n # Optimistic bound: even taking all remaining, can we reach target?\n if current + suffix[i] \u003c target: # PRUNE: undershoot impossible\n return False\n return helper(i + 1, current + nums[i]) or helper(i + 1, current)\n\n return helper(0, 0)\n# Same worst case but typically thousands of nodes, not billions —\n# and each node is O(1), not O(n) as a naive sum(nums[i:]) would make it\n```\n\n**Alternative (constraint propagation — Sudoku / SAT solvers):**\n\n```python\n# When picking a value forces or excludes values elsewhere, propagate immediately\n# instead of recursing into branches that constraint violation will reject\n```\n\n**When NOT to use this pattern:**\n- When the search space is small enough that brute force is faster than designing bounds — pruning has overhead.\n- When the problem has provable polynomial structure (it's not actually combinatorial) — use DP or a polynomial algorithm instead.\n\nReference: [Branch and bound (NIST DADS)](https://xlinux.nist.gov/dads/HTML/branchNbound.html)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":3068,"content_sha256":"5008741b0b73c9fb60cb5ebdd5f18a9910a343062a70cc4dac8b5f331f6039ec"},{"filename":"references/rec-share-memo-across-top-level-calls.md","content":"---\ntitle: Share Memoization Across Top-Level Calls\nimpact: HIGH\nimpactDescription: O(q*n) to O(q+n) for q queries — eliminates repeat exponential work\ntags: rec, memoization, shared-cache, batch-queries, instance-cache\n---\n\n## Share Memoization Across Top-Level Calls\n\nMemoization confined to a single call is wasted when the same function is invoked many times with overlapping inputs — each call starts with an empty cache, re-computing what an earlier call already solved. The fix is to lift the memo out of the call (instance attribute, module-level dict, `lru_cache` on the function itself) so subsequent invocations reuse prior results. This is especially important when serving batched requests: 1,000 queries that each compute `fib(40)` should share one memo, not allocate 1,000 of them.\n\n**Incorrect (cache reset on every call — repeats all work):**\n\n```python\ndef compute(n):\n memo = {} # fresh memo every invocation\n def helper(x):\n if x in memo:\n return memo[x]\n # ... recursive work ...\n memo[x] = result\n return result\n return helper(n)\n\n# Batch query\nfor n in queries: # 1,000 queries\n results.append(compute(n)) # each pays full O(n) recursion\n```\n\n**Correct (module-level `lru_cache` — shared across all callers):**\n\n```python\n@lru_cache(maxsize=10_000)\ndef compute(n):\n if n \u003c 2:\n return n\n return compute(n - 1) + compute(n - 2)\n\nfor n in queries:\n results.append(compute(n)) # second call onward: O(1) cache hits\n```\n\n**Alternative (instance-scoped cache for stateful classes):**\n\n```python\nclass Solver:\n def __init__(self):\n self._memo = {}\n\n def compute(self, n):\n if n in self._memo:\n return self._memo[n]\n result = ... # recursive work, using self.compute for subproblems\n self._memo[n] = result\n return result\n# One Solver instance, many queries → shared cache\n```\n\n**When NOT to use this pattern:**\n- When the function's result depends on hidden state (current time, RNG, mutable globals) — cached results become stale.\n- When the cache would grow unbounded over a long-running process — set `maxsize` on `lru_cache` or use a TTL cache.\n\nReference: [Python `functools.lru_cache` — function-level cache survives across all callers](https://docs.python.org/3/library/functools.html#functools.lru_cache)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2444,"content_sha256":"452531191b0711b9dc05488fe3d133353d7f158436ffc8236e819df4422cdd5f"},{"filename":"references/rec-tabulate-bottom-up.md","content":"---\ntitle: Tabulate Bottom-Up to Eliminate Recursion Overhead\nimpact: MEDIUM-HIGH\nimpactDescription: Same Big-O but 2-10× constant-factor speedup; eliminates stack-depth risk\ntags: rec, dynamic-programming, tabulation, iterative, space-optimization\n---\n\n## Tabulate Bottom-Up to Eliminate Recursion Overhead\n\nMemoized recursion (top-down DP) and tabulation (bottom-up DP) have the same Big-O, but tabulation is faster in practice on most runtimes (no function-call overhead, no hash lookups on the memo, better cache locality on a contiguous array) and trivially space-bounded. The conversion is mechanical: identify the dependency order of subproblems, allocate a table sized to the input, fill it in that order. Tabulation also makes the **rolling-array** space optimization obvious — if `f(n)` only depends on `f(n-1)` and `f(n-2)`, you only need two variables, not a length-n array.\n\n**Incorrect (top-down memoization — same Big-O, but pays call/cache overhead):**\n\n```python\n@lru_cache(None)\ndef fib(n):\n return n if n \u003c 2 else fib(n - 1) + fib(n - 2)\n# O(n) time, O(n) space — and pays Python's function-call overhead n times\n```\n\n**Correct (bottom-up tabulation — faster constants, O(1) space):**\n\n```python\ndef fib(n):\n if n \u003c 2:\n return n\n a, b = 0, 1\n for _ in range(n - 1):\n a, b = b, a + b\n return b\n# O(n) time, O(1) space — pure arithmetic in a tight loop\n```\n\n**Alternative (2-D problem with rolling rows — O(n) space instead of O(n²)):**\n\n```python\ndef edit_distance(a, b):\n prev = list(range(len(b) + 1))\n for i, x in enumerate(a, 1):\n curr = [i] + [0] * len(b)\n for j, y in enumerate(b, 1):\n curr[j] = prev[j - 1] if x == y else 1 + min(prev[j], curr[j - 1], prev[j - 1])\n prev = curr\n return prev[-1]\n# O(|a|*|b|) time but only O(|b|) space — useful when one string is large\n```\n\n**When NOT to use this pattern:**\n- When the subproblem space is sparse (most cells in the table never accessed) — top-down memoization only fills the cells it needs.\n- When the dependency order is hard to derive — start with top-down memoization, then convert once correctness is established.\n\nReference: [Sedgewick & Wayne, Algorithms 4e — Dynamic Programming](https://algs4.cs.princeton.edu/)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2287,"content_sha256":"24eba89404c2ce737240af908bc65e1e699d6f2143c4aca48a107bc9cebdbd10"},{"filename":"references/search-binary-search-on-sorted.md","content":"---\ntitle: Use Binary Search on Sorted Data\nimpact: MEDIUM-HIGH\nimpactDescription: O(n) per lookup to O(log n) — 1,000× speedup at n=1,000,000\ntags: search, binary-search, bisect, sorted, logarithmic\n---\n\n## Use Binary Search on Sorted Data\n\nIf the underlying data is already sorted (or you'll sort it once and query many times), linear scanning to find a value, a boundary, or a range is leaving log-factor speedup on the table. Binary search is O(log n): 1,000,000 elements → 20 comparisons versus 1,000,000. The standard library exposes it directly — `bisect_left`/`bisect_right` (Python), `Arrays.binarySearch` (Java), `std::lower_bound` (C++), `sort.Search` (Go). For JavaScript, write a 10-line bisect helper; the cost is trivial compared to the speedup.\n\n**Incorrect (linear scan against sorted data — O(n) per call):**\n\n```python\nsorted_timestamps = [...] # sorted, 1,000,000 entries\n\ndef first_after(t):\n for i, ts in enumerate(sorted_timestamps):\n if ts >= t:\n return i\n return None\n# 10,000 queries × 500k avg scan = 5,000,000,000 comparisons\n```\n\n**Correct (binary search — O(log n) per call):**\n\n```python\nimport bisect\ndef first_after(t):\n return bisect.bisect_left(sorted_timestamps, t)\n# 10,000 queries × ~20 comparisons = 200,000 comparisons total\n```\n\n**Alternative (range queries with both bounds):**\n\n```python\ndef items_in_range(lo, hi):\n left = bisect.bisect_left(sorted_timestamps, lo)\n right = bisect.bisect_right(sorted_timestamps, hi)\n return sorted_timestamps[left:right] # O(log n + k)\n```\n\n**When NOT to use this pattern:**\n- When data is not sorted and you can only insert (not rebuild) — binary search doesn't apply to unsorted data. Use a hash structure or a balanced tree.\n- When the array is tiny (\u003c 50 items) — the constant factor of bisect can match linear scan; favor readability.\n\nReference: [Python `bisect` — Array bisection algorithm](https://docs.python.org/3/library/bisect.html)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":1994,"content_sha256":"8acc93b861bf1378dd050ab670709c0db8f564ac07ae464eefcd086ed325aae2"},{"filename":"references/search-build-index-once-amortize.md","content":"---\ntitle: Build the Index Once When Queries Dominate\nimpact: MEDIUM-HIGH\nimpactDescription: O(q*n) to O(n + q) — break-even at q ≥ 1 for most index types\ntags: search, indexing, amortization, query-vs-insert, batch-lookup\n---\n\n## Build the Index Once When Queries Dominate\n\nA hash index, a sorted array, or a trie costs O(n) (or O(n log n)) to build but turns each subsequent lookup from O(n) to O(1) or O(log n). When the data is static during a batch of queries — common in batch jobs, request-scoped caches, and analytics pipelines — build the index once outside the query loop. The amortized cost over q queries is O(n + q) instead of O(q*n). Even a single extra lookup against the same data is often enough to justify the build.\n\nThe decision question: how many lookups will this index serve? If it's \"one,\" skip it. If it's \"two or more,\" build it.\n\n**Incorrect (linear scan per query, no shared work):**\n\n```python\ndef annotate(orders, users):\n enriched = []\n for o in orders: # q = len(orders)\n user = next((u for u in users if u.id == o.user_id), None)\n enriched.append((o, user))\n return enriched\n# 10,000 orders × 50,000 users = 500,000,000 comparisons\n```\n\n**Correct (build once, query many — O(n + q)):**\n\n```python\ndef annotate(orders, users):\n by_id = {u.id: u for u in users} # O(|users|) once\n return [(o, by_id.get(o.user_id)) for o in orders] # O(1) each\n# 50,000 + 10,000 = 60,000 ops\n```\n\n**Alternative (request-scoped cache — reuse index across requests):**\n\n```python\n# Build an index at startup, refresh on data change\nUSER_INDEX = {}\n\ndef reload_users():\n global USER_INDEX\n USER_INDEX = {u.id: u for u in fetch_all_users()}\n\ndef get_user(user_id):\n return USER_INDEX.get(user_id)\n# Cost of build is amortized over every request the index serves\n```\n\n**When NOT to use this pattern:**\n- When the index would consume more memory than the working set tolerates — sort-and-bisect uses no extra memory.\n- When data changes between every query — the index is stale before it's used. Use a database with maintained indexes instead.\n\nReference: [Use The Index, Luke — indexing for query speed](https://use-the-index-luke.com/)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2251,"content_sha256":"4f3297a5128693742052dac021ff75706cab108adc57d9cb7f9bd0e71ce9138e"},{"filename":"references/search-quickselect-not-full-sort.md","content":"---\ntitle: Use Quickselect for the K-th Element, Not Full Sort\nimpact: MEDIUM\nimpactDescription: O(n log n) to O(n) average — useful when k is fixed and small\ntags: search, quickselect, nth-element, selection, partial-sort\n---\n\n## Use Quickselect for the K-th Element, Not Full Sort\n\nFinding the median, the 90th percentile, or the k-th smallest doesn't require a full sort. Quickselect (a.k.a. `std::nth_element`) finds the k-th element in O(n) average time by partitioning around a pivot and recursing only into the half that contains the target. The full result list isn't materialized, but the element at position k is correct and everything to its left is ≤ everything to its right. This is the right tool for percentile calculations, \"median of medians\" queries, and \"find the closest k points\" subproblems.\n\n**Incorrect (full sort for one element — O(n log n)):**\n\n```python\ndef percentile(values, p):\n sorted_vals = sorted(values) # O(n log n)\n return sorted_vals[int(len(values) * p)]\n# 10,000,000 values for one p95 query: O(n log n) ≈ 230M ops\n```\n\n**Correct (quickselect — O(n) average):**\n\n```python\nimport heapq\n\ndef percentile(values, p):\n k = int(len(values) * p)\n return heapq.nsmallest(k + 1, values)[-1]\n# heapq.nsmallest uses partial sort: O(n log k) — when k is small, ~linear\n```\n\n**Alternative (C++ `std::nth_element` — true O(n) average):**\n\n```cpp\nstd::vector\u003cint> values = ...;\nauto kth = values.begin() + values.size() / 2;\nstd::nth_element(values.begin(), kth, values.end()); // O(n) avg\nint median = *kth;\n```\n\n**Alternative (Numpy `partition` — vectorized quickselect):**\n\n```python\nimport numpy as np\narr = np.asarray(values)\nk = int(len(arr) * 0.95)\nnp.partition(arr, k)[k] # O(n) average, vectorized\n```\n\n**When NOT to use this pattern:**\n- When you also need the elements *before* k in sorted order — quickselect doesn't sort them; if you need both, sort once.\n- When you need many percentiles at once (p50, p90, p99) on the same data — sort once and index O(1).\n\nReference: [Quickselect algorithm — Wikipedia](https://en.wikipedia.org/wiki/Quickselect)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2139,"content_sha256":"729f4d057d2518c0abc54c0a8bc3ede6bceca75126751a525d631cd75141cc06"},{"filename":"references/search-sort-once-outside-loop.md","content":"---\ntitle: Sort Once Outside the Loop, Not on Every Iteration\nimpact: HIGH\nimpactDescription: O(n²·log n) to O(n·log n + n) — orders of magnitude on hot paths\ntags: search, sort, hoisting, loop-invariant, cache\n---\n\n## Sort Once Outside the Loop, Not on Every Iteration\n\nSorting is O(n log n) per call — already not free. Re-running the same sort on the same array inside a loop multiplies that by the loop length: O(n² log n) total for n iterations against an n-element array. This pattern appears in \"find the median of this list\" or \"the k smallest\" called per request, where the underlying list rarely changes. Sort once at module load (or whenever the data is updated), cache the sorted view, query it as needed.\n\n**Incorrect (sort per iteration — O(n² log n)):**\n\n```python\nscores = [...] # 10,000 scores, mostly static\n\ndef report_top_5_for_request(request):\n sorted_scores = sorted(scores, reverse=True) # O(n log n) each request\n return sorted_scores[:5]\n# 100 requests/sec × 10,000 × log(10,000) ≈ 13M ops/sec just sorting\n```\n\n**Correct (sort once, maintain on update):**\n\n```python\nsorted_scores = sorted(scores, reverse=True) # once\n\ndef report_top_5_for_request(request):\n return sorted_scores[:5] # O(1)\n\ndef add_score(new_score):\n bisect.insort(sorted_scores, new_score) # O(log n) lookup + O(n) shift\n```\n\n**Alternative (when insertions dominate — heap):**\n\n```python\nimport heapq\n# For \"always read top-k, frequent inserts\" use a heap, not a sorted list\ntop_k = []\ndef add(score):\n if len(top_k) \u003c 5:\n heapq.heappush(top_k, score)\n else:\n heapq.heappushpop(top_k, score)\n```\n\n**When NOT to use this pattern:**\n- When the underlying list changes more often than it's queried — sorting on read is fine; lazy approaches are wasteful.\n- When the comparator depends on per-request state (sort by relevance to this user) — you can't precompute; consider partial sort or top-k heap instead.\n\nReference: [Python `sorted` is Timsort, O(n log n) worst case](https://docs.python.org/3/howto/sorting.html)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2127,"content_sha256":"d5f7546f37df604fe391cc49665714d2c47e374bf5cf4b685952fd3f0c5b89d9"},{"filename":"references/space-generators-over-intermediate-lists.md","content":"---\ntitle: Pipe Through Generators Instead of Materializing Intermediate Lists\nimpact: MEDIUM\nimpactDescription: O(n) intermediate storage to O(1) — also enables early exit\ntags: space, generator, lazy, pipeline, iterator\n---\n\n## Pipe Through Generators Instead of Materializing Intermediate Lists\n\nChaining `map(...)`, `filter(...)`, then `sum(...)` over a list with eager evaluation builds a new full list at each stage — three passes over n items, each allocating n elements. A generator pipeline (Python generator expressions, JS iterator helpers, Java `Stream`, Go channels) walks the data once, lazily, producing each result on demand. Memory drops from O(n) of intermediate allocations to O(1), and short-circuit consumers (`next`, `any`, `all`, `find`) can stop as soon as the answer is known.\n\n**Incorrect (materialized intermediates — O(n) extra memory per stage):**\n\n```python\nsquared = [x * x for x in numbers] # allocates list of size n\npositives = [x for x in squared if x > 0] # allocates again\ntotal = sum(positives) # walks again\n# 3 × n allocations + 3 passes\n```\n\n**Correct (generator pipeline — O(1) memory, one pass):**\n\n```python\ntotal = sum(x * x for x in numbers if x * x > 0)\n# Single fused pass, no intermediate list allocation\n```\n\n**Alternative (generator function with early termination):**\n\n```python\ndef positive_squares(nums):\n for x in nums:\n sq = x * x\n if sq > 0:\n yield sq\n\n# Caller can stop as soon as a condition is met\nfirst_big = next(sq for sq in positive_squares(numbers) if sq > 1_000_000)\n```\n\n**Alternative (JS — generator function):**\n\n```javascript\nfunction* positiveSquares(nums) {\n for (const x of nums) {\n const sq = x * x;\n if (sq > 0) yield sq;\n }\n}\n// Memory: O(1). And: stops early if consumer breaks\n```\n\n**When NOT to use this pattern:**\n- When you need to iterate the same data multiple times — generators are single-pass; materialize the result if you'll reuse it.\n- When you need indexed/random access — generators only support sequential iteration.\n\nReference: [PEP 289 — Generator Expressions](https://peps.python.org/pep-0289/)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2182,"content_sha256":"de702e2a976111220d8554679ddec7e4ce4ba012a28d886c9d4f9706350c3625"},{"filename":"references/space-release-retained-references.md","content":"---\ntitle: Release References That Prevent Garbage Collection\nimpact: LOW-MEDIUM\nimpactDescription: Prevents long-tail memory growth; GC pressure shows up as latency, not OOM\ntags: space, memory-leak, gc, closure, retention\n---\n\n## Release References That Prevent Garbage Collection\n\nA garbage collector reclaims only what's unreachable. Long-lived containers (module-level caches, event listeners, timers, closures captured by long-lived callbacks) keep transitively-reachable objects alive forever — what looks like a memory leak in a GC'd language is almost always an unintended retained reference. In long-running services, this manifests as a slow heap creep that eventually triggers GC pauses (latency spikes), then OOM hours or days later. The fixes are mechanical once you recognize the pattern: bounded caches, weak references for parent→child back-pointers, explicit unsubscription, and avoiding closing over heavy state in callbacks.\n\n**Incorrect (unbounded cache + closure over heavy state):**\n\n```javascript\nconst cache = new Map(); // module-level, never trimmed\n\nfunction handleRequest(req) {\n const heavyResponse = expensiveCompute(req);\n cache.set(req.id, () => heavyResponse); // closure pins `heavyResponse` forever\n // …\n}\n// Every request leaves a closure that retains the full response object\n```\n\n**Correct (bounded cache, no closure over heavy state):**\n\n```javascript\nimport LRU from 'lru-cache';\nconst cache = new LRU({ max: 1000 }); // bounded, evicts oldest\n\nfunction handleRequest(req) {\n const heavyResponse = expensiveCompute(req);\n cache.set(req.id, summarize(heavyResponse)); // store only what's needed\n}\n```\n\n**Alternative (weak references for parent→child pointers):**\n\n```javascript\n// Avoid: child pinning parent in memory because parent.children[] points to child\nclass Parent {\n constructor() { this.children = []; }\n}\nclass Child {\n constructor(parent) { this.parent = parent; } // back-pointer pins parent\n}\n\n// Better: WeakRef for the back-pointer\nclass Child {\n constructor(parent) { this.parentRef = new WeakRef(parent); }\n getParent() { return this.parentRef.deref(); }\n}\n```\n\n**Alternative (clean up event listeners and timers):**\n\n```javascript\n// Long-lived listener pins everything its closure references\nuseEffect(() => {\n const handler = e => doSomething(state);\n window.addEventListener('resize', handler);\n return () => window.removeEventListener('resize', handler); // critical\n}, [state]);\n```\n\n**When NOT to use this pattern:**\n- For short-lived processes (CLI scripts, request handlers) — retention doesn't matter; GC will reclaim everything when the process exits.\n\nReference: [V8 blog — understanding garbage collection and retention](https://v8.dev/blog/trash-talk)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2765,"content_sha256":"4564781ebce44fce705fb9f17284adb2fa70559b2a1c694f977c2f192cd36eab"},{"filename":"references/space-shallow-not-deep-copy.md","content":"---\ntitle: Use Shallow Copies (or No Copy) Instead of Deep Clones\nimpact: MEDIUM\nimpactDescription: O(size × depth) to O(1) or O(top-level) — 10-100× on nested structures\ntags: space, deep-copy, structured-clone, references, immutability\n---\n\n## Use Shallow Copies (or No Copy) Instead of Deep Clones\n\n`copy.deepcopy(x)`, `JSON.parse(JSON.stringify(x))`, and `structuredClone(x)` recursively walk the entire object graph allocating every node. That's necessary when you must isolate mutation; it's wasteful when the caller is read-only or only modifies the top level. Default to no copy at all (just pass the reference), shallow copy when you need to mutate the container (`{...obj}`, `[...arr]`, `dict(d)`), and reach for deep copy only when you've identified a specific aliasing bug that needs it. Deep cloning a large nested object on a hot path is a common source of mysterious latency.\n\n**Incorrect (deep clone the world — O(total nodes)):**\n\n```javascript\nfunction recordSnapshot(state) {\n history.push(structuredClone(state)); // deep walks every nested object\n}\n// state with 10,000 nodes × 100 snapshots = 1,000,000 allocations\n```\n\n**Correct (shallow copy at the level you'll mutate):**\n\n```javascript\nfunction updateField(state, key, value) {\n return { ...state, [key]: value }; // copies top-level keys only\n}\n// state with 10,000 nested nodes → ~50 top-level pointer copies\n```\n\n**Alternative (Python — be explicit about copy depth):**\n\n```python\nimport copy\n\n# Wrong default: deepcopy everywhere \"just in case\"\nfresh = copy.deepcopy(original) # walks the whole tree\n\n# Right: only what's needed\nfresh = original.copy() # dict/list shallow copy — O(top-level)\nfresh = {**original, 'k': new_value} # update one key, share the rest\n```\n\n**When NOT to use this pattern:**\n- When you genuinely need an isolated copy you'll mutate deeply — e.g., test fixtures, undo/redo with full divergence. Deep copy is correct.\n- When the structure has cycles — `structuredClone` and `copy.deepcopy` handle them; manual shallow copy doesn't.\n\nReference: [MDN — `structuredClone` is a deep clone (use sparingly)](https://developer.mozilla.org/en-US/docs/Web/API/structuredClone)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2225,"content_sha256":"93cdc915f1701b53ab08e24abb00d1a6bfbb3c3120b216a18a7a952637aa81bc"},{"filename":"references/space-stream-dont-load.md","content":"---\ntitle: Stream Large Inputs Instead of Loading Them Whole\nimpact: HIGH\nimpactDescription: O(n) memory to O(1) — enables processing files larger than RAM\ntags: space, streaming, generator, file-io, memory\n---\n\n## Stream Large Inputs Instead of Loading Them Whole\n\nReading a 5GB file with `open(path).read()` allocates 5GB in memory before you can process the first byte. Most line-oriented or chunk-oriented processing doesn't need the whole file resident — the natural shape is \"for each line, do X.\" Iterating over the file handle yields one line at a time, with O(1) memory regardless of file size. The same applies to network streams (use `iter_content`/`iter_lines`), database cursors (`.fetchmany` / server-side cursors), and large API paginated responses. Beyond memory, streaming gives you \"first byte\" latency — the consumer can start producing output before the whole input is read.\n\n**Incorrect (load entire file — O(file size) memory):**\n\n```python\nwith open('access.log') as f:\n lines = f.readlines() # allocates the whole file\nfor line in lines:\n process(line)\n# 5GB file → 5GB RAM, OOM on small instances\n```\n\n**Correct (stream — O(1) memory):**\n\n```python\nwith open('access.log') as f:\n for line in f: # yields one line at a time\n process(line)\n# Constant memory regardless of file size\n```\n\n**Alternative (Node.js streams for HTTP body / file):**\n\n```javascript\nimport { createReadStream } from 'node:fs';\nimport readline from 'node:readline';\n\nconst rl = readline.createInterface({ input: createReadStream(path) });\nfor await (const line of rl) {\n process(line);\n}\n```\n\n**Alternative (database — server-side cursor):**\n\n```python\n# psycopg2: named cursor enables server-side iteration without loading all rows\nwith conn.cursor(name='stream_rows') as cur:\n cur.itersize = 1000\n cur.execute(\"SELECT * FROM events\")\n for row in cur: # batches of 1000, not all at once\n process(row)\n```\n\n**When NOT to use this pattern:**\n- When the algorithm requires random access across the file (e.g., reverse iteration, sort) — you must materialize, but consider `mmap` for OS-managed paging.\n- When the file is small (\u003c 100MB on a modern machine) — load and process is simpler and the memory cost is negligible.\n\nReference: [Python file objects support iteration line-by-line](https://docs.python.org/3/tutorial/inputoutput.html#methods-of-file-objects)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2474,"content_sha256":"f7934bfe90ea98f4ad6f90d775199c85d87d4483789df73d0480ddce553090f1"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"dot-skills Algorithmic Complexity (Big-O) Best Practices","type":"text"}]},{"type":"paragraph","content":[{"text":"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.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"When to Apply","type":"text"}]},{"type":"paragraph","content":[{"text":"Use this skill when:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Reviewing a pull request or function for performance regressions","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Asked \"why is this slow?\" or \"can we make this faster?\"","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Refactoring a hot path or a function that handles user-scaled input","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Reading code that contains: nested loops, ","type":"text"},{"text":".includes","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":".find","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"x in list","type":"text","marks":[{"type":"code_inline"}]},{"text":" inside iteration, ORM access in a loop, recursion without memoization, string/array building via ","type":"text"},{"text":"+=","type":"text","marks":[{"type":"code_inline"}]},{"text":" or spread, file/database I/O inside iteration","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Reviewing code that processes lists, trees, or streams whose size will grow","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Workflow: Find, Classify, Fix","type":"text"}]},{"type":"paragraph","content":[{"text":"The skill is structured for a three-step workflow on any code under review:","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"1. Find — Scan for the Suspicion Patterns","type":"text"}]},{"type":"paragraph","content":[{"text":"Look for these structural signals first (highest hit rate):","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Signal","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Likely Category","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"First Rule to Check","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Two nested ","type":"text"},{"text":"for","type":"text","marks":[{"type":"code_inline"}]},{"text":" loops","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"nested-","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"nested-explicit-quadratic-loops","type":"text","marks":[{"type":"link","attrs":{"href":"references/nested-explicit-quadratic-loops.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":".includes","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":".find","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"x in list","type":"text","marks":[{"type":"code_inline"}]},{"text":" inside a loop","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"nested-","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"nested-includes-in-loop","type":"text","marks":[{"type":"link","attrs":{"href":"references/nested-includes-in-loop.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ORM access inside a loop (","type":"text"},{"text":"for o in orders: o.customer.x","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"io-","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"io-n-plus-one-query","type":"text","marks":[{"type":"link","attrs":{"href":"references/io-n-plus-one-query.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"await fetch","type":"text","marks":[{"type":"code_inline"}]},{"text":" in ","type":"text"},{"text":"for-of","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"io-","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"io-sequential-await-in-loop","type":"text","marks":[{"type":"link","attrs":{"href":"references/io-sequential-await-in-loop.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"array.find","type":"text","marks":[{"type":"code_inline"}]},{"text":" to \"join\" two arrays","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ds-","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ds-hashmap-for-keyed-access","type":"text","marks":[{"type":"link","attrs":{"href":"references/ds-hashmap-for-keyed-access.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Recursive function with overlapping arguments","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"rec-","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"rec-memoize-overlapping-subproblems","type":"text","marks":[{"type":"link","attrs":{"href":"references/rec-memoize-overlapping-subproblems.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"s = s + part","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"[...acc, x]","type":"text","marks":[{"type":"code_inline"}]},{"text":" in a loop","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"build-","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"build-avoid-quadratic-string-concat","type":"text","marks":[{"type":"link","attrs":{"href":"references/build-avoid-quadratic-string-concat.md","title":null}}]},{"text":", ","type":"text"},{"text":"build-avoid-spread-in-reducer","type":"text","marks":[{"type":"link","attrs":{"href":"references/build-avoid-spread-in-reducer.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"sorted(...)","type":"text","marks":[{"type":"code_inline"}]},{"text":" called inside a loop","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"search-","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"search-sort-once-outside-loop","type":"text","marks":[{"type":"link","attrs":{"href":"references/search-sort-once-outside-loop.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"readlines()","type":"text","marks":[{"type":"code_inline"}]},{"text":" / loading whole files","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"space-","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"space-stream-dont-load","type":"text","marks":[{"type":"link","attrs":{"href":"references/space-stream-dont-load.md","title":null}}]}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"2. Classify — Derive the Big-O","type":"text"}]},{"type":"paragraph","content":[{"text":"Compute complexity from the code structure:","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Structure","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Complexity","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Single loop over n items, O(1) body","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"O(n)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Two nested loops over n / m items","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"O(n*m)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Loop calling an O(n) operation (","type":"text"},{"text":".includes","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":".find","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"x in list","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"O(n*m), often misread as O(n)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Recursive ","type":"text"},{"text":"f(n) = f(n-1) + f(n-2)","type":"text","marks":[{"type":"code_inline"}]},{"text":" without memoization","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"O(2ⁿ)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Recursive ","type":"text"},{"text":"f(n) = 2*f(n/2) + O(n)","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"O(n log n)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Recursive ","type":"text"},{"text":"f(n) = 2*f(n/2) + O(1)","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"O(n) (full tree traversal)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Recursive ","type":"text"},{"text":"f(n) = f(n/2) + O(1)","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"O(log n)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"s = s + part","type":"text","marks":[{"type":"code_inline"}]},{"text":" in a loop","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"O(n²) (string immutability)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"[...acc, x]","type":"text","marks":[{"type":"code_inline"}]},{"text":" in a reduce","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"O(n²) (copy-on-spread)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Query/RPC inside loop over n items","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"O(n) round trips","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"When in doubt, ask: ","type":"text"},{"text":"\"As input doubles, does runtime roughly double (linear), quadruple (quadratic), or do something worse (exponential)?\"","type":"text","marks":[{"type":"strong"}]},{"text":" That's the practical complexity class.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"3. Fix — Apply the Pattern From the Matching Rule","type":"text"}]},{"type":"paragraph","content":[{"text":"Each reference file in ","type":"text"},{"text":"references/","type":"text","marks":[{"type":"code_inline"}]},{"text":" is a ","type":"text"},{"text":"{category}-{slug}.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" containing:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"WHY the pattern matters (the cascade effect)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"An ","type":"text"},{"text":"Incorrect","type":"text","marks":[{"type":"strong"}]},{"text":" code example with the cost annotated","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"A ","type":"text"},{"text":"Correct","type":"text","marks":[{"type":"strong"}]},{"text":" example with the minimal diff","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"When NOT to apply the fix (the rule has exceptions)","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"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.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Rule Categories by Priority","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"#","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Category","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Prefix","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Impact","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Rules","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"1","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Nested Iteration Patterns","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"nested-","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"CRITICAL","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"6","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"2","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Loop-Invariant I/O and N+1","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"io-","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"CRITICAL","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"5","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"3","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Data Structure Mismatch","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ds-","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"HIGH","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"6","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"4","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Recursion Complexity","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"rec-","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"HIGH","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"5","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"5","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Redundant Computation","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"compute-","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"MEDIUM-HIGH","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"5","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"6","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Collection Building","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"build-","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"MEDIUM","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"4","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"7","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Search & Sort Selection","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"search-","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"MEDIUM","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"4","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"8","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Space Complexity Traps","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"space-","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"LOW-MEDIUM","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"4","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"See ","type":"text"},{"text":"references/_sections.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/_sections.md","title":null}},{"type":"code_inline"}]},{"text":" for the full ordering rationale.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Quick Reference","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"1. Nested Iteration Patterns (CRITICAL)","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"nested-explicit-quadratic-loops","type":"text","marks":[{"type":"link","attrs":{"href":"references/nested-explicit-quadratic-loops.md","title":null}},{"type":"code_inline"}]},{"text":" — Replace pairwise loops with hash-based single passes","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"nested-includes-in-loop","type":"text","marks":[{"type":"link","attrs":{"href":"references/nested-includes-in-loop.md","title":null}},{"type":"code_inline"}]},{"text":" — Avoid ","type":"text"},{"text":".includes()","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":".indexOf()","type":"text","marks":[{"type":"code_inline"}]},{"text":" inside a loop","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"nested-find-in-loop","type":"text","marks":[{"type":"link","attrs":{"href":"references/nested-find-in-loop.md","title":null}},{"type":"code_inline"}]},{"text":" — Pre-index lookups instead of ","type":"text"},{"text":".find()","type":"text","marks":[{"type":"code_inline"}]},{"text":" per iteration","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"nested-cartesian-comparison","type":"text","marks":[{"type":"link","attrs":{"href":"references/nested-cartesian-comparison.md","title":null}},{"type":"code_inline"}]},{"text":" — Group by key instead of cartesian comparison","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"nested-set-operations-on-arrays","type":"text","marks":[{"type":"link","attrs":{"href":"references/nested-set-operations-on-arrays.md","title":null}},{"type":"code_inline"}]},{"text":" — Use sets for intersection, union, difference","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"nested-substring-search-in-loop","type":"text","marks":[{"type":"link","attrs":{"href":"references/nested-substring-search-in-loop.md","title":null}},{"type":"code_inline"}]},{"text":" — Tokenize once instead of re-scanning per pattern","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"2. Loop-Invariant I/O and N+1 Queries (CRITICAL)","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"io-n-plus-one-query","type":"text","marks":[{"type":"link","attrs":{"href":"references/io-n-plus-one-query.md","title":null}},{"type":"code_inline"}]},{"text":" — Eliminate N+1 queries by fetching related data in one round trip","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"io-sequential-await-in-loop","type":"text","marks":[{"type":"link","attrs":{"href":"references/io-sequential-await-in-loop.md","title":null}},{"type":"code_inline"}]},{"text":" — Run independent async operations in parallel","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"io-batch-instead-of-per-item","type":"text","marks":[{"type":"link","attrs":{"href":"references/io-batch-instead-of-per-item.md","title":null}},{"type":"code_inline"}]},{"text":" — Use batch endpoints instead of per-item calls","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"io-file-read-in-loop","type":"text","marks":[{"type":"link","attrs":{"href":"references/io-file-read-in-loop.md","title":null}},{"type":"code_inline"}]},{"text":" — Read or stat files outside tight loops","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"io-missing-eager-load","type":"text","marks":[{"type":"link","attrs":{"href":"references/io-missing-eager-load.md","title":null}},{"type":"code_inline"}]},{"text":" — Eager-load ORM relations you will access","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"3. Data Structure Mismatch (HIGH)","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"ds-hashmap-for-keyed-access","type":"text","marks":[{"type":"link","attrs":{"href":"references/ds-hashmap-for-keyed-access.md","title":null}},{"type":"code_inline"}]},{"text":" — Store records keyed in a hashmap, not as parallel arrays","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"ds-heap-for-top-k","type":"text","marks":[{"type":"link","attrs":{"href":"references/ds-heap-for-top-k.md","title":null}},{"type":"code_inline"}]},{"text":" — Use a heap for top-k, not full sort + slice","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"ds-deque-for-front-operations","type":"text","marks":[{"type":"link","attrs":{"href":"references/ds-deque-for-front-operations.md","title":null}},{"type":"code_inline"}]},{"text":" — Use a deque for front insertions and removals","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"ds-counter-for-histograms","type":"text","marks":[{"type":"link","attrs":{"href":"references/ds-counter-for-histograms.md","title":null}},{"type":"code_inline"}]},{"text":" — Use Counter / multiset for frequency counting","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"ds-sorted-structure-for-range-queries","type":"text","marks":[{"type":"link","attrs":{"href":"references/ds-sorted-structure-for-range-queries.md","title":null}},{"type":"code_inline"}]},{"text":" — Use a sorted structure for range queries","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"ds-trie-for-prefix-search","type":"text","marks":[{"type":"link","attrs":{"href":"references/ds-trie-for-prefix-search.md","title":null}},{"type":"code_inline"}]},{"text":" — Use a trie for prefix search","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"4. Recursion Complexity (HIGH)","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"rec-memoize-overlapping-subproblems","type":"text","marks":[{"type":"link","attrs":{"href":"references/rec-memoize-overlapping-subproblems.md","title":null}},{"type":"code_inline"}]},{"text":" — Memoize recursion with overlapping subproblems","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"rec-tabulate-bottom-up","type":"text","marks":[{"type":"link","attrs":{"href":"references/rec-tabulate-bottom-up.md","title":null}},{"type":"code_inline"}]},{"text":" — Tabulate bottom-up to eliminate recursion overhead","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"rec-iterative-for-deep-recursion","type":"text","marks":[{"type":"link","attrs":{"href":"references/rec-iterative-for-deep-recursion.md","title":null}},{"type":"code_inline"}]},{"text":" — Use an explicit stack instead of deep recursion","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"rec-prune-with-bounds","type":"text","marks":[{"type":"link","attrs":{"href":"references/rec-prune-with-bounds.md","title":null}},{"type":"code_inline"}]},{"text":" — Prune recursive search with bounds and constraints","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"rec-share-memo-across-top-level-calls","type":"text","marks":[{"type":"link","attrs":{"href":"references/rec-share-memo-across-top-level-calls.md","title":null}},{"type":"code_inline"}]},{"text":" — Share memoization across top-level calls","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"5. Redundant Computation (MEDIUM-HIGH)","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"compute-hoist-loop-invariants","type":"text","marks":[{"type":"link","attrs":{"href":"references/compute-hoist-loop-invariants.md","title":null}},{"type":"code_inline"}]},{"text":" — Hoist loop-invariant computation outside the loop","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"compute-precompile-regex","type":"text","marks":[{"type":"link","attrs":{"href":"references/compute-precompile-regex.md","title":null}},{"type":"code_inline"}]},{"text":" — Pre-compile regex patterns","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"compute-cache-expensive-pure-results","type":"text","marks":[{"type":"link","attrs":{"href":"references/compute-cache-expensive-pure-results.md","title":null}},{"type":"code_inline"}]},{"text":" — Cache expensive pure-function results","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"compute-cache-property-lookup","type":"text","marks":[{"type":"link","attrs":{"href":"references/compute-cache-property-lookup.md","title":null}},{"type":"code_inline"}]},{"text":" — Cache repeated property lookups in hot loops","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"compute-defer-or-short-circuit","type":"text","marks":[{"type":"link","attrs":{"href":"references/compute-defer-or-short-circuit.md","title":null}},{"type":"code_inline"}]},{"text":" — Defer or short-circuit work you might not need","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"6. Collection Building (MEDIUM)","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"build-avoid-quadratic-string-concat","type":"text","marks":[{"type":"link","attrs":{"href":"references/build-avoid-quadratic-string-concat.md","title":null}},{"type":"code_inline"}]},{"text":" — Build strings with joins or builders, not repeated concatenation","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"build-avoid-spread-in-reducer","type":"text","marks":[{"type":"link","attrs":{"href":"references/build-avoid-spread-in-reducer.md","title":null}},{"type":"code_inline"}]},{"text":" — Push to a mutable accumulator instead of spreading","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"build-avoid-immutable-object-spread","type":"text","marks":[{"type":"link","attrs":{"href":"references/build-avoid-immutable-object-spread.md","title":null}},{"type":"code_inline"}]},{"text":" — Use a plain object build phase, then freeze","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"build-presize-when-length-known","type":"text","marks":[{"type":"link","attrs":{"href":"references/build-presize-when-length-known.md","title":null}},{"type":"code_inline"}]},{"text":" — Pre-size collections when the length is known","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"7. Search & Sort Selection (MEDIUM)","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"search-binary-search-on-sorted","type":"text","marks":[{"type":"link","attrs":{"href":"references/search-binary-search-on-sorted.md","title":null}},{"type":"code_inline"}]},{"text":" — Use binary search on sorted data","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"search-sort-once-outside-loop","type":"text","marks":[{"type":"link","attrs":{"href":"references/search-sort-once-outside-loop.md","title":null}},{"type":"code_inline"}]},{"text":" — Sort once outside the loop, not on every iteration","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"search-quickselect-not-full-sort","type":"text","marks":[{"type":"link","attrs":{"href":"references/search-quickselect-not-full-sort.md","title":null}},{"type":"code_inline"}]},{"text":" — Use quickselect for the k-th element, not full sort","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"search-build-index-once-amortize","type":"text","marks":[{"type":"link","attrs":{"href":"references/search-build-index-once-amortize.md","title":null}},{"type":"code_inline"}]},{"text":" — Build the index once when queries dominate","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"8. Space Complexity Traps (LOW-MEDIUM)","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"space-stream-dont-load","type":"text","marks":[{"type":"link","attrs":{"href":"references/space-stream-dont-load.md","title":null}},{"type":"code_inline"}]},{"text":" — Stream large inputs instead of loading them whole","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"space-generators-over-intermediate-lists","type":"text","marks":[{"type":"link","attrs":{"href":"references/space-generators-over-intermediate-lists.md","title":null}},{"type":"code_inline"}]},{"text":" — Pipe through generators instead of materializing intermediate lists","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"space-shallow-not-deep-copy","type":"text","marks":[{"type":"link","attrs":{"href":"references/space-shallow-not-deep-copy.md","title":null}},{"type":"code_inline"}]},{"text":" — Use shallow copies (or no copy) instead of deep clones","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"space-release-retained-references","type":"text","marks":[{"type":"link","attrs":{"href":"references/space-release-retained-references.md","title":null}},{"type":"code_inline"}]},{"text":" — Release references that prevent garbage collection","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"How to Use","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Start with the ","type":"text"},{"text":"Find","type":"text","marks":[{"type":"strong"}]},{"text":" signal table above to locate the most likely pattern.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Open the matching reference file for the WHY and the minimal-diff fix.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"If you're classifying complexity from scratch, use the ","type":"text"},{"text":"Classify","type":"text","marks":[{"type":"strong"}]},{"text":" table to derive Big-O from code structure.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"When proposing a fix, quote the rule by file path so reviewers can verify the reasoning.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"See ","type":"text"},{"text":"references/_sections.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/_sections.md","title":null}},{"type":"code_inline"}]},{"text":" for category ordering rationale, and ","type":"text"},{"text":"assets/templates/_template.md","type":"text","marks":[{"type":"link","attrs":{"href":"assets/templates/_template.md","title":null}},{"type":"code_inline"}]},{"text":" when adding new rules.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Reference Files","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"File","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Description","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"references/_sections.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/_sections.md","title":null}}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Category definitions, impact levels, and ordering rationale","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"assets/templates/_template.md","type":"text","marks":[{"type":"link","attrs":{"href":"assets/templates/_template.md","title":null}}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Template for adding new rules","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"metadata.json","type":"text","marks":[{"type":"link","attrs":{"href":"metadata.json","title":null}}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Discipline, type, and source references","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Related Skills","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"bug-review","type":"text","marks":[{"type":"code_inline"}]},{"text":" — Multi-pass PR bug review (this skill is a focused complement for performance issues specifically)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"A language-specific best-practices skill (React, Python, Go) — covers idioms beyond Big-O; pair with this skill for performance-critical reviews","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}}]},"metadata":{"date":"2026-06-05","name":"algorithmic-complexity-review","author":"@skillopedia","source":{"stars":153,"repo_name":"dot-skills","origin_url":"https://github.com/pproenca/dot-skills/blob/HEAD/skills/.experimental/algorithmic-complexity-review/SKILL.md","repo_owner":"pproenca","body_sha256":"aca12878ba8b29e61ae0f5716ddfce705655276aed1eb663606d1947ffe29d0c","cluster_key":"6f827b8f0d0afd826669d285906b8d6ac0b5af87ec5dbeaa02876773b65cecd7","clean_bundle":{"format":"clean-skill-bundle-v1","source":"pproenca/dot-skills/skills/.experimental/algorithmic-complexity-review/SKILL.md","attachments":[{"id":"9c592652-c9b1-58df-bb5b-51a54e9cf18e","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/9c592652-c9b1-58df-bb5b-51a54e9cf18e/attachment.md","path":"AGENTS.md","size":10627,"sha256":"332b9fac38684864cf3d78635ae9df86c879bda4257f855c8f244842050bce15","contentType":"text/markdown; charset=utf-8"},{"id":"c7dfa96e-ba1c-5ff1-8c90-fe354558ed8d","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/c7dfa96e-ba1c-5ff1-8c90-fe354558ed8d/attachment.md","path":"README.md","size":7684,"sha256":"e7868462508ef3c4529572b2050b6e8cf08b712e33f9d0b9631f2735294ac442","contentType":"text/markdown; charset=utf-8"},{"id":"501a50e0-47b4-5041-9adb-ecc291c1e54e","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/501a50e0-47b4-5041-9adb-ecc291c1e54e/attachment.md","path":"assets/templates/_template.md","size":2694,"sha256":"a3d299f1d8039f7cce25cea6d7fa79cb93017be7bdf4293c6ddabde28d1c7639","contentType":"text/markdown; charset=utf-8"},{"id":"38a3352f-32d5-5eed-8d93-81561bcdcbe7","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/38a3352f-32d5-5eed-8d93-81561bcdcbe7/attachment.json","path":"metadata.json","size":1447,"sha256":"26f1a9360d5391af377df6ea90d347fa3944c5d81e4484fcef3948a115657e23","contentType":"application/json; charset=utf-8"},{"id":"19c980bb-4e33-5cd3-8ba7-494ad6cd3056","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/19c980bb-4e33-5cd3-8ba7-494ad6cd3056/attachment.md","path":"references/_sections.md","size":3831,"sha256":"85939aa1b1f4326163e5e972655ceef9d3600d49f85407b95b320b6103e4bba3","contentType":"text/markdown; charset=utf-8"},{"id":"0ea30124-cd8c-505d-a05b-36d2a7b603bd","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/0ea30124-cd8c-505d-a05b-36d2a7b603bd/attachment.md","path":"references/build-avoid-immutable-object-spread.md","size":1972,"sha256":"8f0e362ee36ff5c2dacafd6dc4d1799c68b474b3ae9d98d06ab798f9c49b6993","contentType":"text/markdown; charset=utf-8"},{"id":"8719591e-188f-5351-8829-1acd8169867d","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/8719591e-188f-5351-8829-1acd8169867d/attachment.md","path":"references/build-avoid-quadratic-string-concat.md","size":2170,"sha256":"4c7fc57b83ae219d394a56a7ca5b4f0977e826b823e18498a1c2b91189378b1b","contentType":"text/markdown; charset=utf-8"},{"id":"3ab564ba-ce24-586d-aba5-762c55720a48","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/3ab564ba-ce24-586d-aba5-762c55720a48/attachment.md","path":"references/build-avoid-spread-in-reducer.md","size":1966,"sha256":"ac061002a4f3241ca81fa2f03900be885eeb73644cbba2256b56a7acb9c5651c","contentType":"text/markdown; charset=utf-8"},{"id":"ec8ecdd2-e572-5205-9aba-3abcada9f5b7","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/ec8ecdd2-e572-5205-9aba-3abcada9f5b7/attachment.md","path":"references/build-presize-when-length-known.md","size":2549,"sha256":"e3e0bd7539a4f12d6b4522aebe1a112794a86bea72ba2322620411a30c41f95b","contentType":"text/markdown; charset=utf-8"},{"id":"3aae8cb5-0ad5-554e-a34c-00035de8b62f","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/3aae8cb5-0ad5-554e-a34c-00035de8b62f/attachment.md","path":"references/compute-cache-expensive-pure-results.md","size":2606,"sha256":"27757c9610b50b7f49b1a5e605e4434c69de9748a30cd3a3b981915d3ae52ab5","contentType":"text/markdown; charset=utf-8"},{"id":"1a0314ed-afce-554c-9041-b8512a72fc5a","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/1a0314ed-afce-554c-9041-b8512a72fc5a/attachment.md","path":"references/compute-cache-property-lookup.md","size":2271,"sha256":"6220d305c79adb70bdce0bcf4953ee5d9552e7680aca8315d775e349336ed73a","contentType":"text/markdown; charset=utf-8"},{"id":"bd3b354d-e1cb-562b-8059-53798479a887","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/bd3b354d-e1cb-562b-8059-53798479a887/attachment.md","path":"references/compute-defer-or-short-circuit.md","size":2258,"sha256":"36e20de28ac5d84166124314f43a54ef0006f0132e7a3cc1d9e9e91f8e4c4029","contentType":"text/markdown; charset=utf-8"},{"id":"834a2519-dcd0-52d3-985d-c1dca39b1216","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/834a2519-dcd0-52d3-985d-c1dca39b1216/attachment.md","path":"references/compute-hoist-loop-invariants.md","size":2469,"sha256":"169928683e95ebf82953e62f4ad48f28aab90010203dffb792be500f4def06dc","contentType":"text/markdown; charset=utf-8"},{"id":"2db57fd7-97e6-5ae8-b2dd-79ee24748bec","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/2db57fd7-97e6-5ae8-b2dd-79ee24748bec/attachment.md","path":"references/compute-precompile-regex.md","size":2232,"sha256":"2c0af5887f07a5ffb989c2dcf780742a11f4034059cef9b5b03c1765252c4ca2","contentType":"text/markdown; charset=utf-8"},{"id":"af379279-9265-55f5-9697-22c739dcc8f0","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/af379279-9265-55f5-9697-22c739dcc8f0/attachment.md","path":"references/ds-counter-for-histograms.md","size":1935,"sha256":"4275ac73b98ef2017e12e7da61ab7aaeb9c2372477c3b0435a918c00879b9793","contentType":"text/markdown; charset=utf-8"},{"id":"9df95b2a-c07a-558e-9579-fafc594f7fde","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/9df95b2a-c07a-558e-9579-fafc594f7fde/attachment.md","path":"references/ds-deque-for-front-operations.md","size":2029,"sha256":"0da8ae77eae08ddee4e8fb080a797faedce58ac821d3b1763452f06a71844449","contentType":"text/markdown; charset=utf-8"},{"id":"35ed6a3c-9305-5036-97a3-39988f30417c","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/35ed6a3c-9305-5036-97a3-39988f30417c/attachment.md","path":"references/ds-hashmap-for-keyed-access.md","size":2197,"sha256":"624f9a88454a8c6af2c43cf327e5b25394e34948d697de059e9565697a2fa33a","contentType":"text/markdown; charset=utf-8"},{"id":"362724d4-c29e-51f1-83b9-ae4cf7f01dc9","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/362724d4-c29e-51f1-83b9-ae4cf7f01dc9/attachment.md","path":"references/ds-heap-for-top-k.md","size":1593,"sha256":"0c0a7a2c8d395665f96a5172430471a08731e8dfcd50ef548f72302afe8cca88","contentType":"text/markdown; charset=utf-8"},{"id":"f2961098-cd9d-530f-9cc8-b5ec22b3f6d0","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/f2961098-cd9d-530f-9cc8-b5ec22b3f6d0/attachment.md","path":"references/ds-sorted-structure-for-range-queries.md","size":2245,"sha256":"64a1d33360b85b6c6b9309fa729d9f99834bb087cabf06c6d693675dab975b99","contentType":"text/markdown; charset=utf-8"},{"id":"36424326-a494-5f30-bb62-da39fca338b7","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/36424326-a494-5f30-bb62-da39fca338b7/attachment.md","path":"references/ds-trie-for-prefix-search.md","size":2482,"sha256":"2cc18015788a95d1a0af316147acead7fce3e8d9ed864f4690d491a40ce86bab","contentType":"text/markdown; charset=utf-8"},{"id":"cf55f906-6564-5315-926e-d1d7b213b711","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/cf55f906-6564-5315-926e-d1d7b213b711/attachment.md","path":"references/io-batch-instead-of-per-item.md","size":2182,"sha256":"d32c44390d690c61d6b05c4a3ea284bb3c6ef7c1d3157b8859a547b0732d37eb","contentType":"text/markdown; charset=utf-8"},{"id":"f724f90b-1bb6-5a84-a535-a66d7ff428ec","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/f724f90b-1bb6-5a84-a535-a66d7ff428ec/attachment.md","path":"references/io-file-read-in-loop.md","size":2072,"sha256":"74e107a708671ea09269e9fa2e077c91729059c081980219cea39b5572f8254d","contentType":"text/markdown; charset=utf-8"},{"id":"0f48e83a-5cdc-5df3-a540-7c13c8ee1f30","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/0f48e83a-5cdc-5df3-a540-7c13c8ee1f30/attachment.md","path":"references/io-missing-eager-load.md","size":2207,"sha256":"d89968adea6eb3b9f5c26a049aa0363ace015906498d5f3a3ccd9da2378434a4","contentType":"text/markdown; charset=utf-8"},{"id":"e1654b4f-3dcd-58f9-bf5b-2c6fba9ce8ca","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/e1654b4f-3dcd-58f9-bf5b-2c6fba9ce8ca/attachment.md","path":"references/io-n-plus-one-query.md","size":2012,"sha256":"48b02e8cc277f92e2cdce4f3646a000f99335fc4fd2aecedfafd38e198a7fa59","contentType":"text/markdown; charset=utf-8"},{"id":"a0cb3b66-0aca-57f0-a932-b6e94329f792","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/a0cb3b66-0aca-57f0-a932-b6e94329f792/attachment.md","path":"references/io-sequential-await-in-loop.md","size":2039,"sha256":"931c6584396c07a23098113e5c11a77760fe549f319b6c7ffb19090daca3b46d","contentType":"text/markdown; charset=utf-8"},{"id":"bce9d06b-df41-565a-a23b-c19cd77000c4","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/bce9d06b-df41-565a-a23b-c19cd77000c4/attachment.md","path":"references/nested-cartesian-comparison.md","size":1885,"sha256":"16b02907c3b57ca449d8c0f7b2936c19dce541f9b9d677f1d454299c14b3337d","contentType":"text/markdown; charset=utf-8"},{"id":"297a0010-98c9-57bb-8873-10a1c91de580","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/297a0010-98c9-57bb-8873-10a1c91de580/attachment.md","path":"references/nested-explicit-quadratic-loops.md","size":1634,"sha256":"664a745d5bfd7436bd9772ebae20a54d408217998c43a2d439e2e80014fee529","contentType":"text/markdown; charset=utf-8"},{"id":"014e752b-032c-5dd1-ad8e-03a88dadff79","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/014e752b-032c-5dd1-ad8e-03a88dadff79/attachment.md","path":"references/nested-find-in-loop.md","size":1694,"sha256":"4d943a0b310f7994a699bc4d272cbc8f7f76302696d0a45c0986aa45a0536c2d","contentType":"text/markdown; charset=utf-8"},{"id":"acbc39fe-b9e4-5626-948c-f62a0efc1aaf","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/acbc39fe-b9e4-5626-948c-f62a0efc1aaf/attachment.md","path":"references/nested-includes-in-loop.md","size":1817,"sha256":"5d7296f3b9394c7bc7c6bc9bdaaf47e9375dfe1f1d9f104a37b989aac7527761","contentType":"text/markdown; charset=utf-8"},{"id":"152680ff-3053-5c42-9edf-eb271c1812cb","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/152680ff-3053-5c42-9edf-eb271c1812cb/attachment.md","path":"references/nested-set-operations-on-arrays.md","size":1792,"sha256":"234752b03a423fa0dd85239eb2874b0f3f3fbdab4a4e4c74d4de9b1b9593f7bc","contentType":"text/markdown; charset=utf-8"},{"id":"f351b76b-4a42-51ef-a503-ee361fce4001","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/f351b76b-4a42-51ef-a503-ee361fce4001/attachment.md","path":"references/nested-substring-search-in-loop.md","size":2541,"sha256":"8b96c496d4af9d98e3a9161689a58fb8f5f1072dca0bbb910f626545cc259be0","contentType":"text/markdown; charset=utf-8"},{"id":"4eb5be28-65fc-597b-9f10-8dae89fef5eb","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/4eb5be28-65fc-597b-9f10-8dae89fef5eb/attachment.md","path":"references/rec-iterative-for-deep-recursion.md","size":2084,"sha256":"b5d4938261625a77a6b37be96d076d65f186aa6cc23d9ecfbc15378ed98e4329","contentType":"text/markdown; charset=utf-8"},{"id":"4d48ecbc-9627-5722-a226-88109dd9e28d","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/4d48ecbc-9627-5722-a226-88109dd9e28d/attachment.md","path":"references/rec-memoize-overlapping-subproblems.md","size":2129,"sha256":"b4608c511dda7d0c0d9693ed7418a963c274f2a4acfca05abce6b2e9760b4329","contentType":"text/markdown; charset=utf-8"},{"id":"b7991824-133b-56b2-9922-55a9dbc720f8","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/b7991824-133b-56b2-9922-55a9dbc720f8/attachment.md","path":"references/rec-prune-with-bounds.md","size":3068,"sha256":"5008741b0b73c9fb60cb5ebdd5f18a9910a343062a70cc4dac8b5f331f6039ec","contentType":"text/markdown; charset=utf-8"},{"id":"6685aa1b-b4d2-5647-bb13-771987a4ffa9","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/6685aa1b-b4d2-5647-bb13-771987a4ffa9/attachment.md","path":"references/rec-share-memo-across-top-level-calls.md","size":2444,"sha256":"452531191b0711b9dc05488fe3d133353d7f158436ffc8236e819df4422cdd5f","contentType":"text/markdown; charset=utf-8"},{"id":"e4d3b3bc-2e9a-5e7e-8a6d-4729f4b5a60c","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/e4d3b3bc-2e9a-5e7e-8a6d-4729f4b5a60c/attachment.md","path":"references/rec-tabulate-bottom-up.md","size":2287,"sha256":"24eba89404c2ce737240af908bc65e1e699d6f2143c4aca48a107bc9cebdbd10","contentType":"text/markdown; charset=utf-8"},{"id":"889293cc-1d03-5887-bedb-17867a6e7224","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/889293cc-1d03-5887-bedb-17867a6e7224/attachment.md","path":"references/search-binary-search-on-sorted.md","size":1994,"sha256":"8acc93b861bf1378dd050ab670709c0db8f564ac07ae464eefcd086ed325aae2","contentType":"text/markdown; charset=utf-8"},{"id":"1c83be85-89e0-5073-90fd-522ad6b47f03","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/1c83be85-89e0-5073-90fd-522ad6b47f03/attachment.md","path":"references/search-build-index-once-amortize.md","size":2251,"sha256":"4f3297a5128693742052dac021ff75706cab108adc57d9cb7f9bd0e71ce9138e","contentType":"text/markdown; charset=utf-8"},{"id":"b50ae5d9-ef95-5ee5-9242-da282814c2dd","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/b50ae5d9-ef95-5ee5-9242-da282814c2dd/attachment.md","path":"references/search-quickselect-not-full-sort.md","size":2139,"sha256":"729f4d057d2518c0abc54c0a8bc3ede6bceca75126751a525d631cd75141cc06","contentType":"text/markdown; charset=utf-8"},{"id":"aac98fd7-f8fd-5b9a-9916-3dda69412ec2","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/aac98fd7-f8fd-5b9a-9916-3dda69412ec2/attachment.md","path":"references/search-sort-once-outside-loop.md","size":2127,"sha256":"d5f7546f37df604fe391cc49665714d2c47e374bf5cf4b685952fd3f0c5b89d9","contentType":"text/markdown; charset=utf-8"},{"id":"531c959e-9fc8-5e7d-9005-ac016c4cfdde","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/531c959e-9fc8-5e7d-9005-ac016c4cfdde/attachment.md","path":"references/space-generators-over-intermediate-lists.md","size":2182,"sha256":"de702e2a976111220d8554679ddec7e4ce4ba012a28d886c9d4f9706350c3625","contentType":"text/markdown; charset=utf-8"},{"id":"7eb01d69-2660-5041-a7a8-66929bf0799f","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/7eb01d69-2660-5041-a7a8-66929bf0799f/attachment.md","path":"references/space-release-retained-references.md","size":2765,"sha256":"4564781ebce44fce705fb9f17284adb2fa70559b2a1c694f977c2f192cd36eab","contentType":"text/markdown; charset=utf-8"},{"id":"1172c0eb-6a6d-569d-955d-e66975b815a2","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/1172c0eb-6a6d-569d-955d-e66975b815a2/attachment.md","path":"references/space-shallow-not-deep-copy.md","size":2225,"sha256":"93cdc915f1701b53ab08e24abb00d1a6bfbb3c3120b216a18a7a952637aa81bc","contentType":"text/markdown; charset=utf-8"},{"id":"09a55b1b-6356-5bf7-bc96-4c4db105ea29","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/09a55b1b-6356-5bf7-bc96-4c4db105ea29/attachment.md","path":"references/space-stream-dont-load.md","size":2474,"sha256":"f7934bfe90ea98f4ad6f90d775199c85d87d4483789df73d0480ddce553090f1","contentType":"text/markdown; charset=utf-8"}],"bundle_sha256":"3ba23cb4ffeb6c3269532e2d9a0d0f7158c654c5283aaf13d348b0dfeccd237c","attachment_count":44,"text_attachments":44,"attachment_storage":"skillopedia-attachments-v1","binary_attachments":0,"excluded_attachments":[]},"cluster_size":1,"skill_md_path":"skills/.experimental/algorithmic-complexity-review/SKILL.md","import_metadata":{"date":"2026-06-05","author":"@skillopedia","version":"v1","category":"web-development","category_label":"Web"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"web-development","import_tag":"clean-skills-v1","description":"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."}},"renderedAt":1782979866414}

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 - As…