DSA sheet · Recursion · Linear recursion pattern

Pow(x, n)

This is the last question of the linear recursion pattern. We must compute x raised to the power n, where n can be negative and can be as big as about two billion. The teacher first shows the obvious way (multiply x again and again, n times), then shows the trick that makes it fast: to get x¹⁰, get x⁵ once and multiply it by itself. That halving idea turns O(n) into O(log n). She writes it first as a while loop and then converts the loop into a recursive function.

Why it matters: this is the classic example that recursion does not always mean "slow" or "2ⁿ". A recursion that makes one call per step and halves its input each time has only log n levels.

Every part below follows the same order:
① the question in simple words → ② what the constraints tell us → ③ intuition → ④ building the logic from examples → ⑤ approach steps → ⑥ code → ⑦ code line by line → ⑧ dry run (recursion tree + call stack) → ⑨ complexity & remember

Part 0 · Recursion from scratch

1. A function that calls itself

Recursion means a function solves a problem by calling itself on a smaller version of the same problem. For powers this is very natural:

2. The base case: where it must stop

The base case is the smallest input whose answer we know directly, without another call. For powers it is n = 0: anything to the power 0 is 1.

Doubt: what happens if I forget the base case?
→ The function keeps calling itself forever: power(2, 0) would call power(2, −1), then power(2, −2)… Each call takes a little memory. Python stops it after about 1000 nested calls with a RecursionError: maximum recursion depth exceeded. So the base case is not optional. It is the only thing that stops recursion.

3. The recursive case: make the problem smaller

The recursive case is the line that calls the function again with a smaller input, and then uses that answer. Every call must move closer to the base case (here: n must shrink towards 0), otherwise we never reach it.

4. Trust the smaller call ("leap of faith")

