A clear explanation of Pow(x, n) using binary exponentiation to compute powers in logarithmic time.
Problem Restatement
We need to implement pow(x, n).
Given a floating-point number x and an integer n, return x raised to the power n.
The official problem asks us to calculate x raised to n, written as x^n. Example inputs include x = 2.00000, n = 10, which returns 1024.00000, and x = 2.00000, n = -2, which returns 0.25000.
For a negative exponent:
x ** -n = 1 / (x ** n)For example:
2^-2 = 1 / 2^2 = 1 / 4 = 0.25Input and Output
| Item | Meaning |
|---|---|
| Input | A float x and an integer n |
| Output | The value of x raised to the power n |
| Negative exponent | Return the reciprocal of the positive power |
| Goal | Compute efficiently without multiplying x one step at a time |
Function shape:
def myPow(x: float, n: int) -> float:
...First Thought: Multiply Repeatedly
The simplest idea is to multiply x by itself n times.
For example:
x = 2
n = 10We could compute:
2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2This gives:
1024Code for positive n:
result = 1.0
for _ in range(n):
result *= xThis works for small n, but it is too slow when n is large.
LeetCode allows n to be as small as -2^31 and as large as 2^31 - 1, so an O(n) loop is not acceptable for large exponents.
Key Insight
Use binary exponentiation.
Instead of multiplying one copy of x at a time, repeatedly square the base.
For example:
x^10 = x^8 * x^2We can get these powers by squaring:
x
x^2
x^4
x^8The exponent 10 in binary is:
1010That means:
10 = 8 + 2So:
x^10 = x^8 * x^2Binary exponentiation uses the bits of n to decide which powers of x should be multiplied into the answer.
Algorithm
First handle negative exponents.
If n < 0, change the problem from:
x^nto:
1 / x^(-n)Then compute the positive exponent using a loop.
Initialize:
result = 1.0
base = x
exp = abs(n)While exp > 0:
- If
expis odd, multiplyresultbybase. - Square
base. - Divide
expby2using integer division.
At the end, if the original exponent was negative, return 1 / result.
Otherwise, return result.
Walkthrough
Use:
x = 2
n = 10Start:
result = 1
base = 2
exp = 10Since 10 is even, do not multiply result.
Square the base:
base = 4
exp = 5Now 5 is odd, so multiply:
result = 1 * 4 = 4Square again:
base = 16
exp = 22 is even, so do not multiply.
Square again:
base = 256
exp = 11 is odd, so multiply:
result = 4 * 256 = 1024Now:
exp = 0Return:
1024Correctness
The algorithm keeps result as the product of the powers of x selected from the binary representation of the exponent.
At each step, base represents the current power of x.
Initially, base = x, which corresponds to x^1.
After one squaring, base = x^2.
After another squaring, base = x^4.
Then x^8, x^16, and so on.
When the current exponent bit is 1, that power is part of the final answer, so the algorithm multiplies it into result.
When the bit is 0, that power is skipped.
Integer-dividing the exponent by 2 moves to the next binary bit.
Therefore, after all bits have been processed, result equals x^abs(n).
If n was negative, the mathematical definition gives:
x^n = 1 / x^(-n)So returning the reciprocal gives the correct value.
Complexity
| Metric | Value | Why |
|---|---|---|
| Time | `O(log | n |
| Space | O(1) | Only a few variables are used |
Implementation
class Solution:
def myPow(self, x: float, n: int) -> float:
exp = abs(n)
base = x
result = 1.0
while exp > 0:
if exp % 2 == 1:
result *= base
base *= base
exp //= 2
if n < 0:
return 1.0 / result
return resultCode Explanation
We convert the exponent to a non-negative value:
exp = abs(n)In Python, this is safe for very small negative integers because Python integers do not overflow.
We keep the current power in:
base = xThe result starts at 1.0 because multiplying by 1 does not change the answer:
result = 1.0The loop processes the exponent bit by bit:
while exp > 0:If the current exponent is odd, its lowest binary bit is 1, so we include the current base:
if exp % 2 == 1:
result *= baseThen we square the base:
base *= baseThis moves from x, to x^2, to x^4, to x^8.
Then we discard the lowest bit:
exp //= 2Finally, if the original exponent was negative, return the reciprocal:
if n < 0:
return 1.0 / resultOtherwise, return the computed positive power.
Testing
def almost_equal(a, b, eps=1e-9):
return abs(a - b) < eps
def run_tests():
s = Solution()
assert almost_equal(s.myPow(2.0, 10), 1024.0)
assert almost_equal(s.myPow(2.1, 3), 9.261)
assert almost_equal(s.myPow(2.0, -2), 0.25)
assert almost_equal(s.myPow(1.0, -2147483648), 1.0)
assert almost_equal(s.myPow(-2.0, 3), -8.0)
assert almost_equal(s.myPow(-2.0, 4), 16.0)
assert almost_equal(s.myPow(5.0, 0), 1.0)
print("all tests passed")
run_tests()| Test | Expected | Reason |
|---|---|---|
2.0, 10 | 1024.0 | Standard positive exponent |
2.1, 3 | 9.261 | Floating-point base |
2.0, -2 | 0.25 | Negative exponent |
1.0, -2147483648 | 1.0 | Very small exponent |
-2.0, 3 | -8.0 | Negative base with odd exponent |
-2.0, 4 | 16.0 | Negative base with even exponent |
5.0, 0 | 1.0 | Any nonzero base to power zero |