Skip to content

Commit 9bc2800

Browse files
committed
Add Recursive Staircase Problem.
1 parent 5e0e571 commit 9bc2800

10 files changed

+231
-0
lines changed

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ a set of rules that precisely define a sequence of operations.
139139
* `B` [Jump Game](src/algorithms/uncategorized/jump-game) - backtracking, dynamic programming (top-down + bottom-up) and greedy examples
140140
* `B` [Unique Paths](src/algorithms/uncategorized/unique-paths) - backtracking, dynamic programming and Pascal's Triangle based examples
141141
* `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem (dynamic programming and brute force versions)
142+
* `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - count the number of ways to reach to the top (4 solutions)
142143
* `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens)
143144
* `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour)
144145

@@ -151,6 +152,7 @@ algorithm is an abstraction higher than a computer program.
151152
* **Brute Force** - look at all the possibilities and selects the best solution
152153
* `B` [Linear Search](src/algorithms/search/linear-search)
153154
* `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem
155+
* `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - count the number of ways to reach to the top
154156
* `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray)
155157
* `A` [Travelling Salesman Problem](src/algorithms/graph/travelling-salesman) - shortest possible route that visits each city and returns to the origin city
156158
* `A` [Discrete Fourier Transform](src/algorithms/math/fourier-transform) - decompose a function of time (a signal) into the frequencies that make it up
@@ -178,6 +180,7 @@ algorithm is an abstraction higher than a computer program.
178180
* `B` [Jump Game](src/algorithms/uncategorized/jump-game)
179181
* `B` [Unique Paths](src/algorithms/uncategorized/unique-paths)
180182
* `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem
183+
* `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - count the number of ways to reach to the top
181184
* `A` [Levenshtein Distance](src/algorithms/string/levenshtein-distance) - minimum edit distance between two sequences
182185
* `A` [Longest Common Subsequence](src/algorithms/sets/longest-common-subsequence) (LCS)
183186
* `A` [Longest Common Substring](src/algorithms/string/longest-common-substring)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Recursive Staircase Problem
2+
3+
## The Problem
4+
5+
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._
6+
7+
![](https://cdncontribute.geeksforgeeks.org/wp-content/uploads/nth-stair.png)
8+
9+
## The Solution
10+
11+
This is an interesting problem because there are several ways of how it may be solved that illustrate different programming paradigms.
12+
13+
- [Brute Force Recursive Solution](./recursiveStaircaseBF.js) - Time: `O(2^n)`; Space: `O(1)`
14+
- [Recursive Solution With Memoization](./recursiveStaircaseMEM.js) - Time: `O(n)`; Space: `O(n)`
15+
- [Dynamic Programming Solution](./recursiveStaircaseDP.js) - Time: `O(n)`; Space: `O(n)`
16+
- [Iterative Solution](./recursiveStaircaseIT.js) - Time: `O(n)`; Space: `O(1)`
17+
18+
## References
19+
20+
- [On YouTube by Gayle Laakmann McDowell](https://www.youtube.com/watch?v=eREiwuvzaUM&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=81&t=0s)
21+
- [GeeksForGeeks](https://www.geeksforgeeks.org/count-ways-reach-nth-stair/)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import recursiveStaircaseBF from '../recursiveStaircaseBF';
2+
3+
describe('recursiveStaircaseBF', () => {
4+
it('should calculate number of variants using Brute Force solution', () => {
5+
expect(recursiveStaircaseBF(-1)).toBe(0);
6+
expect(recursiveStaircaseBF(0)).toBe(0);
7+
expect(recursiveStaircaseBF(1)).toBe(1);
8+
expect(recursiveStaircaseBF(2)).toBe(2);
9+
expect(recursiveStaircaseBF(3)).toBe(3);
10+
expect(recursiveStaircaseBF(4)).toBe(5);
11+
expect(recursiveStaircaseBF(5)).toBe(8);
12+
expect(recursiveStaircaseBF(6)).toBe(13);
13+
expect(recursiveStaircaseBF(7)).toBe(21);
14+
expect(recursiveStaircaseBF(8)).toBe(34);
15+
expect(recursiveStaircaseBF(9)).toBe(55);
16+
expect(recursiveStaircaseBF(10)).toBe(89);
17+
});
18+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import recursiveStaircaseDP from '../recursiveStaircaseDP';
2+
3+
describe('recursiveStaircaseDP', () => {
4+
it('should calculate number of variants using Dynamic Programming solution', () => {
5+
expect(recursiveStaircaseDP(-1)).toBe(0);
6+
expect(recursiveStaircaseDP(0)).toBe(0);
7+
expect(recursiveStaircaseDP(1)).toBe(1);
8+
expect(recursiveStaircaseDP(2)).toBe(2);
9+
expect(recursiveStaircaseDP(3)).toBe(3);
10+
expect(recursiveStaircaseDP(4)).toBe(5);
11+
expect(recursiveStaircaseDP(5)).toBe(8);
12+
expect(recursiveStaircaseDP(6)).toBe(13);
13+
expect(recursiveStaircaseDP(7)).toBe(21);
14+
expect(recursiveStaircaseDP(8)).toBe(34);
15+
expect(recursiveStaircaseDP(9)).toBe(55);
16+
expect(recursiveStaircaseDP(10)).toBe(89);
17+
});
18+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import recursiveStaircaseIT from '../recursiveStaircaseIT';
2+
3+
describe('recursiveStaircaseIT', () => {
4+
it('should calculate number of variants using Iterative solution', () => {
5+
expect(recursiveStaircaseIT(-1)).toBe(0);
6+
expect(recursiveStaircaseIT(0)).toBe(0);
7+
expect(recursiveStaircaseIT(1)).toBe(1);
8+
expect(recursiveStaircaseIT(2)).toBe(2);
9+
expect(recursiveStaircaseIT(3)).toBe(3);
10+
expect(recursiveStaircaseIT(4)).toBe(5);
11+
expect(recursiveStaircaseIT(5)).toBe(8);
12+
expect(recursiveStaircaseIT(6)).toBe(13);
13+
expect(recursiveStaircaseIT(7)).toBe(21);
14+
expect(recursiveStaircaseIT(8)).toBe(34);
15+
expect(recursiveStaircaseIT(9)).toBe(55);
16+
expect(recursiveStaircaseIT(10)).toBe(89);
17+
});
18+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import recursiveStaircaseMEM from '../recursiveStaircaseMEM';
2+
3+
describe('recursiveStaircaseMEM', () => {
4+
it('should calculate number of variants using Brute Force with Memoization', () => {
5+
expect(recursiveStaircaseMEM(-1)).toBe(0);
6+
expect(recursiveStaircaseMEM(0)).toBe(0);
7+
expect(recursiveStaircaseMEM(1)).toBe(1);
8+
expect(recursiveStaircaseMEM(2)).toBe(2);
9+
expect(recursiveStaircaseMEM(3)).toBe(3);
10+
expect(recursiveStaircaseMEM(4)).toBe(5);
11+
expect(recursiveStaircaseMEM(5)).toBe(8);
12+
expect(recursiveStaircaseMEM(6)).toBe(13);
13+
expect(recursiveStaircaseMEM(7)).toBe(21);
14+
expect(recursiveStaircaseMEM(8)).toBe(34);
15+
expect(recursiveStaircaseMEM(9)).toBe(55);
16+
expect(recursiveStaircaseMEM(10)).toBe(89);
17+
});
18+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* Recursive Staircase Problem (Brute Force Solution).
3+
*
4+
* @param {number} stairsNum - Number of stairs to climb on.
5+
* @return {number} - Number of ways to climb a staircase.
6+
*/
7+
export default function recursiveStaircaseBF(stairsNum) {
8+
if (stairsNum <= 0) {
9+
// There is no way to go down - you climb the stairs only upwards.
10+
// Also if you're standing on the ground floor that you don't need to do any further steps.
11+
return 0;
12+
}
13+
14+
if (stairsNum === 1) {
15+
// There is only one way to go to the first step.
16+
return 1;
17+
}
18+
19+
if (stairsNum === 2) {
20+
// There are two ways to get to the second steps: (1 + 1) or (2).
21+
return 2;
22+
}
23+
24+
// Sum up how many steps we need to take after doing one step up with the number of
25+
// steps we need to take after doing two steps up.
26+
return recursiveStaircaseBF(stairsNum - 1) + recursiveStaircaseBF(stairsNum - 2);
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* Recursive Staircase Problem (Dynamic Programming Solution).
3+
*
4+
* @param {number} stairsNum - Number of stairs to climb on.
5+
* @return {number} - Number of ways to climb a staircase.
6+
*/
7+
export default function recursiveStaircaseDP(stairsNum) {
8+
if (stairsNum < 0) {
9+
// There is no way to go down - you climb the stairs only upwards.
10+
return 0;
11+
}
12+
13+
// Init the steps vector that will hold all possible ways to get to the corresponding step.
14+
const steps = new Array(stairsNum + 1).fill(0);
15+
16+
// Init the number of ways to get to the 0th, 1st and 2nd steps.
17+
steps[0] = 0;
18+
steps[1] = 1;
19+
steps[2] = 2;
20+
21+
if (stairsNum <= 2) {
22+
// Return the number of ways to get to the 0th or 1st or 2nd steps.
23+
return steps[stairsNum];
24+
}
25+
26+
// Calculate every next step based on two previous ones.
27+
for (let currentStep = 3; currentStep <= stairsNum; currentStep += 1) {
28+
steps[currentStep] = steps[currentStep - 1] + steps[currentStep - 2];
29+
}
30+
31+
// Return possible ways to get to the requested step.
32+
return steps[stairsNum];
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/**
2+
* Recursive Staircase Problem (Iterative Solution).
3+
*
4+
* @param {number} stairsNum - Number of stairs to climb on.
5+
* @return {number} - Number of ways to climb a staircase.
6+
*/
7+
export default function recursiveStaircaseIT(stairsNum) {
8+
if (stairsNum <= 0) {
9+
// There is no way to go down - you climb the stairs only upwards.
10+
// Also you don't need to do anything to stay on the 0th step.
11+
return 0;
12+
}
13+
14+
// Init the number of ways to get to the 0th, 1st and 2nd steps.
15+
const steps = [1, 2];
16+
17+
if (stairsNum <= 2) {
18+
// Return the number of possible ways of how to get to the 1st or 2nd steps.
19+
return steps[stairsNum - 1];
20+
}
21+
22+
// Calculate the number of ways to get to the n'th step based on previous ones.
23+
// Comparing to Dynamic Programming solution we don't store info for all the steps but
24+
// rather for two previous ones only.
25+
for (let currentStep = 3; currentStep <= stairsNum; currentStep += 1) {
26+
[steps[0], steps[1]] = [steps[1], steps[0] + steps[1]];
27+
}
28+
29+
// Return possible ways to get to the requested step.
30+
return steps[1];
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
* Recursive Staircase Problem (Recursive Solution With Memoization).
3+
*
4+
* @param {number} totalStairs - Number of stairs to climb on.
5+
* @return {number} - Number of ways to climb a staircase.
6+
*/
7+
export default function recursiveStaircaseMEM(totalStairs) {
8+
// Memo table that will hold all recursively calculated results to avoid calculating them
9+
// over and over again.
10+
const memo = [];
11+
12+
// Recursive closure.
13+
const getSteps = (stairsNum) => {
14+
if (stairsNum <= 0) {
15+
// There is no way to go down - you climb the stairs only upwards.
16+
// Also if you're standing on the ground floor that you don't need to do any further steps.
17+
return 0;
18+
}
19+
20+
if (stairsNum === 1) {
21+
// There is only one way to go to the first step.
22+
return 1;
23+
}
24+
25+
if (stairsNum === 2) {
26+
// There are two ways to get to the second steps: (1 + 1) or (2).
27+
return 2;
28+
}
29+
30+
// Avoid recursion for the steps that we've calculated recently.
31+
if (memo[stairsNum]) {
32+
return memo[stairsNum];
33+
}
34+
35+
// Sum up how many steps we need to take after doing one step up with the number of
36+
// steps we need to take after doing two steps up.
37+
memo[stairsNum] = getSteps(stairsNum - 1) + getSteps(stairsNum - 2);
38+
39+
return memo[stairsNum];
40+
};
41+
42+
// Return possible ways to get to the requested step.
43+
return getSteps(totalStairs);
44+
}

0 commit comments

Comments
 (0)