Algo complexity analysis
Skill Pavel-Kravchenko/Bioinformatics/Skills/algo-complexity-analysis
Derive Big O time/space complexity of loops and recursion via recurrence relations; simplify expressions, compare growth at scale. Use when asked the complexity of code, hunting O(n^2) loops, or worst-case cost.From its SKILL.md
npx -y skills add Pavel-Kravchenko/Bioinformatics --skill algo-complexity-analysisAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
7.0 KB, ~2.0k tokens by cl100k_base, as published. Nobody here has run it
Algorithmic Complexity Analysis (Big O)
When to Use
- Asked to state or derive the time/space complexity ("what's the Big O of this function") of a code snippet or algorithm
- Reviewing code for hidden quadratic behavior:
inon a list inside a loop,+=string concatenation,sorted()inside a loop - Choosing between data structures/algorithms for scale (list vs set membership, sort vs heap)
- Deriving recursive complexity via a recurrence relation, e.g.
T(n) = 2T(n/2) + n(Master theorem) - Explaining best/average/worst-case or amortized cost (
list.append, hash table lookup, quicksort pivot choice)
Version Compatibility
- Language-agnostic technique; example code uses Python ≥3.8 stdlib only (
math, no third-party dependencies)
Prerequisites
- Comfortable reading Python loops, function calls, and recursion
- No packages to install
Complexity Classes (fastest to slowest)
| Class | Name | Example |
|---|---|---|
| O(1) | Constant | Dict lookup, array index |
| O(log n) | Logarithmic | Binary search |
| O(n) | Linear | Linear scan, single pass |
| O(n log n) | Linearithmic | Merge sort, heap sort |
| O(n²) | Quadratic | Nested loops, bubble sort |
| O(2ⁿ) | Exponential | Naive recursive Fibonacci, subset enumeration |
| O(n!) | Factorial | Permutation enumeration, brute-force TSP |
Simplification Rules
O(2n + 5) → O(n) # drop constants
O(n² + n) → O(n²) # drop lower-order terms
O(500) → O(1)
O(n² + n³) → O(n³)
O(A) then O(B) → O(A + B) # sequential loops add
O(A) inside O(B) → O(A × B) # nested loops multiply
Goal: classify the complexity of straight-line and loop-based code.
Approach: identify the loop structure (single / nested / sequential / halving), express operation count as a function of n, then apply the simplification rules above.
def get_first_element(arr):
"""Return the first element. O(1) time, O(1) space.
Direct index access: base_address + index * element_size,
independent of array length.
"""
return arr[0] if arr else None
def binary_search(arr, target):
"""Find target in a sorted array. O(log n) time, O(1) space.
Each iteration halves the search space: after k steps the
remaining size is n / 2**k, so it terminates in ~log2(n) steps.
"""
left, right = 0, len(arr) - 1
while left <= right:
mid = (left + right) // 2 # O(1)
if arr[mid] == target:
return mid
elif arr[mid] < target:
left = mid + 1 # discard left half
else:
right = mid - 1 # discard right half
return -1
def has_duplicate_naive(arr):
"""O(n²) time, O(1) space: compares every pair of elements."""
n = len(arr)
for i in range(n):
for j in range(i + 1, n):
if arr[i] == arr[j]:
return True
return False
def has_duplicate_fast(arr):
"""O(n) time, O(n) space: trades memory for speed via a set."""
seen = set()
for x in arr:
if x in seen: # O(1) average membership test
return True
seen.add(x)
return False
Goal: derive complexity of recursive functions.
Approach: write the recurrence relation T(n) = a*T(n/b) + f(n) (Master theorem form), then match it to a known pattern.
def merge_sort(arr):
"""Sort via divide-and-conquer. O(n log n) time, O(n) space.
Recurrence: T(n) = 2*T(n/2) + O(n) -> O(n log n)
(log n levels of recursion, O(n) merge work per level)
"""
if len(arr) <= 1:
return arr
mid = len(arr) // 2
left = merge_sort(arr[:mid])
right = merge_sort(arr[mid:])
return _merge(left, right)
def _merge(left, right):
"""Merge two sorted lists. O(n) time, O(n) space."""
result, i, j = [], 0, 0
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i]); i += 1
else:
result.append(right[j]); j += 1
result.extend(left[i:])
result.extend(right[j:])
return result
def fibonacci_naive(n):
"""Naive recursive Fibonacci. O(2^n) time, O(n) space (call stack).
Recurrence: T(n) = T(n-1) + T(n-2) + O(1) -> O(2^n)
Each call branches into two more calls, forming a binary call tree.
"""
if n <= 1:
return n
return fibonacci_naive(n - 1) + fibonacci_naive(n - 2)
| Pattern | Recurrence | Solution |
|---|---|---|
| Linear recursion | T(n) = T(n-1) + 1 | O(n) |
| Binary recursion (no reuse) | T(n) = 2T(n-1) + 1 | O(2ⁿ) |
| Divide & conquer (merge sort) | T(n) = 2T(n/2) + n | O(n log n) |
| Binary search | T(n) = T(n/2) + 1 | O(log n) |
At Scale (n = 1,000,000)
| Complexity | Operations | Feasible? |
|---|---|---|
| O(1) | 1 | Yes |
| O(log n) | ~20 | Yes |
| O(n) | 1,000,000 | Yes |
| O(n log n) | ~20,000,000 | Yes |
| O(n²) | 10¹² | No |
| O(2ⁿ) | ∞ | Never |
Best / Average / Worst
| Algorithm | Best | Average | Worst |
|---|---|---|---|
| Binary search | O(1) | O(log n) | O(log n) |
| Quicksort | O(n log n) | O(n log n) | O(n²) |
| Merge sort | O(n log n) | O(n log n) | O(n log n) |
| Hash table lookup | O(1) | O(1) | O(n) |
| BFS/DFS | O(V+E) | O(V+E) | O(V+E) |
Amortized Complexity
- Python
list.append(): O(1) amortized (occasional O(n) resize when capacity doubles, but rare) - Python
dict/setlookup: O(1) average; O(n) worst case (pathological hash collisions — rare with good hashing)
Pitfalls
- Hidden O(n) inside a loop:
x in some_listis O(n); inside an O(n) loop that's O(n²). Use asetfor O(1) membership (seehas_duplicate_fastabove). - String concatenation:
s += xin a loop reallocates and copies each time → O(n²) total. Use''.join(parts). sorted()is O(n log n): calling it inside a loop makes the loop O(n² log n) — sort once outside the loop.- Recursion depth: unbounded recursion on large
nhits Python's default ~1000-frame limit. Prefer an iterative rewrite over raisingsys.setrecursionlimit. - Space vs time trade-off: memoization/hash sets trade O(n) space for O(n²) → O(n) or O(1) repeated lookups.
- Worst-case vs average-case: quicksort degrades to O(n²) on already-sorted input with a naive pivot; use random/median-of-three pivot selection or Python's built-in Timsort (
sorted()/list.sort()), which is O(n log n) worst case.
See Also
algo-basic-algorithms— foundational search/sort algorithms referenced abovealgo-linear-binary-search— linear vs binary search trade-offs in depthalgo-comparison-sorts— merge sort, quicksort, heapsort implementationsalgo-intro-memoization— turning exponential recursion into polynomial time
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.
Gives 0 of the 12 instructions most research analysis skills give in ~2.0k tokens
Counted across 1,063 of the 1,754 authors here whose files we hold, read 2026-08-07
- Generate a markdown reportin 32 of 1063, across 23 files
- Cite each claim's sourcein 30 of 1063, across 15 files
- Define the ideal customer profilein 20 of 1063, across 2 files
- Search for companies matching the criteriain 20 of 1063, across 2 files
- Assign a fit score from one to tenin 20 of 1063, across 2 files
- Analyze the codebase to understand the productin 19 of 1063, across 1 file
- Ask clarifying questions about the value propositionin 19 of 1063, across 1 file
- Look for signals of immediate needin 19 of 1063, across 1 file
- Identify the target decision maker rolein 19 of 1063, across 1 file
- Suggest a personalized contact strategyin 19 of 1063, across 1 file
- Provide conversation starters for outreachin 19 of 1063, across 1 file
- Format results in a scannable markdown templatein 19 of 1063, across 1 file
Said here and by no other author read
- drop constants from complexity expressions
- add complexities for sequential loops
- multiply complexities for nested loops
- write a recurrence relation for recursive functions
- match recurrence relations to known patterns
- use sets for constant-time membership tests
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.