Add Recursive Staircase Problem.

This commit is contained in:
Oleksii Trekhleb 2018-11-14 17:45:14 +02:00
parent 5e0e571a5c
commit 9bc2800848
10 changed files with 231 additions and 0 deletions

View File

@ -139,6 +139,7 @@ a set of rules that precisely define a sequence of operations.
* `B` [Jump Game](src/algorithms/uncategorized/jump-game) - backtracking, dynamic programming (top-down + bottom-up) and greedy examples * `B` [Jump Game](src/algorithms/uncategorized/jump-game) - backtracking, dynamic programming (top-down + bottom-up) and greedy examples
* `B` [Unique Paths](src/algorithms/uncategorized/unique-paths) - backtracking, dynamic programming and Pascal's Triangle based examples * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths) - backtracking, dynamic programming and Pascal's Triangle based examples
* `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem (dynamic programming and brute force versions) * `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem (dynamic programming and brute force versions)
* `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - count the number of ways to reach to the top (4 solutions)
* `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens) * `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens)
* `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour) * `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour)
@ -151,6 +152,7 @@ algorithm is an abstraction higher than a computer program.
* **Brute Force** - look at all the possibilities and selects the best solution * **Brute Force** - look at all the possibilities and selects the best solution
* `B` [Linear Search](src/algorithms/search/linear-search) * `B` [Linear Search](src/algorithms/search/linear-search)
* `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem * `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem
* `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - count the number of ways to reach to the top
* `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray) * `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray)
* `A` [Travelling Salesman Problem](src/algorithms/graph/travelling-salesman) - shortest possible route that visits each city and returns to the origin city * `A` [Travelling Salesman Problem](src/algorithms/graph/travelling-salesman) - shortest possible route that visits each city and returns to the origin city
* `A` [Discrete Fourier Transform](src/algorithms/math/fourier-transform) - decompose a function of time (a signal) into the frequencies that make it up * `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.
* `B` [Jump Game](src/algorithms/uncategorized/jump-game) * `B` [Jump Game](src/algorithms/uncategorized/jump-game)
* `B` [Unique Paths](src/algorithms/uncategorized/unique-paths) * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths)
* `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem * `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem
* `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - count the number of ways to reach to the top
* `A` [Levenshtein Distance](src/algorithms/string/levenshtein-distance) - minimum edit distance between two sequences * `A` [Levenshtein Distance](src/algorithms/string/levenshtein-distance) - minimum edit distance between two sequences
* `A` [Longest Common Subsequence](src/algorithms/sets/longest-common-subsequence) (LCS) * `A` [Longest Common Subsequence](src/algorithms/sets/longest-common-subsequence) (LCS)
* `A` [Longest Common Substring](src/algorithms/string/longest-common-substring) * `A` [Longest Common Substring](src/algorithms/string/longest-common-substring)

View File

