Problem
You are climbing a staircase. It takes n steps to reach the top.
Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?
OR
There are n stairs, a person standing at the bottom wants to reach the top. The person can climb either 1 stair or 2 stairs at a time. Count the number of ways, the person can reach the top.
Examples
Example 1:
| |
Example 2:
| |
Example 3:
| |
Example 4:
| |
Solution
Video explanation
Here is the video explaining this method in detail. Please check it out:
Method 1 - Backtracking
This approach uses Depth-First Search (DFS) or backtracking to explore all possible paths to climb the staircase. At each step, the function recursively adds either 1 step or 2 steps, terminating when the step count either reaches or exceeds n.
Here si the approach:
- Start the recursion (DFS) from step
0. - At each step:
- Add 1 step to the current step and call the function recursively.
- Add 2 steps to the current step and call the function recursively.
- Base Cases:
- If
current_step == n, the path is valid, so return1. - If
current_step > n, the path exceeds the total steps, so return0.
- If
- Accumulate valid paths for both choices (taking 1 step or 2 steps).
Here is how the recursion tree will look like:
graph TD;
A("0:4") ---|1 step| B(1)
A ---|2 steps| C(2)
B ---|1 step| D(2)
B ---|2 steps| E(3)
C ---|1 step| F(3)
C ---|2 steps| G(4):::green
D ---|1 step| H(3)
D ---|2 steps| I(4):::green
E ---|1 step| J(4):::green
E ---|2 steps| K(5):::red
F ---|1 step| L(4):::green
F ---|2 steps| M(5):::red
H ---|1 step| N(4):::green
H ---|2 steps| O(5):::red
classDef green fill:#3CB371,stroke:#000,stroke-width:1px,color:#fff;
classDef red fill:#FF0000,stroke:#000,stroke-width:1px,color:#fff;
As, you can see the total number of green or valid nodes are 5.
Code
| |
| |
Complexity
- ⏰ Time complexity:
O(2^n). The total number of paths is roughly2^nbecause two recursive calls are made at each step. - 🧺 Space complexity:
O(n), as the recursion stack can grow up tonlevels deep.
Method 2 - Recursion
We can easily find recursive nature in above problem.
Lets take n = 2, then we have 2 ways - either take 1 step twice or 2 steps in one go.
For n = 3, we have 3 ways:
- One Step at a time
- Two-step then one step
- One step then Two-step
For n = 4, we have 5 ways: (1, 1, 1, 1), (2, 2), (1, 1, 2), (2, 1, 1), (1, 2, 1)
Now, lets take n = 6, and try to get the algorithm.
So in the next step, we need to calculate the number of ways taken to raise 5 steps and 4 steps.
We can build full tree for the steps taken as below (not complete for clarity):
Code
| |
| |
Complexity
- ⏰ Time complexity:
O(2^n), because overlapping subproblems are recomputed multiple times. - 🧺 Space complexity:
O(n)due to recursion stack.
Method 3 - Top Down DP
The naive recursive approach recalculates overlapping subproblems multiple times, leading to inefficiency. By using a memoisation table (cache), you can store results of previously computed subproblems to avoid redundant calculations.
Here is the approach:
- Use a cache (
HashMapor dictionary) to store results for each step:- If the result for
nis already computed, retrieve it from the cache. - Otherwise, compute
ways(n)recursively:ways(n) = ways(n-1) + ways(n-2) - Save the result for
nin the cache for future use.
- If the result for
Code
| |
| |
Complexity
- ⏰ Time complexity:
O(n) - 🧺 Space complexity:
O(n)
Method 4 - Bottom Up DP
Instead of recursion, build the solution iteratively using a dp table. Once base cases are solved (dp[1] = 1, dp[2] = 2), compute the number of ways for each step up to n by combining results for the previous two steps. This avoids recursion overhead and ensures every subproblem is solved sequentially.
Here is the approach:
- Initialise a
dparray of sizen+1(to store results for steps1ton). - Populate the base cases:
dp[1] = 1dp[2] = 2.
- Use the recurrence relation iteratively:
dp[i] = dp[i-1] + dp[i-2] - Return the value stored at
dp[n].
Code
| |
| |
Complexity
- ⏰ Time complexity:
O(n) - 🧺 Space complexity:
O(n)for using the dp tale
Method 5 - Space efficient Bottom up DP
While the bottom-up DP uses a dp table, observe that only the last two values, dp[i-1] and dp[i-2], are needed to compute dp[i]. This allows us to optimise space by storing only two variables (prev1 and prev2) instead of maintaining an entire table.
Here is the approach:
- Initialise two variables:
prev1holdsdp[i-1](starting withdp[2]= 2).prev2holdsdp[i-2](starting withdp[1]= 1).
- Iteratively compute the current value using the relation:
curr = prev1 + prev2 - Shift the variables:
prev2 = prev1prev1 = curr.
- Return the final value (
prev1).
Code
| |
| |
Complexity
- ⏰ Time complexity:
O(n). We iterate through all steps from3ton. - 🧺 Space complexity:
O(1). Uses only two variables (prev1andprev2), avoiding the need for a DP table.
Method 6- Using Fibonacci Numbers
The number of ways to reach the n-th stair on a staircase depends on whether you can take one step at a time (from the (n-1)th stair) or two steps at a time (from the (n-2)th stair). We’ll represent this total number of ways to reach the n-th stair as ways(n).
| |
This is actually formula for generating nth fibonacci number.
But notice one thing that ways(n) is equal to fib(n+1), hence we can reuse fib(n) function.
| |
Code
| |
Complexity
- ⏰ Time complexity:
O(n). (It can be optimized to work in O(Logn) time using matrix approach) - 🧺 Space complexity:
O(n)