50. Pow(x, n)
Problem Description
You need to implement a function that calculates x
raised to the power n
(written as x^n
). This is the mathematical operation of exponentiation where you multiply x
by itself n
times.
For example:
pow(2, 10)
should return1024
(2 multiplied by itself 10 times)pow(2.1, 3)
should return9.261
(2.1 × 2.1 × 2.1)pow(2, -2)
should return0.25
(which is 1/(2×2) = 1/4)
The function should handle:
- Any floating-point number
x
as the base - Any integer
n
as the exponent (including negative numbers and zero) - When
n
is negative, the result should be1/x^|n|
- When
n
is zero, the result should be1
(any number to the power of 0 equals 1)
The solution uses a fast powering technique (also called binary exponentiation) to efficiently compute the result. Instead of multiplying x
by itself n
times which would take O(n) time, this algorithm works by breaking down the exponent into its binary representation and uses the property that x^(a+b) = x^a × x^b
.
The algorithm repeatedly:
- Checks if the current bit of
n
is 1 (usingn & 1
) - If yes, multiplies the answer by the current power of
x
- Squares the current power of
x
(since each bit position represents a power of 2) - Shifts
n
right by 1 bit to process the next bit
This reduces the time complexity from O(n) to O(log n), making it much more efficient for large exponents.
Intuition
The naive approach to calculate x^n
would be to multiply x
by itself n
times. But when n
is very large like 1000000, this becomes extremely inefficient.
The key insight comes from observing how we can break down powers using the properties of exponents. Consider calculating x^10
:
- Instead of doing
x × x × x × x × x × x × x × x × x × x
(10 multiplications) - We notice that
x^10 = x^8 × x^2 = (x^4)^2 × x^2
This leads us to think about the binary representation of the exponent. The number 10 in binary is 1010
, which means:
10 = 8 + 2 = 2^3 + 2^1
- Therefore,
x^10 = x^(8+2) = x^8 × x^2
We can compute these powers of 2 efficiently by repeatedly squaring:
x^1 = x
x^2 = x × x
(square once)x^4 = x^2 × x^2
(square again)x^8 = x^4 × x^4
(square again)
So instead of 10 multiplications, we only need:
- 3 squaring operations to get
x^2
,x^4
,x^8
- 1 multiplication to combine
x^8 × x^2
This pattern works for any exponent. We can always express n
as a sum of powers of 2 (its binary representation), compute those specific powers by repeated squaring, and multiply together only the ones we need.
The algorithm naturally falls out from this observation: we examine each bit of n
from right to left, maintaining the current power of x
(which doubles each time), and accumulate the result whenever we encounter a 1
bit.
For negative exponents, we use the mathematical property that x^(-n) = 1/(x^n)
, so we compute the positive power first and then take its reciprocal.
Solution Approach
The solution implements the fast powering (binary exponentiation) algorithm to efficiently compute x^n
in O(log n) time.
The implementation consists of two parts:
-
Main function
myPow
: Handles the sign of the exponent- If
n >= 0
, directly calls the helper functionqpow(x, n)
- If
n < 0
, computes1 / qpow(x, -n)
to handle negative powers
- If
-
Helper function
qpow
: Performs the actual fast powering calculationThe algorithm works as follows:
- Initialize
ans = 1
to store the result - While
n
is not zero:- Check if the least significant bit of
n
is 1 usingn & 1
- If yes, multiply
ans
by the current value ofa
:ans *= a
- This corresponds to including this power of 2 in our result
- If yes, multiply
- Square
a
by doinga *= a
- This prepares the next power of 2 (e.g., from
x^2
tox^4
)
- This prepares the next power of 2 (e.g., from
- Right shift
n
by 1 bit usingn >>= 1
- This moves to the next bit in the binary representation
- Check if the least significant bit of
- Return the accumulated result
ans
- Initialize
Example walkthrough for x = 2, n = 10
(binary: 1010):
- Initially:
ans = 1
,a = 2
,n = 10 (1010)
- Iteration 1:
n & 1 = 0
, skip multiplication,a = 4
,n = 5 (101)
- Iteration 2:
n & 1 = 1
,ans = 1 × 4 = 4
,a = 16
,n = 2 (10)
- Iteration 3:
n & 1 = 0
, skip multiplication,a = 256
,n = 1 (1)
- Iteration 4:
n & 1 = 1
,ans = 4 × 256 = 1024
,a = 65536
,n = 0
- Result:
1024
The algorithm efficiently computes the result by only multiplying together the necessary powers of x
based on the binary representation of n
, achieving logarithmic time complexity instead of linear.
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through calculating pow(3, 5)
using the binary exponentiation approach.
Setup:
- We want to compute
3^5
- The number 5 in binary is
101
, which means5 = 4 + 1 = 2^2 + 2^0
- Therefore,
3^5 = 3^4 × 3^1
Step-by-step execution:
Initial state:
ans = 1
(accumulator for result)a = 3
(current power of x)n = 5
(binary:101
)
Iteration 1:
- Check rightmost bit:
5 & 1 = 1
(bit is 1) - Multiply answer:
ans = 1 × 3 = 3
- Square the base:
a = 3 × 3 = 9
(now represents3^2
) - Shift right:
n = 5 >> 1 = 2
(binary:10
)
Iteration 2:
- Check rightmost bit:
2 & 1 = 0
(bit is 0) - Skip multiplication (don't need
3^2
in final result) - Square the base:
a = 9 × 9 = 81
(now represents3^4
) - Shift right:
n = 2 >> 1 = 1
(binary:1
)
Iteration 3:
- Check rightmost bit:
1 & 1 = 1
(bit is 1) - Multiply answer:
ans = 3 × 81 = 243
- Square the base:
a = 81 × 81 = 6561
(now represents3^8
) - Shift right:
n = 1 >> 1 = 0
Loop ends (n = 0)
Result: ans = 243
We can verify: 3^5 = 3 × 3 × 3 × 3 × 3 = 243
✓
Notice how we only needed 3 iterations (log₂(5) rounded up) instead of 5 multiplications. The algorithm selected exactly the powers we needed (3^1
and 3^4
) based on the binary representation of 5.
Solution Implementation
1class Solution:
2 def myPow(self, x: float, n: int) -> float:
3 """
4 Calculate x raised to the power n (x^n).
5 Uses binary exponentiation for O(log n) time complexity.
6
7 Args:
8 x: The base number
9 n: The exponent (can be negative)
10
11 Returns:
12 The result of x^n
13 """
14
15 def quick_power(base: float, exponent: int) -> float:
16 """
17 Helper function to calculate base^exponent using binary exponentiation.
18 Only handles non-negative exponents.
19
20 Args:
21 base: The base number
22 exponent: Non-negative exponent
23
24 Returns:
25 The result of base^exponent
26 """
27 result = 1.0
28
29 # Process each bit of the exponent
30 while exponent > 0:
31 # If current bit is 1, multiply result by current base
32 if exponent & 1: # Check if least significant bit is 1
33 result *= base
34
35 # Square the base for the next bit position
36 base *= base
37
38 # Right shift to process the next bit
39 exponent >>= 1
40
41 return result
42
43 # Handle negative exponents by computing 1 / (x^(-n))
44 if n >= 0:
45 return quick_power(x, n)
46 else:
47 return 1.0 / quick_power(x, -n)
48
1class Solution {
2 /**
3 * Calculates x raised to the power n (x^n)
4 * @param x the base number
5 * @param n the exponent (can be negative)
6 * @return the result of x^n
7 */
8 public double myPow(double x, int n) {
9 // Handle positive and negative exponents separately
10 // For negative n, calculate x^(-n) and return its reciprocal
11 // Cast n to long to handle Integer.MIN_VALUE overflow when negating
12 return n >= 0 ? quickPower(x, n) : 1.0 / quickPower(x, -(long) n);
13 }
14
15 /**
16 * Fast exponentiation using binary exponentiation algorithm
17 * Time complexity: O(log n)
18 * @param base the base number to be raised to a power
19 * @param exponent the non-negative exponent
20 * @return the result of base^exponent
21 */
22 private double quickPower(double base, long exponent) {
23 double result = 1.0;
24
25 // Binary exponentiation: process exponent bit by bit
26 while (exponent > 0) {
27 // If current bit is 1, multiply result by current base
28 if ((exponent & 1) == 1) {
29 result = result * base;
30 }
31 // Square the base for the next bit position
32 base = base * base;
33 // Right shift to process the next bit
34 exponent >>= 1;
35 }
36
37 return result;
38 }
39}
40
1class Solution {
2public:
3 double myPow(double x, int n) {
4 // Lambda function for fast exponentiation using binary exponentiation
5 auto fastPower = [](double base, long long exponent) {
6 double result = 1.0;
7
8 // Iterate while exponent is not zero
9 while (exponent > 0) {
10 // If current bit is 1, multiply result by current base
11 if (exponent & 1) {
12 result *= base;
13 }
14 // Square the base for next bit position
15 base *= base;
16 // Right shift to process next bit
17 exponent >>= 1;
18 }
19
20 return result;
21 };
22
23 // Handle positive and negative exponents
24 // For negative exponent, calculate reciprocal of positive power
25 // Cast n to long long to handle INT_MIN overflow case
26 return n >= 0 ? fastPower(x, n) : 1.0 / fastPower(x, -(long long)n);
27 }
28};
29
1/**
2 * Calculates x raised to the power n (x^n) using binary exponentiation
3 * @param x - The base number
4 * @param n - The exponent (can be positive, negative, or zero)
5 * @returns The result of x^n
6 */
7function myPow(x: number, n: number): number {
8 /**
9 * Helper function that performs fast exponentiation using binary representation
10 * Uses the property: x^n = (x^2)^(n/2) when n is even, x * x^(n-1) when n is odd
11 * @param base - The base number to be raised to a power
12 * @param exponent - The positive exponent
13 * @returns The result of base^exponent
14 */
15 const quickPower = (base: number, exponent: number): number => {
16 let result = 1;
17
18 // Process each bit of the exponent from right to left
19 while (exponent > 0) {
20 // If the current bit is 1, multiply result by current base
21 if (exponent & 1) {
22 result *= base;
23 }
24 // Square the base for the next bit position
25 base *= base;
26 // Right shift to process the next bit
27 exponent >>>= 1;
28 }
29
30 return result;
31 };
32
33 // Handle negative exponents by calculating 1 / (x^|n|)
34 return n >= 0 ? quickPower(x, n) : 1 / quickPower(x, -n);
35}
36
Time and Space Complexity
The time complexity is O(log n)
, where n
is the absolute value of the exponent. This is achieved through the binary exponentiation algorithm (also known as exponentiation by squaring). The while loop iterates through each bit of n
, and since n
is right-shifted by 1 position in each iteration (n >>= 1
), the loop runs approximately log₂(n)
times.
The space complexity is O(1)
as the algorithm only uses a constant amount of extra space. The variables ans
and a
are the only additional storage used, regardless of the input size. The helper function qpow
is called at most once (not recursively), so there's no additional stack space consumption beyond the initial function call.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Integer Overflow with Minimum Integer Value
The Pitfall:
When handling negative exponents, the code uses -n
to convert a negative exponent to positive. However, in many programming languages, the minimum integer value (e.g., -2^31
in 32-bit systems) cannot be negated because its absolute value exceeds the maximum positive integer value (2^31 - 1
). This causes integer overflow.
For example, if n = -2147483648
(minimum 32-bit integer), then -n
would theoretically be 2147483648
, which exceeds the maximum 32-bit integer 2147483647
.
Solution:
Convert n
to a long integer type before negation to avoid overflow:
def myPow(self, x: float, n: int) -> float:
def quick_power(base: float, exponent: int) -> float:
result = 1.0
while exponent > 0:
if exponent & 1:
result *= base
base *= base
exponent >>= 1
return result
# Convert to long to handle minimum integer value
long_n = n
if long_n >= 0:
return quick_power(x, long_n)
else:
return 1.0 / quick_power(x, -long_n)
2. Special Edge Cases Not Handled
The Pitfall: The basic implementation doesn't explicitly handle certain edge cases that might cause issues:
x = 0
with negative exponent (division by zero)x = 1
orx = -1
with very large exponents (can be optimized)x = 0
withn = 0
(mathematically undefined but often treated as 1)
Solution: Add explicit checks for these special cases:
def myPow(self, x: float, n: int) -> float:
# Handle special cases
if x == 0:
if n < 0:
# 0^negative is undefined (division by zero)
raise ValueError("Cannot raise 0 to a negative power")
return 0 if n > 0 else 1 # 0^0 is typically defined as 1
if x == 1:
return 1
if x == -1:
return -1 if n % 2 == 1 else 1
# Continue with regular algorithm...
def quick_power(base: float, exponent: int) -> float:
result = 1.0
while exponent > 0:
if exponent & 1:
result *= base
base *= base
exponent >>= 1
return result
long_n = n
if long_n >= 0:
return quick_power(x, long_n)
else:
return 1.0 / quick_power(x, -long_n)
3. Floating-Point Precision Issues
The Pitfall: When dealing with very large exponents or very small/large base values, floating-point arithmetic can lead to precision loss or overflow/underflow. Repeated multiplication can accumulate rounding errors.
Solution: While complete precision cannot be guaranteed with floating-point arithmetic, you can add checks for potential overflow/underflow:
def myPow(self, x: float, n: int) -> float:
import sys
def quick_power(base: float, exponent: int) -> float:
result = 1.0
while exponent > 0:
if exponent & 1:
result *= base
# Check for overflow/underflow
if result == float('inf') or result == float('-inf'):
return result
if abs(result) < sys.float_info.min and result != 0:
return 0.0 # Underflow to zero
base *= base
# Check base for overflow
if base == float('inf'):
return float('inf') if exponent & 1 else result
exponent >>= 1
return result
# Rest of the implementation...
These solutions ensure the algorithm handles edge cases correctly and provides more robust behavior in production environments.
Which data structure is used to implement priority queue?
Recommended Readings
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Want a Structured Path to Master System Design Too? Don’t Miss This!