mirror of
https://github.moeyy.xyz/https://github.com/trekhleb/javascript-algorithms.git
synced 2024-12-26 07:01:18 +08:00
Add Recursive Staircase Problem.
This commit is contained in:
parent
5e0e571a5c
commit
9bc2800848
@ -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` [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` [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` [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
|
||||
* `B` [Linear Search](src/algorithms/search/linear-search)
|
||||
* `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` [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
|
||||
@ -178,6 +180,7 @@ algorithm is an abstraction higher than a computer program.
|
||||
* `B` [Jump Game](src/algorithms/uncategorized/jump-game)
|
||||
* `B` [Unique Paths](src/algorithms/uncategorized/unique-paths)
|
||||
* `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` [Longest Common Subsequence](src/algorithms/sets/longest-common-subsequence) (LCS)
|
||||
* `A` [Longest Common Substring](src/algorithms/string/longest-common-substring)
|
||||
|
21
src/algorithms/uncategorized/recursive-staircase/README.md
Normal file
21
src/algorithms/uncategorized/recursive-staircase/README.md
Normal 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/)
|
@ -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);
|
||||
});
|
||||
});
|
@ -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);
|
||||
});
|
||||
});
|
@ -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);
|
||||
});
|
||||
});
|
@ -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);
|
||||
});
|
||||
});
|
@ -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);
|
||||
}
|
@ -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];
|
||||
}
|
@ -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];
|
||||
}
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user