3.7.1Algorithm Paradigms

Brute force — exhaustive search, when acceptable

2,153 words10 min readdifficulty · medium

WHAT is brute force?

The two ingredients:

  1. Enumeration — a way to list every candidate exactly once (e.g. all subsets, all permutations, all pairs, all integers in a range).
  2. 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:

T=(number of candidates)×(cost to verify one)T = (\text{number of candidates}) \times (\text{cost to verify one})

The number of candidates usually grows combinatorially. Let's derive the famous ones from first principles.

So total time is e.g. Θ(2nverify)\Theta(2^n \cdot \text{verify}) for a subset search. These explode fast — which is exactly why we eventually need smarter paradigms (greedy, DP, divide-and-conquer).


Figure — Brute force — exhaustive search, when acceptable

WHEN is brute force acceptable?

Accept brute force when any of these hold:

  1. Small input bound. If constraints say n20n \le 20 for subsets (2201062^{20}\approx 10^6) or n10n \le 10 for permutations (10!3.6×10610! \approx 3.6\times10^6), the total fits in the budget (roughly 10810^8 simple operations per second).
  2. It's a one-off / not performance-critical. Run-once scripts, config-time computation.
  3. You need a correct reference to test an optimized solution against (differential testing).
  4. 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?
n11n \le 11 O(n!)O(n!) yes (permutations)
n20n \le 202424 O(2n)O(2^n) yes (subsets)
n500n \le 500 O(n3)O(n^3) borderline
n5000n \le 5000 O(n2)O(n^2) maybe
n105n \le 10^5 O(nlogn)O(n\log n) no
n109n \le 10^9 O(logn)O(\log n) / O(1)O(1) no

Worked Example 1 — Two-Sum by brute force

Problem: given array aa and target tt, find indices i<ji<j with ai+aj=ta_i+a_j=t.

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 (n2)\binom{n}{2} pairs covers the whole space exactly once (we start jj at i+1i+1 to avoid duplicates & self-pairs).
  • Why correct? Every valid pair is some (i,j)(i,j) with i<ji<j, and we visit all of them.
  • Cost: Θ(n2)\Theta(n^2). Acceptable for nn\le a few thousand; for n=105n=10^5 use a hash set (O(n)O(n)).

Worked Example 2 — Subset sum (max value under a weight cap)

Problem: pick a subset of items maximizing total value with total weight W\le W.

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 << n masks? A bitmask mask from 00 to 2n12^n-1 enumerates every subset: bit ii set ⇔ item ii chosen. This realises the 2n2^n count we derived.
  • Why correct? Optimal subset is some subset → it is one of the masks → it gets considered.
  • Cost: Θ(2nn)\Theta(2^n \cdot n). Fine for n20n\le 20. Beyond that, switch to DP (O(nW)O(nW)).

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 10410^4? Length-4 string over 10 digits → bk=104b^k = 10^4 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?
Enumerate every candidate in the solution space and test each; uses no shortcut/insight. Correct if enumeration is complete & verifier is correct.
Why is brute force guaranteed correct?
If enumeration misses no candidate, the true answer is among those checked.
Number of subsets of an n-element set and why?
2n2^n — each element is independently in or out (2 choices, n times).
Number of permutations of n items and why?
n!n!nn choices for slot 1, n1n-1 for slot 2, … down to 1.
Number of unordered pairs from n items?
(n2)=n(n1)/2=Θ(n2)\binom{n}{2}=n(n-1)/2 = \Theta(n^2).
General time cost of brute force?
(#candidates) × (cost to verify one).
Rough operations-per-second budget to compare against?
~10810^8 (to 10910^9) simple ops/sec.
If constraint is n20n\le 20, what brute force is OK?
Subset enumeration O(2n)O(2^n) since 2201062^{20}\approx10^6.
If constraint is n11n\le 11, what brute force is OK?
Permutation enumeration O(n!)O(n!).
How do you enumerate all subsets with bitmasks?
Loop mask from 0 to 2n12^n-1; bit ii set ⇔ item ii included.
When should you NOT use brute force?
When search-space × verify cost ≫ 10810^8 and exploitable structure (sorting, hashing, DP, greedy) exists.
Common enumeration bug for pairs and the fix?
Double counting/self-pairs; fix by starting inner loop at i+1.
Why keep a brute-force version even after optimizing?
As a correct reference for differential/stress testing the fast algorithm.

Connections

  • Algorithm Paradigms — brute force is the baseline paradigm
  • Time Complexity & Big-O — how we estimate 2n2^n, n!n!, n2n^2 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

needs

needs

complete enumeration gives

correct predicate gives

used to test

serves as

cost is

equals candidates times verify

counted by

subsets 2^n, perms n!

forces

else use

Brute Force / Exhaustive Search

Enumeration - list every candidate

Verification - test each candidate

Always correct

Baseline for comparison

Time cost T

Combinatorial explosion

Search space sizes

Acceptable when small input

Smarter paradigms

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: nn items ke subsets 2n2^n hote hain (har item ya to andar ya bahar), permutations n!n! hote hain, aur pairs n2n^2 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 10810^8 simple operations per second karta hai. Constraint dekho aur formula me daalo. Agar n20n \le 20 hai to 2n1062^n \approx 10^6 — bilkul theek hai. Agar n11n \le 11 hai to n!n! bhi chalega. Lekin agar n=105n = 10^5 hai to n2=1010n^2 = 10^{10} — 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.

Go deeper — visual, from zero

Test yourself — Algorithm Paradigms

Connections