When you write half = power(x, n // 2), don't try to trace the whole chain in your head. Just assume it correctly returns xn//2, and ask only: "Given that answer, how do I build xn?" If the base case is right and each step is right, the whole thing is right. This trust is called the leap of faith.

5. The call stack: push on call, pop on return

Python keeps a call stack: a pile of the calls that have started but not finished.

The number of calls stacked up at the deepest moment is the depth of the recursion. That depth is the extra memory (space) the recursion uses.

6. Work on the way down vs work on the way back up

The teacher refers to two styles from her earlier video. You will see both on this page:

Functional recursionParameterized recursion
where the answer is builton the way back up: each call takes the answer returned by the smaller call and combines iton the way down: the partial answer is passed along as an extra parameter
what the base case returnsthe answer for the smallest input (here 1)the finished answer carried in the parameter (here ans)
on this pagePart A (naive) and Part BPart D

7. Two facts about powers we need


Part A · Brute force: multiply x, n times

LeetCode 50 · Pow(x, n)

1The question in simple words

Given a decimal number x and a whole number n, return xn as a decimal number (a float in Python).

xnanswerwhy
2.0101024.02 × 2 × … ten times. (2² = 4, 2³ = 8, …, 2¹⁰ = 1024)
2.139.2612.1 × 2.1 × 2.1
2.0−20.25the minus sign sends 2 to the bottom: 1/2² = (0.5)² = 0.25

Because x is a decimal, the answer must also be a decimal. The teacher keeps the answer in a double variable. In Python we start with 1.0, so everything stays a float.

2What the constraints tell us

Doubt: why does the teacher store n in a long when it's negative? Do I need that in Python?
→ The smallest n is −2³¹ = −2147483648. Flipping it gives +2147483648 = 2³¹. A 32-bit int in Java/C++ can hold at most 2³¹ − 1, so the flip overflows and becomes negative again. That's why she copies n into a 64-bit variable first. In Python, integers have no size limit, so -n just works. We still copy n into exp to keep her structure, and we test n = −2³¹ to be sure.

3Intuition

The first idea anyone has: power means "multiply x by itself n times". So start with 1 and multiply by x, n times. If n is negative, first flip x to 1/x and make n positive, then do the same.

4Building the logic from the examples

The same as a recursion: xn = x × xn−1, with base case x⁰ = 1. Each call does one multiplication and passes "n − 1" down.

5Approach steps

  1. If n < 0: set x = 1/x and n = −n.
  2. Start ans = 1.0.
  3. Repeat n times: ans = ans * x.
  4. Return ans. (Recursive form: power(x, n) = x × power(x, n − 1), and power(x, 0) = 1.)

6Code (Python)

Brute force loop (too slow for big n)
class Solution:
    def myPow(self, x: float, n: int) -> float:
        if n < 0:                 # negative power: flip the base
            x = 1 / x
            n = -n
        ans = 1.0
        for _ in range(n):        # multiply n times
            ans = ans * x
        return ans
Brute force as naive recursion (n levels deep)
def power_naive(x, n):            # assumes n >= 0
    if n == 0:                    # base case: x^0 = 1
        return 1.0
    return x * power_naive(x, n - 1)   # x^n = x * x^(n-1)

7Code line by line

linewhat it means
if n < 0: x = 1 / x n = -nThe two changes for a negative power: the base goes to the bottom, and the power becomes positive.
ans = 1.01 is "nothing multiplied yet". The .0 keeps it a float.
for _ in range(n): ans = ans * xOne multiplication per unit of power: n steps.
if n == 0: return 1.0(recursive version) The base case. Stops the chain.
return x * power_naive(x, n - 1)Trust the smaller call to give xn−1, then multiply one more x on the way back up.

8Dry run: the naive recursion for 2¹⁰

Each line of the tree is one call: p(n) → returned value. Every call makes exactly one smaller call, so the "tree" is a straight line.

p(10) → 1024
  |
p(9)  → 512
  |
p(8)  → 256
  |
p(7)  → 128
  |
 ...      (one call for every n)
  |
p(1)  → 2
  |
p(0)  → 1     ← base case
                 11 calls, 11 levels deep
  1. p(10) needs p(9), so it pauses. p(9) needs p(8), and so on. Each one is pushed on the stack.
  2. p(0) hits the base case and returns 1. It is popped.
  3. p(1) receives 1 and returns 2 × 1 = 2. Popped.
  4. p(2) returns 2 × 2 = 4, p(3) returns 8, … each return does one multiplication on the way up.
  5. p(10) receives 512 and returns 2 × 512 = 1024 ✓.
deepest moment (11 calls waiting)
p(10)p(9)…p(1)p(0) → 1
on the way up
p(10)p(9)…p(3) → 8

9Complexity & remember

Remember the brute forceNegative n → x = 1/x, n = −n. Then multiply n times. Correct, but O(n): too slow for n ≈ 2 × 10⁹.

Part B · Fast power by halving (recursive)

1The question

The same question: return xn. But now we want it in far fewer than n steps.

2What the constraints tell us

n up to ~2 × 10⁹ means we need roughly O(log n): log₂(2³¹) is just 31. That's a huge hint to "cut the problem in half at each step".

3Intuition: the teacher's "left half, right half" picture

When we multiply 2 ten times, we're repeating work. Split the ten 2's into two equal groups:

2¹⁰ = (2 × 2 × 2 × 2 × 2) × (2 × 2 × 2 × 2 × 2)
       └──── left half ────┘   └──── right half ───┘
              = 2⁵                     = 2⁵  (the SAME number!)

If we somehow get the left half, 2⁵ = 32, we don't need to compute the right half at all: it's the same 32. One multiplication, 32 × 32, gives 1024. We just saved all the work of the right half.

Now apply the same trick to 2⁵, then to whatever that needs, until the power is 0.

4Building the logic from the example 2¹⁰

The teacher breaks it down step by step:

Now the answers travel back up:

That's just 4 halving steps instead of 10 multiplications in a row.

Doubt 1: why exactly 4 steps for n = 10?
→ Each step halves the power: 10 → 5 → 2 → 1 → 0. The question is "how many times can I halve 10 before reaching 0?". 2¹ = 2, 2² = 4, 2³ = 8, 2⁴ = 16. 10 sits between 8 and 16, so log₂ 10 ≈ 3.3, and it takes 4 halvings. In general it's ⌊log₂ n⌋ + 1 halvings. For n = 64, the loop would do 64 multiplications, but halving takes only 7 steps.
Doubt 2: why "log base 2"?
→ Because we cut the power into 2 parts each time. If we cut into 3 parts each time, it would be log base 3. (In big-O we usually just write O(log n).)
Doubt 3 (why not X): what if I write it as power(x, n//2) * power(x, n//2), i.e. call twice?
→ That brings back the waste the teacher removed. Each call makes two calls, so the tree doubles at every level: 1 + 2 + 4 + … ≈ 2n calls. That's O(n) again! The whole trick is to compute the half once, store it in a variable, and reuse it.

5Approach steps

  1. If n < 0: x = 1/x, n = −n.
  2. power(x, n): if n == 0 return 1.
  3. half = power(x, n // 2), computed once.
  4. If n is even return half × half; if odd return half × half × x.

6Code (Python)

Fast power, functional recursion (answer built on the way up)
class Solution:
    def myPow(self, x: float, n: int) -> float:
        if n < 0:                       # negative power: flip the base
            x = 1 / x
            n = -n                      # Python ints never overflow, even for -2**31
        return self.power(x, n)

    def power(self, x, n):
        if n == 0:                      # base case: x^0 = 1
            return 1.0
        half = self.power(x, n // 2)    # ONE call, for half the power
        if n % 2 == 1:                  # odd: one x is left over
            return half * half * x
        return half * half              # even: two equal halves

7Code line by line

linewhat it means
if n < 0: x = 1 / x; n = -nSame flip as before. After this, n ≥ 0.
if n == 0: return 1.0Base case. Reached after about log₂ n halvings.
half = self.power(x, n // 2)Leap of faith: trust that this returns xn//2. // is whole-number division, so 5 // 2 = 2.
if n % 2 == 1: return half * half * xOdd n: xn = xn//2 × xn//2 × x. (5 = 2 + 2 + 1.)
return half * halfEven n: the left half times the (identical) right half.

8Dry run: why the call tree has only log n levels

Put the two recursion trees for 2¹⁰ side by side. Each node shows call → returned value.

naive: n → n − 1 (Part A)
p(10) → 1024
p(9)  → 512
p(8)  → 256
p(7)  → 128
p(6)  → 64
p(5)  → 32
p(4)  → 16
p(3)  → 8
p(2)  → 4
p(1)  → 2
p(0)  → 1
11 levels
halving: n → n // 2 (Part B)
power(2,10) → 1024   = 32·32
     |
power(2,5)  → 32     = 4·4·2
     |
power(2,2)  → 4      = 2·2
     |
power(2,1)  → 2      = 1·1·2
     |
power(2,0)  → 1      base case

5 levels
  1. power(2,10) pauses and calls power(2,5). stack: [10]
  2. power(2,5) pauses and calls power(2,2). stack: [10, 5]
  3. power(2,2) calls power(2,1). power(2,1) calls power(2,0). stack: [10, 5, 2, 1, 0]: the deepest moment, 5 calls.
  4. power(2,0) returns 1 and is popped.
  5. power(2,1): half = 1, n is odd → 1 × 1 × 2 = 2. Popped.
  6. power(2,2): half = 2, even → 2 × 2 = 4. Popped.
  7. power(2,5): half = 4, odd → 4 × 4 × 2 = 32. Popped.
  8. power(2,10): half = 32, even → 32 × 32 = 1024 ✓. The stack is empty.
step 3 (deepest)
power(2,10)power(2,5)power(2,2)power(2,1)power(2,0) → 1
step 6
power(2,10)power(2,5)power(2,2) → 4
step 8
power(2,10) → 1024

Counting the levels. The naive version subtracts 1, so it needs n + 1 calls to get from n down to 0. The halving version divides by 2, so after k calls the power is about n / 2k. It reaches 0 once 2k > n, i.e. after about log₂ n + 2 calls.

nnaive calls (n + 1)halving calls (⌊log₂ n⌋ + 2)
10115
64658
1 000 0001 000 001 (crashes Python's stack)21
2³¹ ≈ 2.1 × 10⁹~2.1 billion (impossible)33

Both are linear recursion (one call per call, so the tree is a single chain). The difference is only how fast the input shrinks: −1 per level gives n levels, ÷2 per level gives log n levels. 33 levels is far below Python's limit of ~1000, so no setrecursionlimit is needed.

9Complexity & remember

Remember fast powerxn = half × half (× x if n is odd), where half = xn//2 is computed once. Halving the power at each level → log n levels.

Part C · The halving idea as a while loop (teacher's first code)

The teacher first writes the fast idea without recursion, then converts it. The loop goes in the opposite direction from Part B: instead of breaking 2¹⁰ down and building back up, it walks the power down and keeps squaring the base as it goes.

1–2Question & constraints

The same as Part A. The negative-n flip is done the same way at the start.

3Intuition

Keep three things: the answer so far (ans, starts at 1), the current base x, and the power still left (exp). At each step:

Stop when exp reaches 0. Then ans holds the full answer.

Doubt: the teacher says "double x". Is it doubling?
→ She means "double the power that x represents", which in code is squaring: x = x * x. 2 → 4 → 16 → 256. These are 2¹, 2², 2⁴, 2⁸: the exponent doubles while the value is squared. Don't write x * 2.

4Building the logic: why "odd → multiply into ans"

Look at 10 in binary: 1010 = 8 + 2. So 2¹⁰ = 2⁸ × 2². The loop visits the bases 2¹, 2², 2⁴, 2⁸ (squaring each time). The steps where exp is odd are exactly the 1-bits of 10, so ans picks up 2² and 2⁸ and skips 2¹ and 2⁴. 4 × 256 = 1024 ✓. That's why the check is "is exp odd?".

5Approach steps

  1. exp = n. If exp < 0: x = 1/x, exp = −exp.
  2. ans = 1.0.
  3. While exp > 0: if exp is odd, ans *= x. Then x = x·x and exp = exp // 2.
  4. Return ans.

6Code (Python)

Fast power, iterative (teacher's while loop)
class Solution:
    def myPow(self, x: float, n: int) -> float:
        exp = n                      # (Java/C++ need a long here)
        if exp < 0:
            x = 1 / x
            exp = -exp
        ans = 1.0
        while exp > 0:
            if exp % 2 == 1:         # odd: take one copy of x into the answer
                ans = ans * x
            x = x * x                # square the base
            exp = exp // 2           # halve the power
        return ans

7Code line by line

linewhat it means
exp = nA working copy of the power. In Java/C++ it must be a long so that −(−2³¹) fits; in Python any int is fine.
ans = 1.0The answer collected so far.
while exp > 0:Keep going while some power is still owed.
if exp % 2 == 1: ans = ans * xAn odd power leaves one x over. Put it into the answer.
x = x * xThe base now stands for twice as many original x's.
exp = exp // 2So we owe half as many of them. 1 // 2 = 0 ends the loop.

8Dry run: the teacher's table for x = 2, n = 10

roundexp at startodd?ans afterx after squaringexp after
110no145
25yes1 × 4 = 4162
32no42561
41yes4 × 256 = 102465536 (not used)0
exp = 0 → loop ends → return 1024 ✓. Only 4 rounds, not 10.

There's no recursion here, so there's no call stack. The next part turns this exact loop into recursion.

9Complexity & remember

Remember the loopif exp odd: ans *= x → x *= x → exp //= 2, until exp is 0.

Part D · The loop turned into parameterized recursion (teacher's second code)

Now the teacher converts the while loop into a recursive function. The rule she follows: everything that changes in the loop becomes a parameter, and the loop's stop condition becomes the base case.

1–3Question, constraints, intuition

The same question, and the same flip for negative n. The loop changed three things each round: x, exp and ans. So the function takes all three: power(x, n, ans). The first call is power(x, exp, 1.0), because ans started at 1.

4Building it from the loop

while loop (Part C)recursion (Part D)
ans = 1.0 before the looppass 1.0 in the first call
while exp > 0base case: if n == 0: return ans (the opposite condition)
if exp % 2 == 1: ans *= xthe same line, inside the function
x = x * x, exp = exp // 2no manual update: pass the new values as arguments: power(x * x, n // 2, ans)
return ans after the loopthe base case returns it, and every call passes it straight back up
Doubt: why does the base case return ans and not 1, like Part B?
→ This is parameterized recursion: the answer is built on the way down and carried in the ans parameter. By the time n hits 0, the answer is already complete, so the base case simply hands it back. In Part B (functional), the answer is built on the way up, so the base case returns the smallest answer (x⁰ = 1) and the callers multiply it up. The teacher says if this feels confusing, revisit the difference between functional and parameterized recursion (Part 0, point 6).

5Approach steps

  1. Flip for negative n, then return power(x, exp, 1.0).
  2. power: if n == 0 → return ans.
  3. If n is odd → ans = ans × x.
  4. Return power(x × x, n // 2, ans).

6Code (Python)

Fast power, parameterized recursion (teacher's recursive code)
class Solution:
    def myPow(self, x: float, n: int) -> float:
        exp = n
        if exp < 0:
            x = 1 / x
            exp = -exp
        return self.power(x, exp, 1.0)

    def power(self, x, n, ans):
        if n == 0:                   # the loop's stop condition
            return ans               # answer is already complete
        if n % 2 == 1:               # odd: take one x into the answer
            ans = ans * x
        return self.power(x * x, n // 2, ans)   # square base, halve power

7Code line by line

linewhat it means
return self.power(x, exp, 1.0)Start the chain with ans = 1, just like the loop did.
if n == 0: return ansThe loop would stop here. The finished answer goes back.
if n % 2 == 1: ans = ans * xThe same odd check as the loop.
return self.power(x * x, n // 2, ans)"The next round of the loop", done as a call with updated arguments. Its result is returned unchanged, so no work is left for the way back up.

8Dry run: x = 2, n = 10

Recursion tree (a single chain). Each node shows its arguments and what it returns:

power(x=2,     n=10, ans=1)     → 1024
   |  10 even: ans stays 1
power(x=4,     n=5,  ans=1)     → 1024
   |  5 odd: ans = 1·4 = 4
power(x=16,    n=2,  ans=4)     → 1024
   |  2 even: ans stays 4
power(x=256,   n=1,  ans=4)     → 1024
   |  1 odd: ans = 4·256 = 1024
power(x=65536, n=0,  ans=1024)  → 1024   ← base case
  1. Going down. Each call does its small piece of work (maybe multiply into ans), then calls the next one with the squared base and the halved power. Compare with Part C: the arguments are exactly the loop's table, one row per call.
  2. The 5th call has n = 0 → it returns 1024.
  3. Coming back up. Each call just passes the same 1024 to the one below it. No calculation happens on the way up.
  4. myPow returns 1024 ✓.
after 2 calls
power(2,10,1)power(4,5,1)
deepest: 5 calls
power(2,10,1)power(4,5,1)power(16,2,4)power(256,1,4)power(65536,0,1024) → 1024
returning
power(2,10,1)power(4,5,1) → 1024

9Complexity & remember

Remember the conversionLoop → recursion: changing variables become parameters, the loop condition flipped becomes the base case, the variable updates become the arguments of the next call.

Part E · Revision page

A · brute forceB · halving, functionalC · halving loopD · halving, parameterized
ideax · xn−1half · half (· x)odd → ans·=x; x·=x; exp//=2same as C, as calls
input shrinks by−1÷2÷2÷2
calls / rounds for n = 101154 rounds5
answer builton the way upon the way upin the loopon the way down
base case returns11—ans
timeO(n)O(log n)O(log n)O(log n)
spaceO(1) loop / O(n) recursionO(log n)O(1)O(log n)
If you remember only 5 lines 1. Negative n: x = 1/x and n = −n (in Java/C++, use a long for n = −2³¹).
2. xn = (xn/2)², times one extra x when n is odd.
3. Compute the half once. Calling it twice brings back O(n).
4. Halving the power each level → log₂ n levels → O(log n) time.
5. Loop → recursion: variables become parameters, the stop condition becomes the base case.
Mistakes to avoid ✗ forgetting negative n (or flipping n but not x)
✗ overflow on −(−2³¹) in fixed-size ints (not a problem in Python)
✗ x * 2 instead of x * x
✗ power(x, n//2) * power(x, n//2): two calls make it O(n)
✗ in the parameterized version, returning 1 from the base case instead of ans
✗ starting ans at 0 instead of 1
test it yourself (paste under any Solution above)
s = Solution()
print(s.myPow(2.0, 10))         # 1024.0
print(s.myPow(2.1, 3))          # 9.261 (approximately)
print(s.myPow(2.0, -2))         # 0.25
print(s.myPow(5.0, 0))          # 1.0
print(s.myPow(-2.0, 3))         # -8.0
print(s.myPow(1.0, -2**31))     # 1.0  (smallest n, fast)
print(s.myPow(2.0, -2**31))     # 0.0  (far too small for a float)

Based on this video: Pow(x, n) | Linear Recursion