@ -0,0 +1,21 @@
# Recursive Staircase Problem
## 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._
![](https://cdncontribute.geeksforgeeks.org/wp-content/uploads/nth-stair.png)
## 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](./recursiveStaircaseBF.js) - Time: `O(2^n)`; Space: `O(1)`
- [Recursive Solution With Memoization](./recursiveStaircaseMEM.js) - Time: `O(n)`; Space: `O(n)`
- [Dynamic Programming Solution](./recursiveStaircaseDP.js) - Time: `O(n)`; Space: `O(n)`
- [Iterative Solution](./recursiveStaircaseIT.js) - Time: `O(n)`; Space: `O(1)`
## References
- [On YouTube by Gayle Laakmann McDowell](https://www.youtube.com/watch?v=eREiwuvzaUM&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=81&t=0s)
- [GeeksForGeeks](https://www.geeksforgeeks.org/count-ways-reach-nth-stair/)

View File

@ -0,0 +1,18 @@
import recursiveStaircaseBF from '../recursiveStaircaseBF';
describe('recursiveStaircaseBF', () => {
it('should calculate number of variants using Brute Force solution', () => {
expect(recursiveStaircaseBF(-1)).toBe(0);
expect(recursiveStaircaseBF(0)).toBe(0);
expect(recursiveStaircaseBF(1)).toBe(1);
expect(recursiveStaircaseBF(2)).toBe(2);
expect(recursiveStaircaseBF(3)).toBe(3);
expect(recursiveStaircaseBF(4)).toBe(5);
expect(recursiveStaircaseBF(5)).toBe(8);
expect(recursiveStaircaseBF(6)).toBe(13);
expect(recursiveStaircaseBF(7)).toBe(21);
expect(recursiveStaircaseBF(8)).toBe(34);
expect(recursiveStaircaseBF(9)).toBe(55);
expect(recursiveStaircaseBF(10)).toBe(89);
});
});

View File

@ -0,0 +1,18 @@
import recursiveStaircaseDP from '../recursiveStaircaseDP';
describe('recursiveStaircaseDP', () => {
it('should calculate number of variants using Dynamic Programming solution', () => {
expect(recursiveStaircaseDP(-1)).toBe(0);
expect(recursiveStaircaseDP(0)).toBe(0);
expect(recursiveStaircaseDP(1)).toBe(1);
expect(recursiveStaircaseDP(2)).toBe(2);
expect(recursiveStaircaseDP(3)).toBe(3);
expect(recursiveStaircaseDP(4)).toBe(5);
expect(recursiveStaircaseDP(5)).toBe(8);
expect(recursiveStaircaseDP(6)).toBe(13);
expect(recursiveStaircaseDP(7)).toBe(21);
expect(recursiveStaircaseDP(8)).toBe(34);
expect(recursiveStaircaseDP(9)).toBe(55);
expect(recursiveStaircaseDP(10)).toBe(89);
});
});

View File

@ -0,0 +1,18 @@
import recursiveStaircaseIT from '../recursiveStaircaseIT';
describe('recursiveStaircaseIT', () => {
it('should calculate number of variants using Iterative solution', () => {
expect(recursiveStaircaseIT(-1)).toBe(0);
expect(recursiveStaircaseIT(0)).toBe(0);
expect(recursiveStaircaseIT(1)).toBe(1);
expect(recursiveStaircaseIT(2)).toBe(2);
expect(recursiveStaircaseIT(3)).toBe(3);
expect(recursiveStaircaseIT(4)).toBe(5);
expect(recursiveStaircaseIT(5)).toBe(8);
expect(recursiveStaircaseIT(6)).toBe(13);
expect(recursiveStaircaseIT(7)).toBe(21);
expect(recursiveStaircaseIT(8)).toBe(34);
expect(recursiveStaircaseIT(9)).toBe(55);
expect(recursiveStaircaseIT(10)).toBe(89);
});
});

View File

@ -0,0 +1,18 @@
import recursiveStaircaseMEM from '../recursiveStaircaseMEM';
describe('recursiveStaircaseMEM', () => {
it('should calculate number of variants using Brute Force with Memoization', () => {
expect(recursiveStaircaseMEM(-1)).toBe(0);
expect(recursiveStaircaseMEM(0)).toBe(0);
expect(recursiveStaircaseMEM(1)).toBe(1);
expect(recursiveStaircaseMEM(2)).toBe(2);
expect(recursiveStaircaseMEM(3)).toBe(3);
expect(recursiveStaircaseMEM(4)).toBe(5);
expect(recursiveStaircaseMEM(5)).toBe(8);
expect(recursiveStaircaseMEM(6)).toBe(13);
expect(recursiveStaircaseMEM(7)).toBe(21);
expect(recursiveStaircaseMEM(8)).toBe(34);
expect(recursiveStaircaseMEM(9)).toBe(55);
expect(recursiveStaircaseMEM(10)).toBe(89);
});
});

View File

@ -0,0 +1,27 @@
/**
* 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);
}

View File

@ -0,0 +1,33 @@
/**
* 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];
}

View File

@ -0,0 +1,31 @@
/**
* 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];
}

View File

@ -0,0 +1,44 @@
/**
* 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);
}