Classical examples
Seven classic problems show the shapes recursion takes: counting down with one call, branching into two, shrinking numbers, and halving. Each has an animation of its calls, so you can see exactly how the answer is assembled.
Learning goals
- Write factorial, Fibonacci, digit sum, reverse, power and GCD recursively
- Explain why naive Fibonacci is exponential and how memoization fixes it
- Use halving to turn O(n) power into O(log n)
- Relate recursive binary search to the iterative one
Prerequisites
Factorial
n! is n × (n - 1)! with 0! = 1. It has one recursive call per level, so n + 1 calls and a stack n + 1 frames deep. You saw its call stack in lesson 5.01.
Watch the range: 12! fits in an int, but 13! does not (6,227,020,800 exceeds 2,147,483,647). A long holds up to 20!. For larger values use BigInteger.
| n | n! | Fits in |
|---|---|---|
| 5 | 120 | int |
| 12 | 479,001,600 | int |
| 13 | 6,227,020,800 | long |
| 20 | 2,432,902,008,176,640,000 | long |
| 21 | 51,090,942,171,709,440,000 | BigInteger only |
Worst
O(n)
Space
O(n) stack
Fibonacci
fib(n) = fib(n - 1) + fib(n - 2) with fib(0) = 0 and fib(1) = 1. The recursion has two calls per level, so the tree branches. Run n = 6 in the first animation and look at the tree: fib(3) is computed three times and fib(2) five times.
The number of calls T(n) satisfies T(n) = T(n - 1) + T(n - 2) + 1, which grows like φⁿ with φ ≈ 1.618. The second animation adds a memo array. Each value is computed once, the tree collapses into a chain with cache hits (dashed green), and the cost drops to O(n).
| n | Calls with plain recursion | Calls with memoization |
|---|---|---|
| 10 | 177 | 19 |
| 20 | 21,891 | 39 |
| 30 | 2,692,537 | 59 |
| 40 | 331,160,281 | 79 |
Fibonacci: naive recursion tree
Interactive · edit the inputRecursion tree · 1 call
Call fib(5).
1static long fib(int n) {2if (n <= 1) return n; // base cases3return fib(n - 1) + fib(n - 2); // two recursive calls4}
Live state
n
5
depth
1
Call stack (top first)
- fib(5)
Execution trace (dry run table)Show 60 stepsHide
| Step | Line | State | What happens |
|---|---|---|---|
| 1 | L1 | n=5 depth=1 | Call fib(5). |
| 2 | L2 | n=5 | Not a base case. |
| 3 | L3 | n=5 | fib(5) = fib(4) + fib(3). Call fib(4) first. |
| 4 | L1 | n=4 depth=2 | Call fib(4). |
| 5 | L2 | n=4 | Not a base case. |
| 6 | L3 | n=4 | fib(4) = fib(3) + fib(2). Call fib(3) first. |
| 7 | L1 | n=3 depth=3 | Call fib(3). |
| 8 | L2 | n=3 | Not a base case. |
| 9 | L3 | n=3 | fib(3) = fib(2) + fib(1). Call fib(2) first. |
| 10 | L1 | n=2 depth=4 | Call fib(2). |
| 11 | L2 | n=2 | Not a base case. |
| 12 | L3 | n=2 | fib(2) = fib(1) + fib(0). Call fib(1) first. |
| 13 | L1 | n=1 depth=5 | Call fib(1). |
| 14 | L2 | n=1 | Base case: fib(1) = 1. |
| 15 | L2 | n=1 return=1 | return 1. |
| 16 | L3 | n=2 left=1 | fib(1) = 1. Now call fib(0). |
| 17 | L1 | n=0 depth=5 | Call fib(0). |
| 18 | L2 | n=0 | Base case: fib(0) = 0. |
| 19 | L2 | n=0 return=0 | return 0. |
| 20 | L3 | n=2 left=1 right=0 return=1 | fib(2) = 1 + 0 = 1. |
| 21 | L3 | n=3 left=1 | fib(2) = 1. Now call fib(1). |
| 22 | L1 | n=1 depth=4 | Call fib(1). |
| 23 | L2 | n=1 | Base case: fib(1) = 1. |
| 24 | L2 | n=1 return=1 | return 1. |
| 25 | L3 | n=3 left=1 right=1 return=2 | fib(3) = 1 + 1 = 2. |
| 26 | L3 | n=4 left=2 | fib(3) = 2. Now call fib(2). |
| 27 | L1 | n=2 depth=3 | Call fib(2). |
| 28 | L2 | n=2 | Not a base case. |
| 29 | L3 | n=2 | fib(2) = fib(1) + fib(0). Call fib(1) first. |
| 30 | L1 | n=1 depth=4 | Call fib(1). |
| 31 | L2 | n=1 | Base case: fib(1) = 1. |
| 32 | L2 | n=1 return=1 | return 1. |
| 33 | L3 | n=2 left=1 | fib(1) = 1. Now call fib(0). |
| 34 | L1 | n=0 depth=4 | Call fib(0). |
| 35 | L2 | n=0 | Base case: fib(0) = 0. |
| 36 | L2 | n=0 return=0 | return 0. |
| 37 | L3 | n=2 left=1 right=0 return=1 | fib(2) = 1 + 0 = 1. |
| 38 | L3 | n=4 left=2 right=1 return=3 | fib(4) = 2 + 1 = 3. |
| 39 | L3 | n=5 left=3 | fib(4) = 3. Now call fib(3). |
| 40 | L1 | n=3 depth=2 | Call fib(3). |
| 41 | L2 | n=3 | Not a base case. |
| 42 | L3 | n=3 | fib(3) = fib(2) + fib(1). Call fib(2) first. |
| 43 | L1 | n=2 depth=3 | Call fib(2). |
| 44 | L2 | n=2 | Not a base case. |
| 45 | L3 | n=2 | fib(2) = fib(1) + fib(0). Call fib(1) first. |
| 46 | L1 | n=1 depth=4 | Call fib(1). |
| 47 | L2 | n=1 | Base case: fib(1) = 1. |
| 48 | L2 | n=1 return=1 | return 1. |
| 49 | L3 | n=2 left=1 | fib(1) = 1. Now call fib(0). |
| 50 | L1 | n=0 depth=4 | Call fib(0). |
| 51 | L2 | n=0 | Base case: fib(0) = 0. |
| 52 | L2 | n=0 return=0 | return 0. |
| 53 | L3 | n=2 left=1 right=0 return=1 | fib(2) = 1 + 0 = 1. |
| 54 | L3 | n=3 left=1 | fib(2) = 1. Now call fib(1). |
| 55 | L1 | n=1 depth=3 | Call fib(1). |
| 56 | L2 | n=1 | Base case: fib(1) = 1. |
| 57 | L2 | n=1 return=1 | return 1. |
| 58 | L3 | n=3 left=1 right=1 return=2 | fib(3) = 1 + 1 = 2. |
| 59 | L3 | n=5 left=3 right=2 return=5 | fib(5) = 3 + 2 = 5. |
| 60 | L3 | return=5 | fib(5) = 5 with 15 calls. Notice how fib(3) and its subtrees repeat. Memoization removes this waste. |
Fibonacci with memoization
Interactive · edit the inputRecursion tree · 1 call
Call fib(6).
1static long[] memo = new long[100];2static long fib(int n) {3if (n <= 1) return n; // base cases4if (memo[n] != 0) return memo[n]; // already solved: reuse it5return memo[n] = fib(n - 1) + fib(n - 2); // solve once, remember6}
Live state
n
6
depth
1
Call stack (top first)
- fib(6)
Execution trace (dry run table)Show 52 stepsHide
| Step | Line | State | What happens |
|---|---|---|---|
| 1 | L2 | n=6 depth=1 | Call fib(6). |
| 2 | L3 | n=6 | Not a base case. |
| 3 | L4 | n=6 memo[n]=0 | memo[6] is empty, so compute it. |
| 4 | L5 | n=6 | fib(6) = fib(5) + fib(4). Call fib(5) first. |
| 5 | L2 | n=5 depth=2 | Call fib(5). |
| 6 | L3 | n=5 | Not a base case. |
| 7 | L4 | n=5 memo[n]=0 | memo[5] is empty, so compute it. |
| 8 | L5 | n=5 | fib(5) = fib(4) + fib(3). Call fib(4) first. |
| 9 | L2 | n=4 depth=3 | Call fib(4). |
| 10 | L3 | n=4 | Not a base case. |
| 11 | L4 | n=4 memo[n]=0 | memo[4] is empty, so compute it. |
| 12 | L5 | n=4 | fib(4) = fib(3) + fib(2). Call fib(3) first. |
| 13 | L2 | n=3 depth=4 | Call fib(3). |
| 14 | L3 | n=3 | Not a base case. |
| 15 | L4 | n=3 memo[n]=0 | memo[3] is empty, so compute it. |
| 16 | L5 | n=3 | fib(3) = fib(2) + fib(1). Call fib(2) first. |
| 17 | L2 | n=2 depth=5 | Call fib(2). |
| 18 | L3 | n=2 | Not a base case. |
| 19 | L4 | n=2 memo[n]=0 | memo[2] is empty, so compute it. |
| 20 | L5 | n=2 | fib(2) = fib(1) + fib(0). Call fib(1) first. |
| 21 | L2 | n=1 depth=6 | Call fib(1). |
| 22 | L3 | n=1 | Base case: fib(1) = 1. |
| 23 | L3 | n=1 return=1 | return 1. |
| 24 | L5 | n=2 left=1 | fib(1) = 1. Now call fib(0). |
| 25 | L2 | n=0 depth=6 | Call fib(0). |
| 26 | L3 | n=0 | Base case: fib(0) = 0. |
| 27 | L3 | n=0 return=0 | return 0. |
| 28 | L5 | n=2 left=1 right=0 return=1 | fib(2) = 1 + 0 = 1. Store it in memo[2]. |
| 29 | L5 | n=3 left=1 | fib(2) = 1. Now call fib(1). |
| 30 | L2 | n=1 depth=5 | Call fib(1). |
| 31 | L3 | n=1 | Base case: fib(1) = 1. |
| 32 | L3 | n=1 return=1 | return 1. |
| 33 | L5 | n=3 left=1 right=1 return=2 | fib(3) = 1 + 1 = 2. Store it in memo[3]. |
| 34 | L5 | n=4 left=2 | fib(3) = 2. Now call fib(2). |
| 35 | L2 | n=2 depth=4 | Call fib(2). |
| 36 | L3 | n=2 | Not a base case. |
| 37 | L4 | n=2 memo[n]=1 | memo[2] is already 1. No need to recurse again. |
| 38 | L4 | n=2 return=1 | Cache hit: return 1 immediately. This whole subtree is skipped. |
| 39 | L5 | n=4 left=2 right=1 return=3 | fib(4) = 2 + 1 = 3. Store it in memo[4]. |
| 40 | L5 | n=5 left=3 | fib(4) = 3. Now call fib(3). |
| 41 | L2 | n=3 depth=3 | Call fib(3). |
| 42 | L3 | n=3 | Not a base case. |
| 43 | L4 | n=3 memo[n]=2 | memo[3] is already 2. No need to recurse again. |
| 44 | L4 | n=3 return=2 | Cache hit: return 2 immediately. This whole subtree is skipped. |
| 45 | L5 | n=5 left=3 right=2 return=5 | fib(5) = 3 + 2 = 5. Store it in memo[5]. |
| 46 | L5 | n=6 left=5 | fib(5) = 5. Now call fib(4). |
| 47 | L2 | n=4 depth=2 | Call fib(4). |
| 48 | L3 | n=4 | Not a base case. |
| 49 | L4 | n=4 memo[n]=3 | memo[4] is already 3. No need to recurse again. |
| 50 | L4 | n=4 return=3 | Cache hit: return 3 immediately. This whole subtree is skipped. |
| 51 | L5 | n=6 left=5 right=3 return=8 | fib(6) = 5 + 3 = 8. Store it in memo[6]. |
| 52 | L5 | return=8 | fib(6) = 8 with 11 calls. Plain recursion would need 25 calls. |
Sum of digits
To sum the digits of n, take the last digit n % 10 and add the digit sum of the rest, n / 10. The recursion stops at 0.
The number of calls equals the number of digits plus one, so the work is O(log₁₀ n). This pattern, peel off a piece and recurse on the remainder, is the same as walking a list.
Worst
O(log n)
Space
O(log n) stack
Sum of digits
Interactive · edit the inputRecursion tree · 1 call
Call sumDigits(4821).
1static int sumDigits(int n) {2if (n == 0) return 0; // no digits left3return n % 10 + sumDigits(n / 10); // last digit + the rest4}
Live state
n
4821
Call stack (top first)
- sumDigits(4821)
Execution trace (dry run table)Show 20 stepsHide
| Step | Line | State | What happens |
|---|---|---|---|
| 1 | L1 | n=4821 | Call sumDigits(4821). |
| 2 | L2 | n=4821 | Split 4821 into last digit 1 and the rest 482. |
| 3 | L3 | n=4821 digit=1 | Call sumDigits(482) for the remaining digits. |
| 4 | L1 | n=482 | Call sumDigits(482). |
| 5 | L2 | n=482 | Split 482 into last digit 2 and the rest 48. |
| 6 | L3 | n=482 digit=2 | Call sumDigits(48) for the remaining digits. |
| 7 | L1 | n=48 | Call sumDigits(48). |
| 8 | L2 | n=48 | Split 48 into last digit 8 and the rest 4. |
| 9 | L3 | n=48 digit=8 | Call sumDigits(4) for the remaining digits. |
| 10 | L1 | n=4 | Call sumDigits(4). |
| 11 | L2 | n=4 | Split 4 into last digit 4 and the rest 0. |
| 12 | L3 | n=4 digit=4 | Call sumDigits(0) for the remaining digits. |
| 13 | L1 | n=0 | Call sumDigits(0). |
| 14 | L2 | n=0 | Base case: no digits left. |
| 15 | L2 | n=0 return=0 | return 0. |
| 16 | L3 | n=4 return=4 | 4 + 0 = 4. |
| 17 | L3 | n=48 return=12 | 8 + 4 = 12. |
| 18 | L3 | n=482 return=14 | 2 + 12 = 14. |
| 19 | L3 | n=4821 return=15 | 1 + 14 = 15. |
| 20 | L3 | return=15 | The digits of 4821 sum to 15. Calls = number of digits + 1 = 5. |
Reverse array
To reverse a[lo..hi], swap the two ends and reverse the inside a[lo + 1..hi - 1]. The base case is a range with zero or one element. The recursion depth is about n / 2.
An iterative two-pointer loop does the same with no stack. The recursive version is a good way to practise stating the invariant: positions outside lo..hi are already final.
Worst
O(n)
Space
O(n) stack
Reverse an array recursively
Interactive · edit the inputint[] arr · length 7
Call reverse(a, 0, 6).
1static void reverse(int[] a, int lo, int hi) {2if (lo >= hi) return; // zero or one element: nothing to do3swap(a, lo, hi); // fix the two outer elements4reverse(a, lo + 1, hi - 1); // reverse the inside5}
Live state
lo
0
hi
6
Call stack (top first)
- reverse(0, 6)
Execution trace (dry run table)Show 12 stepsHide
| Step | Line | State | What happens |
|---|---|---|---|
| 1 | L1 | lo=0 hi=6 | Call reverse(a, 0, 6). |
| 2 | L2 | lo=0 hi=6 | Two or more elements: swap the outer pair. |
| 3 | L3 | lo=0 hi=6 | Swap a[0] and a[6]. Those two positions are now final. |
| 4 | L1 | lo=1 hi=5 | Call reverse(a, 1, 5). |
| 5 | L2 | lo=1 hi=5 | Two or more elements: swap the outer pair. |
| 6 | L3 | lo=1 hi=5 | Swap a[1] and a[5]. Those two positions are now final. |
| 7 | L1 | lo=2 hi=4 | Call reverse(a, 2, 4). |
| 8 | L2 | lo=2 hi=4 | Two or more elements: swap the outer pair. |
| 9 | L3 | lo=2 hi=4 | Swap a[2] and a[4]. Those two positions are now final. |
| 10 | L1 | lo=3 hi=3 | Call reverse(a, 3, 3). |
| 11 | L2 | lo=3 hi=3 | The pointers met or crossed. The middle needs no work. |
| 12 | L4 | Reversed with 3 swaps and 4 calls. Recursion depth is about n / 2. |
Power function
Computing x^n with n multiplications is O(n). Halving the exponent is much faster: x^n = (x^(n/2))² for even n and (x^(n/2))² · x for odd n. One recursive call with the smaller exponent is reused, not repeated.
The depth is ⌊log₂ n⌋ + 1. Try 2^16: only 5 calls and a handful of multiplications. Calling power(x, n / 2) twice instead of storing it in half would silently bring back O(n).
Worst
O(log n)
Space
O(log n) stack
Power function: halving the exponent
Interactive · edit the inputRecursion tree · 1 call
Call power(2, 13).
1static long power(long x, int n) {2if (n == 0) return 1; // x^0 = 13long half = power(x, n / 2); // solve a problem half the size4return (n % 2 == 0) ? half * half : half * half * x;5}
Live state
x
2
n
13
Call stack (top first)
- power(2, 13)
Execution trace (dry run table)Show 20 stepsHide
| Step | Line | State | What happens |
|---|---|---|---|
| 1 | L1 | x=2 n=13 | Call power(2, 13). |
| 2 | L2 | n=13 | n = 13 is not 0. Halve it: 13 / 2 = 6. |
| 3 | L3 | x=2 n=13 | Compute power(2, 6) once and reuse it. |
| 4 | L1 | x=2 n=6 | Call power(2, 6). |
| 5 | L2 | n=6 | n = 6 is not 0. Halve it: 6 / 2 = 3. |
| 6 | L3 | x=2 n=6 | Compute power(2, 3) once and reuse it. |
| 7 | L1 | x=2 n=3 | Call power(2, 3). |
| 8 | L2 | n=3 | n = 3 is not 0. Halve it: 3 / 2 = 1. |
| 9 | L3 | x=2 n=3 | Compute power(2, 1) once and reuse it. |
| 10 | L1 | x=2 n=1 | Call power(2, 1). |
| 11 | L2 | n=1 | n = 1 is not 0. Halve it: 1 / 2 = 0. |
| 12 | L3 | x=2 n=1 | Compute power(2, 0) once and reuse it. |
| 13 | L1 | x=2 n=0 | Call power(2, 0). |
| 14 | L2 | n=0 | Base case: any number to the power 0 is 1. |
| 15 | L2 | n=0 return=1 | return 1. |
| 16 | L4 | n=1 half=1 return=2 | n is odd: half × half × x = 1 × 1 × 2 = 2. |
| 17 | L4 | n=3 half=2 return=8 | n is odd: half × half × x = 2 × 2 × 2 = 8. |
| 18 | L4 | n=6 half=8 return=64 | n is even: half × half = 8 × 8 = 64. |
| 19 | L4 | n=13 half=64 return=8192 | n is odd: half × half × x = 64 × 64 × 2 = 8192. |
| 20 | L4 | return=8192 | 2^13 = 8192 with 5 calls (about log₂ n) instead of 13 multiplications. |
Greatest common divisor
Euclid's algorithm uses gcd(a, b) = gcd(b, a % b) and stops when b is 0. It works because any number that divides both a and b also divides the remainder a % b. Try 252 and 105: the pairs go (252, 105), (105, 42), (42, 21), (21, 0), so the answer is 21.
The numbers shrink at least by half every two steps, so it takes O(log min(a, b)) calls. The slowest inputs are consecutive Fibonacci numbers, such as the “Fibonacci pair” preset. The call is a tail call, so it is easy to write as a loop.
Worst
O(log min(a, b))
Space
O(log n) stack, O(1) as a loop
Greatest common divisor (Euclid)
Interactive · edit the inputRecursion tree · 1 call
Call gcd(252, 105).
1static int gcd(int a, int b) {2if (b == 0) return a; // base case3return gcd(b, a % b); // same answer, smaller numbers4}
Live state
a
252
b
105
Call stack (top first)
- gcd(252, 105)
Execution trace (dry run table)Show 16 stepsHide
| Step | Line | State | What happens |
|---|---|---|---|
| 1 | L1 | a=252 b=105 | Call gcd(252, 105). |
| 2 | L2 | a=252 b=105 | b is not 0. 252 % 105 = 42, and gcd(a, b) = gcd(b, a % b). |
| 3 | L3 | a=252 b=105 a % b=42 | Call gcd(105, 42). |
| 4 | L1 | a=105 b=42 | Call gcd(105, 42). |
| 5 | L2 | a=105 b=42 | b is not 0. 105 % 42 = 21, and gcd(a, b) = gcd(b, a % b). |
| 6 | L3 | a=105 b=42 a % b=21 | Call gcd(42, 21). |
| 7 | L1 | a=42 b=21 | Call gcd(42, 21). |
| 8 | L2 | a=42 b=21 | b is not 0. 42 % 21 = 0, and gcd(a, b) = gcd(b, a % b). |
| 9 | L3 | a=42 b=21 a % b=0 | Call gcd(21, 0). |
| 10 | L1 | a=21 b=0 | Call gcd(21, 0). |
| 11 | L2 | a=21 b=0 | b is 0, so 21 divides everything left: the answer is 21. |
| 12 | L2 | a=21 b=0 return=21 | return 21. Nothing more to do on the way back: this is a tail call. |
| 13 | L3 | a=42 b=21 return=21 | return 21. Nothing more to do on the way back: this is a tail call. |
| 14 | L3 | a=105 b=42 return=21 | return 21. Nothing more to do on the way back: this is a tail call. |
| 15 | L3 | a=252 b=105 return=21 | return 21. Nothing more to do on the way back: this is a tail call. |
| 16 | L3 | return=21 | gcd(252, 105) = 21 after 4 calls. |
Recursive binary search
Binary search is recursion on a range: look at the middle, then search the left or right half. The base case is an empty range. The call is a tail call, and the depth is O(log n).
This is the same algorithm you traced in Chapter 16. Compare the animation here with the iterative version: the call stack panel replaces the loop variables lo and hi.
Worst
O(log n)
Space
O(log n) stack
Binary search (recursive)
Interactive · edit the inputint[] arr · length 9
Enter search(arr, 44, 0, 8). Call depth is 1.
1public static int search(int[] arr, int target, int lo, int hi) {2if (lo > hi) {3return -1;4}5int mid = lo + (hi - lo) / 2;6if (arr[mid] == target) {7return mid;8}9if (arr[mid] < target) {10return search(arr, target, mid + 1, hi);11}12return search(arr, target, lo, mid - 1);13}
Live state
target
44
lo
0
hi
8
depth
1
Call stack (top first)
- search(0, 8)
Execution trace (dry run table)Show 13 stepsHide
| Step | Line | State | What happens |
|---|---|---|---|
| 1 | L1 | target=44 lo=0 hi=8 depth=1 | Enter search(arr, 44, 0, 8). Call depth is 1. |
| 2 | L2 | target=44 lo=0 hi=8 depth=1 | Window is not empty, so this call does real work. |
| 3 | L5 | target=44 lo=0 hi=8 mid=4 depth=1 | mid = 4. |
| 4 | L6 | target=44 lo=0 hi=8 mid=4 arr[mid]=27 depth=1 | No match yet. |
| 5 | L9 | target=44 lo=0 hi=8 mid=4 arr[mid]=27 depth=1 | Target is larger, so recurse into the right half. |
| 6 | L10 | target=44 lo=0 hi=8 mid=4 depth=1 | Call search(arr, 44, 5, 8). This call waits for the answer. |
| 7 | L1 | target=44 lo=5 hi=8 depth=2 | Enter search(arr, 44, 5, 8). Call depth is 2. |
| 8 | L2 | target=44 lo=5 hi=8 depth=2 | Window is not empty, so this call does real work. |
| 9 | L5 | target=44 lo=5 hi=8 mid=6 depth=2 | mid = 6. |
| 10 | L6 | target=44 lo=5 hi=8 mid=6 arr[mid]=44 depth=2 | Match. |
| 11 | L7 | target=44 depth=2 return=6 | return 6 from depth 2. |
| 12 | L10 | target=44 depth=1 return=6 | search(5, 8) returned 6. Its caller returns the same value unchanged. |
| 13 | L13 | target=44 return=6 | The original call returns 6. Recursion used 2 calls, so O(log n) stack space. |
Practice ladder
Now try it yourself
Easy
- Sum of an array recursively
- Count occurrences of a value in an array recursively
- Is a number a power of two (recursion by halving)?
Medium
- Fibonacci with a memo array and compare call counts
- Compute x^n modulo m with fast power
- Find the maximum of an array recursively
Advanced
- Fibonacci in O(log n) with matrix exponentiation
- Extended Euclid: find x, y with ax + by = gcd(a, b)
- Count the calls Euclid makes for consecutive Fibonacci inputs
Key takeaways
- Naive Fibonacci recomputes the same subproblems and takes exponential time; memoization makes it linear.
- Halving the problem (power, binary search, GCD) turns O(n) work into O(log n).
- Call counts and stack depth are as important as the answer; always check overflow.