AlgoDaily

Recursive Approach

Read at your own pace. Code execution, quizzes, progress tracking, and the AI tutor are available in the interactive view with JavaScript enabled.

Why Recursion First

From DP signals to recursive shape

In Introduction to Dynamic Programming, you learned to spot two important signals: repeated work and overlapping subproblems.

Now we’ll build the raw form those signals usually come from: a recursive approach.

Before memoization, before top-down DP, and before bottom-up tables, we need to answer:

  • What is the smaller version of this problem?
  • What choices can I make from the current state?
  • When should the recursion stop?

Think of recursion as the first draft of a DP solution: not always efficient, but extremely useful for discovering the structure.

Why Recursion First

The Recursive Contract

A recursive function needs a contract

A good recursive solution is not just “call the function again.” It has a clear contract.

A useful template:

function solve(state):
  if state is finished:
    return known answer

  answer = combine results from smaller states
  return answer

The important word is state.

For a full stack engineer, this is similar to defining an API endpoint contract: given these inputs, what does this function promise to return?

For recursion, the state might be:

  • An index in an array
  • A remaining amount
  • A grid coordinate
  • A string position
  • A pair like (i, j)

Once the state is clear, the recurrence usually becomes easier to write.

The Recursive Contract

Naive Fibonacci

The classic recursive draft

Fibonacci is overused, but it is perfect for seeing the recursive approach clearly.

The contract:

fib(n) returns the nth Fibonacci number.

Base cases:

  • fib(0) = 0
  • fib(1) = 1

Recursive case:

  • fib(n) = fib(n - 1) + fib(n - 2)

This version is intentionally naive. We are not improving it yet — we are learning how to express the problem recursively.

```javascript
let calls = 0;

function fib(n) {
  calls++;

  if (n === 0) return 0;
  if (n === 1) return 1;

  return fib(n - 1) + fib(n - 2);
}

const n = 6;
console.log(`fib(${n}) =`, fib(n));
console.log("recursive calls:", calls);
```

Recursive Ingredients

Which set of ingredients best describes a well-formed recursive solution?

Recursion Tree Cost

Recursion shows the work

The recursive version of Fibonacci creates a tree of calls:

fib(5)
├── fib(4)
│   ├── fib(3)
│   └── fib(2)
└── fib(3)
    ├── fib(2)
    └── fib(1)

Notice that fib(3) and fib(2) appear more than once.

That is the repeated work signal from the previous lesson showing up in a concrete form.

For this lesson, the point is not to fix it yet. The point is to see how recursion exposes the shape of the problem: a tree of smaller decisions or subproblems.

Recursion Tree Cost

Complete Recurrence

For climbing stairs where you can take either 1 or 2 steps, complete the recurrence:

ways(n) = ______

Assume the base cases are handled separately.

Grid Paths Recursively

Recursion is not just Fibonacci

Consider a robot moving through a grid from the top-left to the bottom-right.

Allowed moves:

  • Down
  • Right

The contract:

countPaths(row, col) returns the number of ways to reach the destination from this cell.

Base cases:

  • If we are at the destination, return 1.
  • If we move outside the grid, return 0.

Recursive case:

  • Paths from here = paths going down + paths going right.
```javascript
function countPaths(row, col, rows, cols) {
  const atDestination = row === rows - 1 && col === cols - 1;
  if (atDestination) return 1;

  const outOfBounds = row >= rows || col >= cols;
  if (outOfBounds) return 0;

  const goDown = countPaths(row + 1, col, rows, cols);
  const goRight = countPaths(row, col + 1, rows, cols);

  return goDown + goRight;
}

console.log("3x3 grid paths:", countPaths(0, 0, 3, 3));
console.log("2x4 grid paths:", countPaths(0, 0, 2, 4));
```

Efficiency Check

True or false:

If a recursive solution returns the correct answer, it is automatically efficient enough for large inputs.

Stack And Tradeoffs

What recursion costs

Recursive solutions are often expressive, but they are not free.

Key costs to watch:

  • Call stack depth: each unfinished call stays on the stack.
  • Repeated branches: the same state may be recomputed many times.
  • Exponential growth: two or more branches per call can explode quickly.
  • Debug complexity: state changes across nested calls can be hard to trace.

In production JavaScript, you also need to remember that very deep recursion can hit stack limits. For interview-style DP problems, recursion is still a powerful first model because it reveals the state and transitions cleanly.

Stack And Tradeoffs

Choice Recursion

Recursion often models choices

Many DP-style problems can be drafted recursively by asking:

At this state, what choices do I have?

Example: count the number of ways to make an amount using coin denominations.

At each state, we can choose to:

  • Use the current coin again
  • Skip to the next coin

The state is (index, remaining):

  • index: which coin we are considering
  • remaining: amount left to build

This is still plain recursion. In the next lesson, we’ll look at how to avoid recomputing the same states.

```javascript
function countWays(coins, index, remaining) {
  if (remaining === 0) return 1;
  if (remaining < 0) return 0;
  if (index === coins.length) return 0;

  const useCurrentCoin = countWays(coins, index, remaining - coins[index]);
  const skipCurrentCoin = countWays(coins, index + 1, remaining);

  return useCurrentCoin + skipCurrentCoin;
}

const coins = [1, 2, 5];
const amount = 5;

console.log(`ways to make ${amount}:`, countWays(coins, 0, amount));
```
Open interactive view →