Back to problems
#231Easy·math·6 min read

Power of N

This problem asks us to implement the `pow(x, n)` function, which calculates `x` raised to the power `n`. While it sounds simple, the challenge lies in doing it efficiently for very large values of `n`.

mathbit-manipulation
Share

The intuition behind "halving" is all about reusing work.

Instead of asking, "What is 2 times itself 10 times?" we ask, "What is 252^5?" and then just multiply that result by itself.

The "Folding" Intuition

Imagine you have a long piece of string. If you want to measure 1024 inches, you could lay it out inch by inch (Brute Force). Or, you could take 1 inch, fold it in half 10 times. Each fold doubles the previous length.

In code, we do the opposite: we "unfold" the exponent by halving it until we get down to the simplest case (n=0n=0 or n=1n=1).

Here is the step-by-step breakdown of how to solve this in JavaScript.


This problem asks us to implement the pow(x, n) function, which calculates xx raised to the power nn. While it sounds simple, the challenge lies in doing it efficiently for very large values of nn.

Here is the step-by-step breakdown of how to solve this in JavaScript.


This problem asks us to implement the pow(x, n) function, which calculates xx raised to the power nn. While it sounds simple, the challenge lies in doing it efficiently for very large values of nn.

Here is the step-by-step breakdown of how to solve this in JavaScript.


1. The Goal and the Obstacle

If we want to calculate 2102^{10}, the "brute force" way is to multiply 2 by itself 10 times: 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 = 1024

This works for small numbers. But what if nn is 2,147,483,647? A loop running 2 billion times would be extremely slow and cause a "Time Limit Exceeded" error. We need a faster way.

2. The Shortcut: Binary Exponentiation

We can use a strategy called Binary Exponentiation (or "Fast Powering"). The idea is to use the properties of exponents to cut our work in half at every step.

The Logic:

  • If nn is even: xn=(x2)n/2x^n = (x^2)^{n/2}
    • Example: 2102^{10} is the same as (2×2)5(2 \times 2)^5, which is 454^5. We just turned 10 multiplications into 5.
  • If nn is odd: xn=x×xn1x^n = x \times x^{n-1}
    • Example: 2112^{11} is the same as 2×2102 \times 2^{10}. Now that the remaining exponent is even, we can go back to the "even" rule.

By doubling the base and halving the exponent, we reach the answer in O(logn)O(\log n) steps instead of O(n)O(n) steps. For n=1,000,000n = 1,000,000, this takes about 20 steps instead of a million!


3. Handling Negative Powers

The problem states nn can be negative. In math, xnx^{-n} is equal to 1xn\frac{1}{x^n}. To handle this:

  1. If nn is negative, we change our base xx to be 1/x1/x.
  2. We change nn to be positive.
  3. Then we proceed with the calculation normally.

4. Step-by-Step Code Implementation

Here is the recursive approach in JavaScript:

/**
 * @param {number} x
 * @param {number} n
 * @return {number}
 */
var myPow = function(x, n) {
    // Helper function to handle the recursion
    function functionPower(base, exponent) {
        // Step 1: Base Case
        // Anything to the power of 0 is 1
        if (exponent === 0) return 1;
 
        // Step 2: Recursive Step
        // We calculate the result of the halved exponent
        // Math.floor is used because if n is odd (e.g., 5), 5/2 = 2.5
        let half = functionPower(base, Math.floor(exponent / 2));
 
        // Step 3: Combine the results
        if (exponent % 2 === 0) {
            // If even: (x ^ n/2) * (x ^ n/2)
            return half * half;
        } else {
            // If odd: x * (x ^ n/2) * (x ^ n/2)
            return base * half * half;
        }
    }
 
    // Handle Negative Exponents
    if (n < 0) {
        x = 1 / x;
        n = -n;
    }
 
    return functionPower(x, n);
};

5. Detailed Explanation of the Code

The Base Case

if (exponent === 0) return 1;

Every recursive function needs an "exit." Since any number to the power of 0 is 1, we stop there.

The "Halving" Magic

let half = functionPower(base, Math.floor(exponent / 2));

Instead of calculating half * half inside the return statement twice (which would defeat the purpose), we calculate it once and store it. This is why the algorithm is so fast.

Odd vs. Even Logic

  • Even (n=10n=10): We calculated 252^5 as half. The result is just 25×252^5 \times 2^5.
  • Odd (n=11n=11): Math.floor(11 / 2) gives us 5. We calculate 252^5 as half. But 25×252^5 \times 2^5 only gives us 2102^{10}. We need one more 2 to make it 2112^{11}. So we return base * half * half.

6. Complexity Analysis

  • Time Complexity: O(logn)O(\log n). Because we divide nn by 2 in every step, the number of steps is the logarithm of nn.
  • Space Complexity: O(logn)O(\log n). This is the amount of space used on the "recursion stack" (the memory the computer uses to keep track of the function calls).

Summary for your understanding:

  1. Divide and Conquer: We don't multiply one by one; we square the base and cut the exponent in half.
  2. Recursion: We break the big problem into a smaller version of itself.
  3. Edge Cases: We handle n=0n=0 and negative nn before starting the main logic.

Tracing the Logic: 2102^{10}

Here is exactly what happens inside the computer's memory when you call myPow(2, 10). Notice how the "half" variable stores the result so we don't have to calculate it twice.

  1. Level 1: myPow(2, 10)
    • nn is even.
    • It asks: "What is myPow(2, 5)?" 2. Level 2: myPow(2, 5)
    • nn is odd.
    • It asks: "What is myPow(2, 2)?" (using Math.floor(5/2))
  2. Level 3: myPow(2, 2)
    • nn is even.
    • It asks: "What is myPow(2, 1)?"
  3. Level 4: myPow(2, 1)
    • nn is odd.
    • It asks: "What is myPow(2, 0)?"
  4. Level 5 (Base Case): myPow(2, 0)
    • Returns 1.

How the results "Bubble Up"

Now, the functions start returning their values back up the chain. This is where the half * half logic kicks in:

  • From Level 4: Received 1 from below. Since n=1n=1 (odd), return 2×1×1=22 \times 1 \times 1 = \mathbf{2}.
  • From Level 3: Received 2 from below. This is our half. Since n=2n=2 (even), return 2×2=42 \times 2 = \mathbf{4}.
  • From Level 2: Received 4 from below. This is our half. Since n=5n=5 (odd), return 2×4×4=322 \times 4 \times 4 = \mathbf{32}.
  • From Level 1: Received 32 from below. This is our half. Since n=10n=10 (even), return 32×32=102432 \times 32 = \mathbf{1024}.

Result: 1024

Why the variable let half = ... is critical

Look at Level 1 again. To get 1024, the computer just did 32×3232 \times 32. If we didn't use a variable and wrote return myPow(x, n/2) * myPow(x, n/2), the computer would have to calculate that 3232 all over again on the right side. By storing it in half, we calculate it once and use it twice.


Summary of the "Half" Shortcut

FeatureBrute Force (x×x×x...x \times x \times x...)Halving (Binary Exponentiation)
StrategyAddition of stepsMultiplication of steps
Effortnn operationslog(n)\log(n) operations
2102^{10}10 steps4-5 steps
21,000,0002^{1,000,000}1,000,000 steps~20 steps

Does the way the values "bubble back up" and multiply make sense, or would you like to see how we handle a negative exponent like 232^{-3}?

You might also like