Brute force — exhaustive search, when acceptable
WHAT is brute force?
The two ingredients:
- Enumeration — a way to list every candidate exactly once (e.g. all subsets, all permutations, all pairs, all integers in a range).
- Verification — a predicate that checks whether a candidate is a/the answer.
WHY does it work (and why is it slow)?
The price is time. The cost is:
The number of candidates usually grows combinatorially. Let's derive the famous ones from first principles.
So total time is e.g. for a subset search. These explode fast — which is exactly why we eventually need smarter paradigms (greedy, DP, divide-and-conquer).

WHEN is brute force acceptable?
Accept brute force when any of these hold:
- Small input bound. If constraints say for subsets () or for permutations (), the total fits in the budget (roughly simple operations per second).
- It's a one-off / not performance-critical. Run-once scripts, config-time computation.
- You need a correct reference to test an optimized solution against (differential testing).
- No better algorithm is known (some NP-hard problems — you brute force with pruning).
Reject it when the search space exceeds your time budget and structure exists to exploit.
| Pattern in constraints | Likely intended complexity | Brute force OK? |
|---|---|---|
| yes (permutations) | ||
| – | yes (subsets) | |
| borderline | ||
| maybe | ||
| no | ||
| / | no |
Worked Example 1 — Two-Sum by brute force
Problem: given array and target , find indices with .
def two_sum_brute(a, t):
n = len(a)
for i in range(n): # candidate first index
for j in range(i+1, n): # candidate second index
if a[i] + a[j] == t:
return (i, j)
return None- Why the nested loop? The candidates are unordered pairs; enumerating all pairs covers the whole space exactly once (we start at to avoid duplicates & self-pairs).
- Why correct? Every valid pair is some with , and we visit all of them.
- Cost: . Acceptable for a few thousand; for use a hash set ().
Worked Example 2 — Subset sum (max value under a weight cap)
Problem: pick a subset of items maximizing total value with total weight .
def best_subset(weights, values, W):
n = len(weights)
best = 0
for mask in range(1 << n): # all 2^n subsets, encoded as bits
wt = val = 0
for i in range(n):
if mask & (1 << i): # is item i in this subset?
wt += weights[i]
val += values[i]
if wt <= W:
best = max(best, val)
# Why this step? we only update best for FEASIBLE subsets
return best- Why
1 << nmasks? A bitmaskmaskfrom to enumerates every subset: bit set ⇔ item chosen. This realises the count we derived. - Why correct? Optimal subset is some subset → it is one of the masks → it gets considered.
- Cost: . Fine for . Beyond that, switch to DP ().
Worked Example 3 — Cracking a 4-digit PIN
def crack(check): # check(pin) -> True if correct
for pin in range(10000): # 10^4 candidates
s = f"{pin:04d}"
if check(s):
return s- Why ? Length-4 string over 10 digits → candidates. Tiny, so brute force is instant — this is why short PINs are weak.
Recall Feynman: explain to a 12-year-old
Imagine you lost your house key and you have a giant ring with 200 keys. Brute force is just trying every single key, one by one, until the door opens. You will definitely get in eventually — that's the good part. The bad part is it might take forever if there are a zillion keys. So brute force is great when the keyring is small, and a bad idea when it's huge — in that case you'd rather think about which keys look right (that's what smarter algorithms do).
Flashcards
What defines a brute-force algorithm?
Why is brute force guaranteed correct?
Number of subsets of an n-element set and why?
Number of permutations of n items and why?
Number of unordered pairs from n items?
General time cost of brute force?
Rough operations-per-second budget to compare against?
If constraint is , what brute force is OK?
If constraint is , what brute force is OK?
How do you enumerate all subsets with bitmasks?
When should you NOT use brute force?
Common enumeration bug for pairs and the fix?
Why keep a brute-force version even after optimizing?
Connections
- Algorithm Paradigms — brute force is the baseline paradigm
- Time Complexity & Big-O — how we estimate , , growth
- Dynamic Programming — replaces exponential subset/sequence brute force with polynomial DP
- Greedy Algorithms — trades exhaustive checking for a single myopic choice
- Backtracking — brute force with pruning; skips provably-bad branches
- Bitmasking — the standard technique to enumerate subsets
- NP-Hard Problems — where brute force (with pruning) is sometimes the best we know
Concept Map
Hinglish (regional understanding)
Intuition Hinglish mein samjho
Brute force ka matlab simple hai: koi shortcut mat dhundo, bas saare possible answers ek-ek karke try karo aur check karo kaun sa sahi hai. Isko exhaustive search bhi kehte hain. Sabse badi khoobi yeh hai ki yeh hamesha correct hota hai — agar tumne saare candidates enumerate kar liye aur sahi se check kiya, to answer zaroor mil jayega. Isi liye ise hum baseline maante hain aur fast algorithms ko test karne ke liye reference ki tarah use karte hain.
Problem sirf speed ki hai. Search space bahut tezi se badhta hai: items ke subsets hote hain (har item ya to andar ya bahar), permutations hote hain, aur pairs ke order ke. Yeh numbers jaldi explode kar jaate hain. Total time = (kitne candidates) × (ek candidate check karne ka cost).
Ab sabse important cheez — kab brute force chalega? Rule yaad rakho: computer roughly simple operations per second karta hai. Constraint dekho aur formula me daalo. Agar hai to — bilkul theek hai. Agar hai to bhi chalega. Lekin agar hai to — yeh time out ho jayega, tab tumhe hashing, sorting, DP ya greedy jaisa structure exploit karna padega.
Practical tip: pehle constraint ko formula me daal ke estimate karo, phir decide karo. Aur ek aur cheez — enumeration me galti mat karna (jaise pairs me i+1 se shuru karo warna double count ho jayega), aur answer update karne se pehle constraint feasible hai ki nahi woh check karo. Bas yahi 80/20 hai brute force ka.