Recursive Staircase Problem
Algorithm · Core
Step through it: Dynamic Programming pattern
Step 1 of 6
Goal: how many ways can you climb 5 stairs taking 1 or 2 steps at a time? You reach stair 5 from stair 4 or stair 3, so ways(5) = ways(4) + ways(3). Working that out naively repeats the same sub-questions many times. Instead write each answer down once.
Step 2 of 6
Base cases: there is 1 way to be on stair 0 (do nothing) and 1 way to reach stair 1.
Step 3 of 6
Stair 2 is reached from stair 1 or stair 0.
Step 4 of 6
Stair 3 comes from stairs 2 and 1.
Step 5 of 6
Stair 4: 3 + 2 = 5. Stair 5: 5 + 3 = 8. Each answer reuses two stored answers, so n stairs take n steps instead of exponential time. Storing sub-answers like this is dynamic programming.
Step 6 of 6
Your turn.
The Problem
There are n stairs, a person standing at the bottom wants to reach the top. The person can climb either 1 or 2 stairs at a time. Count the number of ways, the person can reach the top.
The Solution
This is an interesting problem because there are several ways of how it may be solved that illustrate different programming paradigms.
- Brute Force Recursive Solution - Time:
O(2^n); Space:O(1) - Recursive Solution With Memoization - Time:
O(n); Space:O(n) - Dynamic Programming Solution - Time:
O(n); Space:O(n) - Iterative Solution - Time:
O(n); Space:O(1)
Code
/**
* Recursive Staircase Problem (Brute Force Solution).
*
* @param {number} stairsNum - Number of stairs to climb on.
* @return {number} - Number of ways to climb a staircase.
*/
export default function recursiveStaircaseBF(stairsNum) {
if (stairsNum <= 0) {
// There is no way to go down - you climb the stairs only upwards.
// Also if you're standing on the ground floor that you don't need to do any further steps.
return 0;
}
if (stairsNum === 1) {
// There is only one way to go to the first step.
return 1;
}
if (stairsNum === 2) {
// There are two ways to get to the second steps: (1 + 1) or (2).
return 2;
}
// Sum up how many steps we need to take after doing one step up with the number of
// steps we need to take after doing two steps up.
return recursiveStaircaseBF(stairsNum - 1) + recursiveStaircaseBF(stairsNum - 2);
}/**
* Recursive Staircase Problem (Dynamic Programming Solution).
*
* @param {number} stairsNum - Number of stairs to climb on.
* @return {number} - Number of ways to climb a staircase.
*/
export default function recursiveStaircaseDP(stairsNum) {
if (stairsNum < 0) {
// There is no way to go down - you climb the stairs only upwards.
return 0;
}
// Init the steps vector that will hold all possible ways to get to the corresponding step.
const steps = new Array(stairsNum + 1).fill(0);
// Init the number of ways to get to the 0th, 1st and 2nd steps.
steps[0] = 0;
steps[1] = 1;
steps[2] = 2;
if (stairsNum <= 2) {
// Return the number of ways to get to the 0th or 1st or 2nd steps.
return steps[stairsNum];
}
// Calculate every next step based on two previous ones.
for (let currentStep = 3; currentStep <= stairsNum; currentStep += 1) {
steps[currentStep] = steps[currentStep - 1] + steps[currentStep - 2];
}
// Return possible ways to get to the requested step.
return steps[stairsNum];
}/**
* Recursive Staircase Problem (Iterative Solution).
*
* @param {number} stairsNum - Number of stairs to climb on.
* @return {number} - Number of ways to climb a staircase.
*/
export default function recursiveStaircaseIT(stairsNum) {
if (stairsNum <= 0) {
// There is no way to go down - you climb the stairs only upwards.
// Also you don't need to do anything to stay on the 0th step.
return 0;
}
// Init the number of ways to get to the 0th, 1st and 2nd steps.
const steps = [1, 2];
if (stairsNum <= 2) {
// Return the number of possible ways of how to get to the 1st or 2nd steps.
return steps[stairsNum - 1];
}
// Calculate the number of ways to get to the n'th step based on previous ones.
// Comparing to Dynamic Programming solution we don't store info for all the steps but
// rather for two previous ones only.
for (let currentStep = 3; currentStep <= stairsNum; currentStep += 1) {
[steps[0], steps[1]] = [steps[1], steps[0] + steps[1]];
}
// Return possible ways to get to the requested step.
return steps[1];
}/**
* Recursive Staircase Problem (Recursive Solution With Memoization).
*
* @param {number} totalStairs - Number of stairs to climb on.
* @return {number} - Number of ways to climb a staircase.
*/
export default function recursiveStaircaseMEM(totalStairs) {
// Memo table that will hold all recursively calculated results to avoid calculating them
// over and over again.
const memo = [];
// Recursive closure.
const getSteps = (stairsNum) => {
if (stairsNum <= 0) {
// There is no way to go down - you climb the stairs only upwards.
// Also if you're standing on the ground floor that you don't need to do any further steps.
return 0;
}
if (stairsNum === 1) {
// There is only one way to go to the first step.
return 1;
}
if (stairsNum === 2) {
// There are two ways to get to the second steps: (1 + 1) or (2).
return 2;
}
// Avoid recursion for the steps that we've calculated recently.
if (memo[stairsNum]) {
return memo[stairsNum];
}
// Sum up how many steps we need to take after doing one step up with the number of
// steps we need to take after doing two steps up.
memo[stairsNum] = getSteps(stairsNum - 1) + getSteps(stairsNum - 2);
return memo[stairsNum];
};
// Return possible ways to get to the requested step.
return getSteps(totalStairs);
}References
Practice
Dynamic Programming
- Climbing StairsEasy
- Fibonacci NumberEasy
- Min Cost Climbing StairsEasy
- Pascal's TriangleEasy
- House RobberMedium
- House Robber IIMedium
- Coin ChangeMedium
- Coin Change IIMedium
- Longest Increasing SubsequenceMedium
- Longest Common SubsequenceMedium
- Word BreakMedium
- Unique PathsMedium
- Unique Paths IIMedium
- Minimum Path SumMedium
- Jump GameMedium
- Partition Equal Subset SumMedium
- Target SumMedium
- Decode WaysMedium
- Maximum Product SubarrayMedium
- Longest Palindromic SubstringMedium
- Palindromic SubstringsMedium
- Best Time to Buy and Sell Stock with CooldownMedium
- TriangleMedium
- Maximal SquareMedium
- Edit DistanceHard
- Regular Expression MatchingHard
- Burst BalloonsHard
- Distinct SubsequencesHard
- Longest Valid ParenthesesHard
- Best Time to Buy and Sell Stock IVHard
Spotted a mistake or something unclear? Report it on GitHub.