09

Math & Number Theory

gcd, primes, mod 10⁹+7, fast power, nCr and digit tricks: small math that unlocks big interview problems.

intermediate~75 min6 simulations9 problems

▶ guided lesson⚡ 1-minute summary↻ 15 recall cards

before this: Big-O · Recursion

01 · why it exists

Why this exists, and the weight it carries

sincec. 300 BCE

Euclid's algorithm (gcd and lcm)

Euclid of Alexandria (Elements, Book VII); the method is probably older

Euclid's Elements (c. 300 BCE), Book VII, Propositions 1–2, finds the "greatest common measure" of two numbers by repeatedly taking the smaller from the larger. Historians think Euclid collected the method rather than invented it. In 1844 Gabriel Lamé proved it never needs more than 5 × (digits of the smaller number) division steps, a result often called the start of computational complexity theory. Knuth calls it the oldest nontrivial algorithm that is still in use.

the problem it solvedFind the largest number that divides two numbers exactly — without listing all their divisors.

its jobs today

  • Reducing fractions and ratios to one canonical form: a 1920 × 1080 screen is 16:9 because gcd(1920, 1080) = 120; Max Points on a Line uses the same trick for directions.
  • The extended version computes modular inverses — the step that derives an RSA private key.
  • Big numbers in the JDK: BigInteger.gcd runs Euclid while the numbers differ in length, then binary GCD.

the weight it carries

