Understand
30-second explanation
Build the interview-ready mental model before comparing implementations.
To compute base^exp mod m without the number exploding, never build base^exp first. Use fast (binary) exponentiation: square the base each step and multiply it into the answer only on the set bits of exp, taking `mod m` after every multiplication. That turns exp multiplications into about log₂(exp). Critical overflow note: in Java, multiplying two numbers each up to m−1 (≈10⁹) overflows a 32-bit int and even a long if m is near 2⁶³, so reduce mod m every step and use long (or 128-bit / BigInteger) when m is large.
Interview contextWhat is testedWhere candidates slipHow to stand outExplore interview contextHide interview context
What's being tested
Whether you avoid computing base^exp directly (which overflows and is O(exp)), reach for binary exponentiation, and reduce mod m at every step to keep operands bounded.
Where candidates slip
Looping exp times (O(exp) — too slow for exp = 10⁹), or multiplying without taking mod each step so the product overflows long.
How to stand out
Explain WHY squaring halves the exponent (each bit of exp doubles the accounted-for power), prove correctness by the binary expansion of exp, and call out the exact overflow boundary in Java (long products must stay below 2⁶³).
Choose
Compare the available approaches
Use constraints and trade-offs to select the route you can defend in an interview.
Interactive decision treeInteractiveChoose the right approachFirst decision previewresult = 1 base %= mexp > 0 ?NoYesExplore the full treeCollapse the tree
Learn & trace
Build each solution step by step
Move from the core idea to a visual trace, implementation, proof, and edge cases.
Approach 1 of 2
Iterative Multiply exp Times (Baseline)
1Hint 1Explore hintHide hint
The definition of base^exp is base multiplied by itself exp times. What's the most direct loop for that?
2Hint 2Explore hintHide hint
Multiply a running product by base, exp times. To control growth, take the result mod m after each multiplication.
3Hint 3Explore hintHide hint
Now look at the loop count: if exp is 10¹⁸, this loop runs 10¹⁸ times — far too slow. That's the cost you need to cut.
A · Core idea
The literal definition says base^exp is base times itself exp times. So keep a running result = 1 and multiply by base on each of exp iterations, reducing mod m every step to keep the number small.
Why the mod-every-step part is already right. Reducing after each multiply uses the core identity (a·b) mod m = ((a mod m)·(b mod m)) mod m. This keeps result below m at all times, so it never overflows regardless of how large exp is. That half of the idea carries straight over to the fast version.
Why this still fails the problem. The loop runs exp times. The constraints allow exp up to 10¹⁸; even at a billion multiplications per second that's over 30 years. An O(exp) algorithm simply cannot finish. The modular reduction fixed the size of the numbers but not the number of operations.
What we actually need. We want the same correct, bounded multiplications, but far fewer of them. The insight is that base^exp can be assembled from a handful of repeated squarings rather than exp individual multiplies — which is exactly what binary exponentiation does, cutting the count to log₂(exp).
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
base = 2, exp = 5, m = 1000i=1
result = 1*2 = 2
232C · Code with teaching comments
Reference implementation previewpublic long modPow(long base, long exp, long m) { long result = 1 % m; base %= m; for (long i = 0; i < exp; i++) { result = (result * base) % m;Explore the full codeHide the full code
D · Why it works and complexityO(exp) timeO(1) spaceOpen the invariant and proofExplore the proofHide the proof
The baseline already nails the numeric problem — reduce mod m every multiply and nothing overflows. Its only flaw is the count of multiplications. Recognising that 'O(exp) is the bottleneck, not overflow' points directly at logarithmic exponentiation as the fix.
ComplexityO(exp) time, O(1) space — The loop body runs exp times, each doing one constant-time modular multiply, so O(exp). Only a couple of scalars are kept, so O(1) space.
E · Edge cases and pitfalls3Using this when exp is large — O(exp) is far too slow.Explore edge casesHide edge cases
Pitfalls
- Using this when exp is large — O(exp) is far too slow.
- Building base^exp first and then taking mod — the intermediate has billions of digits and overflows.
- Forgetting result = 1 % m so m = 1 wrongly returns 1 instead of 0.
Approach 2 of 2 · Optimal
Binary (Fast) Exponentiation (Optimal)
1Hint 1Explore hintHide hint
base^exp where exp is huge: can you express base^exp using base^(exp/2)? Note base^exp = (base^(exp/2))² when exp is even.
2Hint 2Explore hintHide hint
Write exp in binary. base^13 = base^8 · base^4 · base^1, because 13 = 1101₂. So you only need the squared powers base^(2^k) and a way to pick which ones to multiply in.
3Hint 3Explore hintHide hint
Iterate: keep squaring base to get base^1, base^2, base^4, base^8, …; whenever the current low bit of exp is 1, multiply that squared power into the result. Reduce mod m after every multiply.
A · Core idea
Write the exponent in binary. If exp = b_k…b_1 b_0 in binary, then exp = Σ b_i · 2^i over the set bits, and therefore base^exp = ∏ base^(2^i) over the i where b_i = 1. We never need base^exp itself — only the squared powers base^(2^0), base^(2^1), … and a rule for which to combine.
The square-and-multiply mechanic. Maintain result = 1 and a running b that starts at base. Each iteration: if the lowest bit of exp is 1, fold the current b into the result; then square b (so it advances from base^(2^i) to base^(2^(i+1))); then shift exp right by one bit. After log₂(exp) iterations every bit has been consumed and result holds the product of exactly the squared powers selected by the set bits.
Why this is correct — the binary expansion. Because exp = Σ_{b_i=1} 2^i, exponent laws give base^exp = base^(Σ 2^i) = ∏_{b_i=1} base^(2^i). The loop produces base^(2^i) in b at exactly iteration i (one squaring per step), and multiplies it into result precisely when bit i is set. So result ends as that exact product — no more, no less. The mod-every-step reduction is justified by (a·b) mod m = ((a mod m)(b mod m)) mod m, which lets us reduce freely without changing the final remainder.
Why it halves the exponent. Each iteration does exp >>= 1, literally dividing the remaining exponent by two (dropping the consumed bit). Starting from exp, you reach 0 after ⌊log₂ exp⌋ + 1 halvings — that's why exp = 10¹⁸ needs only about 60 iterations instead of 10¹⁸.
Overflow, precisely. Both result and b are kept below m by reducing after every multiply. The danger is the multiplication itself: result * b with both up to m−1 produces up to (m−1)² . For m ≤ ~3×10⁹ that product is below 9×10¹⁸ < 2⁶³, so a Java long holds it. If m can be larger (close to 2⁶³), even the long product overflows — then use Math.multiplyHigh / 128-bit multiplication, or BigInteger.modPow. Python integers are unbounded, so the language removes the overflow worry entirely (at some speed cost).
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
base = 3, exp = 13, m = 1000 (13 = 1101₂)Array state
bit 0 = 1
multiply b=3 in; result=3
323 (3^13 = 1594323, and 1594323 mod 1000 = 323)C · Code with teaching comments
D · Why it works and complexityO(log exp) timeO(1) spaceOpen the invariant and proofExplore the proofHide the proof
Fast exponentiation is doubling in disguise: squaring the base doubles the exponent it represents, so the binary digits of exp tell you exactly which doublings to keep. The identical 'combine on set bits, square each step' template works for any associative operation — multiply matrices instead of numbers and you get Fibonacci / linear recurrences in O(log n).
ComplexityO(log exp) time, O(1) space — Each iteration strips one bit of exp (exp >>= 1), so the loop runs ⌊log₂ exp⌋ + 1 times. Each iteration does at most two modular multiplications, both O(1). Hence O(log exp) time and O(1) space.
E · Edge cases and pitfalls7exp = 0 — while loop never runs; result stays 1 (or 0 when m = 1) → base^0 = 1.Explore edge casesHide edge cases
Edge cases handled
exp = 0while loop never runs; result stays 1 (or 0 when m = 1) → base^0 = 1.base = 0, exp = 5, m = 7base %= m = 0; result becomes 0 on the first set bit → 0.m = 1Early return 0 — every value is congruent to 0 mod 1.
Pitfalls
- Not reducing base %= m before the loop — the first square can be needlessly large.
- Forgetting the mod after squaring base — base grows and the next product overflows.
- Assuming a Java long is always safe — (m−1)² overflows long when m is near 2⁶³; use 128-bit or BigInteger.
- Using exp / 2 with a signed shift bug, or `exp >> 1` on a negative — exp is non-negative here, but guard if it could be.
Practice
Try the solution yourself
Edit the optimal implementation, test another input, and observe the result.
Editable code previewpublic long modPow(long base, long exp, long m) { if (m == 1) return 0; long result = 1; base %= m; while (exp > 0) {Explore the playgroundClose the playground
Avoid mistakes
Recognize the interview traps
Understand why common attempts fail before reviewing the corrected implementation.
1Building the full power before reducing
base^exp can have billions of digits; in Java it overflows long instantly, and even in Python it's astronomically slow. Reduce mod m at every multiplication instead.
Explore the code comparisonHide the code comparison
Building the full power before reducing
base^exp can have billions of digits; in Java it overflows long instantly, and even in Python it's astronomically slow. Reduce mod m at every multiplication instead.
Don't write this
long power = 1;
for (long i = 0; i < exp; i++) power *= base; // overflows
return power % m;Write this instead
long result = 1;
base %= m;
while (exp > 0) {
if ((exp & 1) == 1) result = (result * base) % m;
base = (base * base) % m;
exp >>= 1;
}
return result;2Forgetting to reduce after squaring
If base isn't reduced after base = base*base, it can exceed m and the next product (m'·m') blows past 2⁶³, overflowing the long silently.
Explore the code comparisonHide the code comparison
Forgetting to reduce after squaring
If base isn't reduced after base = base*base, it can exceed m and the next product (m'·m') blows past 2⁶³, overflowing the long silently.
Don't write this
base = base * base; // not reduced — grows unbounded
result = (result * base) % m;Write this instead
base = (base * base) % m; // reduced every step
result = (result * base) % m;3Ignoring overflow when m is large
Two operands below m multiply to nearly m². If m ≈ 2⁶³ that product overflows even a long. Use 128-bit multiplication or BigInteger when m can be that big.
Explore the code comparisonHide the code comparison
Ignoring overflow when m is large
Two operands below m multiply to nearly m². If m ≈ 2⁶³ that product overflows even a long. Use 128-bit multiplication or BigInteger when m can be that big.
Don't write this
result = (result * base) % m; // (m-1)^2 overflows long for huge mWrite this instead
result = BigInteger.valueOf(result)
.multiply(BigInteger.valueOf(base))
.mod(BigInteger.valueOf(m)).longValue();Revise
Carry the pattern into the interview
Pattern to remember
Square-and-multiply over the bits of the exponent
Code pattern to memorize
result = 1
base %= m
while exp > 0:
if exp & 1: result = (result * base) % m
base = (base * base) % m
exp >>= 1
return resultRules to remember
- 1Reduce
base %= mbefore the loop and take% mafter every multiply — keep all operands below m so products stay bounded. - 2Halve the exponent each step (
exp >>= 1) and square the base — the exponent shrinks from exp to ~log₂(exp) iterations. - 3Multiply base into result only when the current bit is 1 (
exp & 1). The bits of exp select which squared powers to combine. - 4In Java, two longs up to ~10⁹ multiply safely (product < 10¹⁸ < 2⁶³), but if m can exceed ~3×10⁹ use
Math.multiplyHigh, 128-bit, orBigIntegerto avoid overflow. - 5Handle exp = 0 → return
1 % m(not 1; if m = 1 the answer is 0), and reduce a possibly-zero or negative base correctly first.
Use this pattern when
- Compute base^exp mod m where exp is huge (10⁹, 10¹⁸, or bigger)
- Modular inverse via Fermat: a^(m−2) mod m for prime m
- Hashing, RSA-style crypto, combinatorics with a fixed modulus (nCr mod p)
- Any recurrence you can express as a matrix power → matrix fast exponentiation
Choose another pattern when
- exp is tiny (≤ 30 or so) → a plain loop is fine and clearer
- No modulus and the result fits in 64 bits → just compute it directly
- You need the exact (non-modular) huge power → use BigInteger.pow, not modular reduction
- m is not prime but you need an inverse → Fermat fails; use extended Euclid instead
Interview takeaway
Fast exponentiation is the 'logarithmic doubling' idea applied to multiplication: write exp in binary, and each bit either contributes the current squared power or skips it. Squaring doubles the exponent you've accounted for, so you reach exp in log₂(exp) steps. The same square-and-combine skeleton generalises to matrix powers for linear recurrences like Fibonacci in O(log n).
Continue
Transfer the pattern to another problem
Use a direct variation or pattern sibling to prove the idea is reusable.
Transferable patternCanonical Square-and-Multiply. Whenever you raise something to a large power under an associative operation — integers mod m, matrices, polynomials — express the exponent in binary and combine the repeated squarings. The skeleton is identical; only the 'multiply' changes.
Practice queueDirect variations and pattern siblings
Direct follow-ups
- Pow(x, n)Coming soonSame binary exponentiation on a real base; handle negative n by inverting and the INT_MIN edge.
- Super PowComing soonExponent given as a digit array; combine per-digit fast exponentiation with a fixed modulus.
- Modular Inverse via FermatComing soonFor prime m, a⁻¹ ≡ a^(m−2) mod m — one modular exponentiation.
- Matrix Fast ExponentiationComing soonReplace scalar multiply with matrix multiply to compute linear recurrences (Fibonacci) in O(log n).