Illustrative: two numbers near 10¹⁸ (a long). Subtracting the smaller from the larger: gcd(10¹⁸, 1) needs 10¹⁸ − 1 subtractions — about 31.7 years at 10⁹ per second. Euclid with %: the worst case in a long is the Fibonacci pair F₉₂, F₉₁, which takes 90 divisions (Lamé's bound: 5 × 19 digits = 95).

without it

Exact fractions would need slow divisor searches, and RSA key setup (which needs a modular inverse) would lose its fast path.

when · why · how

when
You need a gcd or lcm, a reduced fraction or direction, or to know whether two numbers share a factor.
why
O(log min(a, b)) divisions and O(1) space, against O(min(a, b)) for trying every divisor.
how
while (b != 0) { int r = a % b; a = b; b = r; } return a; · lcm = (long) a / gcd(a, b) * b · BigInteger.gcd for huge values.

02 · plain english

The idea in 30 seconds

Many interview problems hide a little number theory: a gcd, a prime check, a remainder, a power, a count of ways, a digit loop.

Each one has a tiny classic algorithm that turns a slow loop into O(log n) or close: Euclid, the sieve, fast power, Fermat's inverse.

Java adds one rule on top: know the overflow limits (int ≈ 2.1·10⁹, long ≈ 9.2·10¹⁸) and check before you multiply.

picture this

Modular arithmetic is the 12-hour clock on your taskbar: 3 hours after 11 o'clock it shows 2, not 14. % m lets a count grow forever while the stored value stays in 0..m−1. Your CPU's int already wraps like this at 2³² — silently — which is why we choose the wrap ourselves.

03 · remember

What you must know

  • Euclid: gcd(a, b) = gcd(b, a % b), stop when b is 0. O(log min(a, b)): at most 91 divisions even for two longs (90 when a ≥ b). lcm = a / gcd * b (divide first).
  • Sieve of Eratosthenes: for each prime p with p² ≤ n, cross out p², p² + p, …. O(n log log n) time, O(n) memory. For a single number, trial division up to √n is enough.
  • Modulo: reduce after every + and ×: (a + b) % M, (long) a * b % M. Java's % can be negative, so use ((x % M) + M) % M or Math.floorMod.
  • Why 10⁹+7: it is prime (so division works through Fermat), a residue fits in an int, and the product of two residues (< 10¹⁸) fits in a long.
  • Fast power: square the base each step and multiply it in when the exponent's lowest bit is 1. O(log e). For a prime p, a^(p−2) mod p is the inverse of a.
  • nCr: Pascal's rule nCr = (n−1)C(r−1) + (n−1)Cr for small n; factorials and inverse factorials mod p for n up to 10⁵ and beyond.
  • Digits: x % 10 reads the last digit, x / 10 drops it, rev * 10 + d appends one. Guard against overflow before the multiply.
  • Weighted random: prefix sums turn weights into ticket ranges; a binary search finds the owner of a random ticket in O(log n).

04 · see it

Play with it in 3D

Press Space to play, ←/→ to step, drag to move, ? for all shortcuts. Try your own input.

sim

Euclid's gcd step by step

The pair (a, b) slides left as (b, a % b). Watch the bars collapse in a handful of divisions.

loading simulation…
sim

Sieve of Eratosthenes on a number board

Each prime crosses out its multiples starting at p². Whatever survives is prime.

loading simulation…
sim

Fast power, bit by bit

Read the exponent's bits from the right. Square the base every step; multiply it in only on a 1-bit.

loading simulation…
sim

Pascal's triangle (Meru-prastāra) as a 3D landscape

Every inside cell is the sum of the two cells above it. Row n adds up to 2ⁿ.

loading simulation…
sim

Reverse Integer: pop, check, push

Digits leave x from the right and join rev. The guard fires before rev × 10 could overflow.

loading simulation…
sim

Weighted pick with prefix sums

Index i owns w[i] tickets. A random ticket's owner is found by binary search on the prefix sums.

loading simulation…

05 · cost

Time & space, explained

The number-theory toolkit
TimeExtra spacewhy
gcd by repeated subtractionO(max(a, b))O(1)gcd(10¹⁸, 1) needs 10¹⁸ − 1 subtractions.
gcd by Euclid (with %)O(log min(a, b))O(1)Every two steps the larger number drops below half. Lamé: at most 5 × (digits of the smaller).
Is n prime? (trial division)O(√n)O(1)Divisors come in pairs d × (n / d), and one of each pair is ≤ √n.
All primes ≤ n (sieve)O(n log log n)O(n)Each prime p crosses about n / p cells; Σ n / p over primes is n log log n. n = 10⁶: 2,122,048 crossings.
aᵉ mod m, one multiply at a timeO(e)O(1)e = 10¹⁸ would take about 31.7 years at 10⁹ multiplications per second.
aᵉ mod m, fast powerO(log e)O(1)One loop step per bit of e: 60 steps for e = 10¹⁸.
Inverse mod a prime p (Fermat)O(log p)O(1)It is one fast power: a^(p−2) mod p.
Pascal's table up to row nO(n²)O(n²)n(n + 1)/2 cells. Row 10⁵ would need 5·10⁹ cells, about 40 GB of longs.
nCr mod p with factorial tablesO(n + log p) once, O(1) per queryO(n)n multiplications for fact[], one Fermat inverse, n more for invFact[]; each nCr is 2 multiplications.
Peel the digits of xO(log₁₀ x)O(1)An int has at most 10 digits, a long at most 19.
Random Pick with Weight (n weights, total S)
BuildPer pickSpacewhy
Ticket array (index i written w[i] times)O(S)O(1)O(S)S can reach 10⁴ × 10⁵ = 10⁹ ints, about 4 GB.
Prefix sums + linear scanO(n)O(n)O(n)Walk prefix[] until it reaches the ticket.
Prefix sums + binary searchO(n)O(log n)O(n)prefix[] is strictly increasing (every w[i] ≥ 1): 14 probes for n = 10⁴.

06 · java

Raw vs Collections Framework

gcd: write it vs call it

javaEuclid's loop + lcmjava.math.BigInteger · java.util.*
class Euclid {    /** Greatest common divisor of two non-negative ints. gcd(a, 0) = a. */    static int gcd(int a, int b) {        while (b != 0) {            int r = a % b;            a = b;            b = r;        }        return a;    }     /** Least common multiple. Divide first, then multiply, in long: a / gcd * b never overflows early. */    static long lcm(int a, int b) {        if (a == 0 || b == 0) return 0;        return (long) a / gcd(a, b) * b;    }}
  • Java has no Math.gcd. Write the four-line loop from memory; interviewers expect it.
  • BigInteger.gcd runs Euclid while the numbers differ a lot in length, then switches to binary GCD (MutableBigInteger.hybridGCD in OpenJDK).
  • lcm: (long) a / gcd(a, b) * b. Dividing first keeps the intermediate value small; a * b / gcd can overflow even when the lcm fits.

The sieve

javaboolean[] sievejava.math.BigInteger · java.util.*
class Sieve {    /** isPrime[i] for every 0 <= i <= n, in O(n log log n). */    static boolean[] sieve(int n) {        boolean[] isPrime = new boolean[n + 1];        for (int i = 2; i <= n; i++) isPrime[i] = true;        for (int p = 2; (long) p * p <= n; p++) {            if (!isPrime[p]) continue;            for (int m = p * p; m <= n; m += p) isPrime[m] = false;        }        return isPrime;    }     static List<Integer> primesUpTo(int n) {        boolean[] isPrime = sieve(n);        List<Integer> primes = new ArrayList<>();        for (int i = 2; i <= n; i++) if (isPrime[i]) primes.add(i);        return primes;    }}
  • (long) p * p <= n: p * p overflows an int once p > 46,340. p <= n / p is another safe way to write it.
  • boolean[] costs about one byte per number: 10⁷ numbers is about 10 MB. A BitSet stores one bit each (about 1.25 MB) at some speed cost.
  • The JDK uses the same idea: BigInteger.probablePrime sieves candidates with a java.math.BitSieve (odd numbers only) before running the expensive primality test.

Modular arithmetic

javaadd, sub, mul mod 10⁹+7java.math.BigInteger · java.util.*
class Mod {    static final int MOD = 1_000_000_007; // prime, and 2 * (MOD - 1) still fits in an int     static int add(int a, int b) {        return (a + b) % MOD;                      // a, b < MOD, so a + b < 2.15 * 10^9: no overflow    }     static int sub(int a, int b) {        return ((a - b) % MOD + MOD) % MOD;        // Java's % can be negative: shift it back up    }     static int mul(int a, int b) {        return (int) ((long) a * b % MOD);         // widen BEFORE multiplying: the product needs 60 bits    }     static int floorModDemo(int a, int m) {        return Math.floorMod(a, m);                // library version of ((a % m) + m) % m    }}
  • (a * b) % M with int a and b multiplies in 32 bits and overflows before the %. Cast first: (long) a * b % M.
  • Java's % takes the sign of the left operand (JLS §15.17.3): -7 % 3 == -1. Math.floorMod(-7, 3) == 2.
  • BigInteger.modPow and modInverse are perfect for checking your answers; in an interview, write the loop.

Fast power and the modular inverse

javabinary exponentiationjava.math.BigInteger · java.util.*
class FastPower {    /** base^exp mod m by binary exponentiation: about 2 * log2(exp) multiplications. */    static long modPow(long base, long exp, long mod) {        long result = 1 % mod;        base = ((base % mod) + mod) % mod;        while (exp > 0) {            if ((exp & 1) == 1) result = result * base % mod;            base = base * base % mod;            exp >>= 1;        }        return result;    }     /** Inverse of a modulo a PRIME p (Fermat): a^(p-2), valid when a % p != 0. */    static long modInverse(long a, long p) {        return modPow(a, p - 2, p);    }}
  • Keep result, base and mod as long. With mod ≤ 2³¹ − 1, every product of two residues is below 2⁶², so it fits.
  • 1 % mod (not 1) makes mod = 1 return 0, and ((base % mod) + mod) % mod handles a negative base.
  • Fermat's inverse a^(p−2) needs a prime p and a % p != 0. For other moduli, use extended Euclid or BigInteger.modInverse.

Counting: Pascal's triangle

javac[n][r] table in longjava.math.BigInteger · java.util.*
class Pascal {    /** c[n][r] = nCr for every 0 <= r <= n <= rows. Exact in long up to n = 66. */    static long[][] table(int rows) {        long[][] c = new long[rows + 1][];        for (int n = 0; n <= rows; n++) {            c[n] = new long[n + 1];            c[n][0] = c[n][n] = 1;            for (int r = 1; r < n; r++) {                c[n][r] = c[n - 1][r - 1] + c[n - 1][r];            }        }        return c;    }}
  • Exact in long up to row 66: C(66, 33) = 7,219,428,434,016,265,740 fits, C(67, 33) does not.
  • Each row only needs the row above it, so one long[] updated from right to left also works (O(n) space).

Counting: nCr mod p for big n

javafactorials + inverse factorialsjava.math.BigInteger · java.util.*
class BinomialMod {    static final int MOD = 1_000_000_007;    final long[] fact, invFact;     /** Precompute n! and 1/n! mod p once: O(n + log p). Then every nCr is O(1). */    BinomialMod(int maxN) {        fact = new long[maxN + 1];        invFact = new long[maxN + 1];        fact[0] = 1;        for (int i = 1; i <= maxN; i++) fact[i] = fact[i - 1] * i % MOD;        invFact[maxN] = power(fact[maxN], MOD - 2);              // Fermat: a^(p-2) = 1/a        for (int i = maxN; i > 0; i--) invFact[i - 1] = invFact[i] * i % MOD;    }     long nCr(int n, int r) {        if (r < 0 || r > n) return 0;        return fact[n] * invFact[r] % MOD * invFact[n - r] % MOD; // n! / (r! (n-r)!)    }     private static long power(long base, long exp) {   // the same loop as modPow above        long result = 1;        base %= MOD;        while (exp > 0) {            if ((exp & 1) == 1) result = result * base % MOD;            base = base * base % MOD;            exp >>= 1;        }        return result;    }}
  • One Fermat inverse for invFact[maxN], then invFact[i − 1] = invFact[i] * i walks down for free.
  • Multiply in steps and reduce each time: fact[n] * invFact[r] % MOD * invFact[n − r] % MOD.

Digits: arithmetic vs strings

java% 10 and / 10java.util.*
class Arithmetic {    /** Sum of the decimal digits. Works for negatives too: the sign is ignored. */    static int digitSum(int x) {        int sum = 0;        while (x != 0) {            sum += Math.abs(x % 10);   // last digit (Java's % keeps the sign of x, so take abs)            x /= 10;                   // drop the last digit        }        return sum;    }     /** How many digits a non-negative number has (0 has one digit). */    static int countDigits(long x) {        int count = 1;        while (x >= 10) {            x /= 10;            count++;        }        return count;    }     /** Digits of a non-negative number, most significant first. */    static int[] toDigits(long x) {        int[] digits = new int[countDigits(x)];        for (int i = digits.length - 1; i >= 0; i--) {            digits[i] = (int) (x % 10);            x /= 10;        }        return digits;    }     /** Rebuild a number from its digits: shift left one place (x 10), then add the new digit. */    static long fromDigits(int[] digits) {        long x = 0;        for (int d : digits) x = x * 10 + d;        return x;    }}
  • Arithmetic is O(digits) with no allocation; the String route is also O(digits) but creates objects every call.
  • Math.abs(Integer.MIN_VALUE) is still −2,147,483,648. Widen to long first, or work with negative values like the JDK does.
  • ch - '0' turns a digit character into its value: '7' - '0' == 7.
Java API you will actually use
calldoescost
Math.floorMod(x, m)Remainder in [0, m) for m > 0, even when x is negativeO(1)
Math.multiplyExact(a, b) / Math.addExact(a, b)Throws ArithmeticException on int/long overflow instead of wrappingO(1)
Integer.MAX_VALUE / Long.MAX_VALUE2,147,483,647 and 9,223,372,036,854,775,807—
Math.abs(x)Absolute value. Careful: Math.abs(Integer.MIN_VALUE) stays negativeO(1)
BigInteger.valueOf(a).gcd(BigInteger.valueOf(b))gcd for numbers of any sizeEuclid + binary GCD
BigInteger.valueOf(a).modPow(e, m)aᵉ mod m with arbitrary-size numbersO(log e) multiplications
BigInteger.valueOf(a).modInverse(m)a⁻¹ mod m for any m with gcd(a, m) = 1; throws otherwiseExtended Euclid
new Random().nextInt(bound)Uniform int in [0, bound); rejects a few raw values to avoid modulo biasO(1) expected
Arrays.binarySearch(sorted, key)Index of key, or −(insertion point) − 1 when missingO(log n)
Long.toString(x) / ch - '0'Digits as text / one digit character to its valueO(digits) / O(1)

gcd or lcm of two numbers

→ Euclid's loop

O(log min(a, b)), no imports, four lines.

Is this one number prime?

→ Trial division up to √n

O(√n) and no memory; a sieve would be overkill.

Primes (or prime checks) for every number up to ~10⁷

→ Sieve of Eratosthenes

O(n log log n) once, then O(1) per lookup.

"Return the answer modulo 10⁹+7"

→ long products, reduce after every + and ×

Keeps every value below 10⁹+7 with no overflow.

aᵇ mod m, or division under a prime modulus

→ Fast power; inverse = a^(p−2)

O(log b) instead of O(b).

nCr for n ≤ 66 exactly, or small n mod p

→ Pascal's table

Only additions, easy to get right.

nCr mod p for n up to 10⁵ or more

→ fact[] and invFact[] tables

O(n) precompute, O(1) per query.

Pick an index with probability ∝ weight

→ Prefix sums + binary search

O(n) build, O(log n) per pick, O(n) memory.

07 · recognise

Spot the pattern

"The answer may be large, return it modulo 10⁹+7"

Reduce after every + and ×, use long for products, divide with Fermat's inverse

Fractions, slopes or ratios that must compare exactly

Reduce (dy, dx) by their gcd with one sign rule — never use doubles as keys

Count primes, or smallest prime factors for many numbers

Sieve once up to the limit

xⁿ with n up to 10⁹ or 10¹⁸

Fast power: square and multiply, O(log n)

"How many ways to choose / arrange"

nCr: Pascal's rule, or factorials with inverse factorials mod p

Reverse, palindrome or digit sums of a number, "without converting to a string"

Peel digits with % 10 and / 10; guard overflow before rev * 10

"Pick with probability proportional to weight"

Prefix sums + binary search for the first prefix ≥ ticket

Trailing zeros of n!

Count the factors of 5: n/5 + n/25 + n/125 + …

08 · traps & tricks

Mistakes to avoid, tricks to use

traps

  • (a * b) % M with ints: the product overflows before the % runs. Write (long) a * b % M.
  • Forgetting that Java's % can be negative: (a - b) % M may be below 0. Add M and take % again, or use Math.floorMod.
  • p * p <= n in the sieve overflows for p > 46,340 — use (long) p * p <= n.
  • Math.abs(Integer.MIN_VALUE) is still negative, and -Integer.MIN_VALUE == Integer.MIN_VALUE.
  • Checking for overflow after rev * 10 + d: by then the value has already wrapped around. Check before.
  • Using a double slope as a HashMap key: 0.0 and -0.0 are different keys, and vertical lines divide by zero.
  • lcm = a * b / gcd(a, b) overflows even when the lcm fits. Divide first: a / gcd * b.
  • Using Fermat's inverse with a modulus that is not prime, or with a ≡ 0 (mod p): the result is simply wrong.

tricks

  • Memorise three numbers: 2³¹ − 1 = 2,147,483,647 (int), about 9.2·10¹⁸ (long), and 10⁹+7.
  • When the statement says "modulo 10⁹+7", say out loud: "I'll keep everything reduced and use long for products." It shows you know the trap.
  • Before coding a digit loop, dry-run 120 on paper. Chalo, pop 0, then 2, then 1: rev = 21 — the trailing zero vanished by itself.
  • Test every number problem with 0, a negative, 1, Integer.MAX_VALUE and Integer.MIN_VALUE. Most hidden test cases live there.
  • If you forget the gcd loop under pressure, rebuild it from one fact: a common divisor of a and b also divides a % b.

09 · why & how

Questions you might be too shy to ask

Why do so many problems say "return the answer modulo 10⁹+7"?

Because the true answer is astronomically large — 2¹⁰⁰ alone has 31 digits and a long holds 19. The judge needs a fixed-size number to compare. 10⁹+7 is prime, a residue fits in an int, and (10⁹+6)² ≈ 10¹⁸ still fits in a long, so (long) a * b % M is always safe.

Can't I just compute the full answer and take % M once at the end?

No: the full answer is exactly the number that doesn't fit, so it overflows long before the end. The good news: % can be applied after every step without changing the final result. (a + b) % M = ((a % M) + (b % M)) % M, and the same holds for ×. So reduce after every + and ×, and every value stays below M.

In (long) a * b % M, which part happens first?

The cast binds tightest, so a becomes a long first. Then * and % run left to right: ((long) a * b) % M. The multiply happens in 64 bits, so no overflow. (long) (a * b) % M is wrong: the brackets make a * b run in 32 bits and overflow before the cast.

Why does Java say -7 % 3 is -1 and not 2?

Java's integer division truncates toward zero, so the remainder takes the sign of the left operand (JLS §15.17.3). Mathematically both −1 and 2 are "−7 mod 3"; Java picks −1. When you need 0..m−1, use Math.floorMod(x, m) or ((x % m) + m) % m.

Why not just write Math.pow(a, e) % M?

Math.pow returns a double. A double holds every whole number exactly only up to 2⁵³ ≈ 9·10¹⁵. 3⁴⁰ ≈ 1.2·10¹⁹ is already past that, so its last digits are lost, and % M then gives a wrong answer. Bigger powers even become Infinity. Use fast power with long and % M at every step.

Do I need to prove Euclid's algorithm in an interview?

One sentence is enough: a % b = a − q·b, so any number dividing a and b also divides a % b, and any number dividing b and a % b also divides a. Same common divisors, so the same gcd. Bas itna yaad rakho.

How do I divide when everything is mod p?

You multiply by the inverse instead. When p is prime and a % p ≠ 0, Fermat's little theorem gives a^(p−1) ≡ 1, so a^(p−2) is a's inverse — one fast power. For a modulus that isn't prime, use extended Euclid or BigInteger.modInverse; there the inverse exists only when gcd(a, m) = 1.

Is 1 a prime? Is 0?

Neither. A prime has exactly two different positive divisors: 1 and itself. 1 has only one divisor, and 0 is divisible by everything. That's why the sieve and the prime count start from 2, and why Count Primes returns 0 for n = 0, 1 and 2.

Sieve or trial division — how do I choose?

A few numbers: trial division up to √n each, no memory. Many queries up to a limit N (≈10⁷ fits in memory): sieve once in O(N log log N), then each lookup is O(1).

Palindrome Number: why does x == half / 10 handle odd lengths?

Dry-run 12321. The loop moves digits until half catches up: it stops with x = 12 and half = 123. The middle digit 3 sits at the end of half, and it doesn't need a partner. half / 10 drops it: 123 / 10 = 12, which equals x, so it's a palindrome. For even lengths (1221) the halves match directly: x = 12, half = 12.

Reverse Integer: do I need a special case for negative x?

No. In Java, -123 % 10 is −3 and -123 / 10 is −12, so the digits come out negative. The loop builds rev = −3 → −32 → −321 by itself. It's also safer than calling Math.abs(x) on the int first: Math.abs(Integer.MIN_VALUE) is still negative (it overflows).

Reverse Integer: where do the pop > 7 and pop < -8 checks come from?

From the last digits of the limits: Integer.MAX_VALUE is 2,147,483,647 and Integer.MIN_VALUE is −2,147,483,648. If rev is exactly 214,748,364, then rev * 10 is 2,147,483,640 — only a pop of 0..7 still fits. On the negative side, only −8..0 fit. Bas itna yaad rakho: 7 for MAX, −8 for MIN.

What if the items arrive as a stream and I can't build prefix sums?

Reservoir sampling, for a uniform pick. Keep one current choice. When the i-th item arrives (counting from 1), replace your choice with it with probability 1/i. At the end every one of the n items was kept with probability 1/n. That is LC 382 Linked List Random Node and LC 398 Random Pick Index.

Is Math.random() fine, or should I use Random?

Both are fine on LeetCode. random.nextInt(bound) reads more clearly and returns an int in [0, bound) with (approximately) equal chances: the JDK rejects a few raw values so no number is favoured (see the Random.nextInt Javadoc). (int) (Math.random() * bound) works too, with a tiny rounding bias you can ignore here.

10 · practice

Interview problems

Every problem has brute → better → optimal solutions in Java, with complexity and a dry run.

  1. #66
    Plus One
    EasyIntuitGoogleAmazonMicrosoft
  2. #9
    Palindrome Number
    EasyTCSInfosysBloombergGoogleMicrosoft+1
  3. #202
    Happy Number
    EasyAirbnbGoogleAmazonApple
  4. #7
    Reverse Integermust-do
    MediumBloombergAppleGoogleMicrosoftAmazon+1
  5. #172
    Factorial Trailing Zeroes
    MediumBloombergMicrosoftAmazon
  6. #204
    Count Primes
    MediumMicrosoftAmazon
  7. #43
    Multiply Stringsmust-do
    MediumMetaMicrosoftGoogleAmazon
  8. #528
    Random Pick with Weightmust-do
    MediumMetaUberLinkedInAmazonGoogle
  9. #149
    Max Points on a Line
    HardLinkedInAppleGoogleAmazonMicrosoft

Also practise this here

Each problem has one home page in the course; these use this chapter's idea too. The note says what to look for.

  1. #50
    Pow(x, n)
    Mediumin Recursion

    Fast power on doubles, with negative n and the Integer.MIN_VALUE trap — the same halving idea as modPow.

  2. #62
    Unique Paths
    Mediumin Dynamic Programming

    The DP answer equals C(m + n − 2, m − 1): one nCr counts every path.

  3. #268
    Missing Number
    Easyin Bits

    A closed-form shortcut: Gauss's sum n(n + 1)/2 minus the array's sum.

11 · revise

The whole chapter on one screen

9 cards, about a minute. Read them the night before an interview, or right after the chapter to lock it in.

  1. what it is

    Interview number theory is five tools — gcd, the sieve, % M, fast power, nCr — plus digit peeling with % 10 and / 10.

  2. template

    Euclid: while (b != 0) { int r = a % b; a = b; b = r; } return a; — O(log min(a, b)).

  3. template

    Fast power: if ((e & 1) == 1) r = r * b % m; b = b * b % m; e >>= 1; — O(log e) steps.

  4. use it when

    "Modulo 10⁹+7" → reduce after every + and ×, long for products, divide by multiplying with a^(p−2).

  5. cost

    Sieve up to n: O(n log log n) time, O(n) memory. One number: trial division to √n, O(1) memory.

  6. trap

    (a * b) % M with ints overflows before the %. Write (long) a * b % M.

  7. trap

    Java's % keeps the left operand's sign: -7 % 3 == -1. Use Math.floorMod or ((x % m) + m) % m.

  8. pro tip

    Digit loops: guard rev > MAX / 10 before rev * 10 + d. Test 0, negatives and Integer.MIN_VALUE.

  9. use it when

    Weighted random → prefix sums + binary search for the first prefix[i] ≥ ticket.

12 · recall

Flip, remember, repeat

card 1 / 15
recall

Why is gcd(a, b) = gcd(b, a % b)?

tap or Space to flip ↻

Question 1: Why is gcd(a, b) = gcd(b, a % b)?

13 · check yourself

Quick quiz

  1. What is gcd(1071, 462)?

  2. a and b are ints below 10⁹+7. What's wrong with `return (a * b) % MOD;`?

  3. In Java, what is -7 % 3?

  4. In the sieve, why can prime p start crossing out at p² instead of 2p?

  5. Fast power computes 2^e mod m with e = 10¹⁸. Roughly how many multiplications at most?

  6. What is the inverse of 2 modulo 10⁹+7?

  7. How many trailing zeros does 100! have?