From a0ab6983aa5f819f0e486a266cc1a3e85ec9f27e Mon Sep 17 00:00:00 2001 From: Gonzalo Diaz Date: Tue, 6 Aug 2024 15:25:48 -0400 Subject: [PATCH] =?UTF-8?q?[Hacker=20Rank]=20Interview=20Preparation=20Kit?= =?UTF-8?q?:=20Recursion:=20Davis'=20Staircase.=20Solved=20=E2=9C=85.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ctci-recursive-staircase-solution-notes.md | 42 +++++++ .../ctci-recursive-staircase.md | 105 ++++++++++++++++++ .../ctci_recursive_staircase.test.ts | 21 ++++ .../ctci_recursive_staircase.testcases.json | 49 ++++++++ .../ctci_recursive_staircase.ts | 38 +++++++ 5 files changed, 255 insertions(+) create mode 100644 docs/hackerrank/interview_preparation_kit/recursion_and_backtracking/ctci-recursive-staircase-solution-notes.md create mode 100644 docs/hackerrank/interview_preparation_kit/recursion_and_backtracking/ctci-recursive-staircase.md create mode 100644 src/hackerrank/interview_preparation_kit/recursion_and_backtracking/ctci_recursive_staircase.test.ts create mode 100644 src/hackerrank/interview_preparation_kit/recursion_and_backtracking/ctci_recursive_staircase.testcases.json create mode 100644 src/hackerrank/interview_preparation_kit/recursion_and_backtracking/ctci_recursive_staircase.ts diff --git a/docs/hackerrank/interview_preparation_kit/recursion_and_backtracking/ctci-recursive-staircase-solution-notes.md b/docs/hackerrank/interview_preparation_kit/recursion_and_backtracking/ctci-recursive-staircase-solution-notes.md new file mode 100644 index 00000000..0948b705 --- /dev/null +++ b/docs/hackerrank/interview_preparation_kit/recursion_and_backtracking/ctci-recursive-staircase-solution-notes.md @@ -0,0 +1,42 @@ +# [Recursion: Davis' Staircase](https://www.hackerrank.com/challenges/ctci-recursive-staircase) + +Find the number of ways to get from the bottom of a staircase +to the top if you can jump 1, 2, or 3 stairs at a time. + +- Difficulty: `#medium` +- Category: `#ProblemSolvingIntermediate` + +## Failed solution + +This solution correctly calculates the result. The problem is its performance, +since due to the traversal of the recursion tree, +it is eventually easy to reach repeated cases that are recalculated each time. + +```typescript +def step_perms_compute(n: number): number + if (n == 0) { + return 0 + } + if (n == 1) { + return 1 + } + if (n == 2) { + return 2 + } + if (n == 3) { + return 4 + } + + return + step_perms_compute(n - 3) + + step_perms_compute(n - 2) + + step_perms_compute(n - 1) +``` + +## Alternative solution + +The final solution introduces a simple caching mechanism, +so that repeated cases are not recalculated. + +The trade-off is that the algorithm now requires +more memory to run in less time. diff --git a/docs/hackerrank/interview_preparation_kit/recursion_and_backtracking/ctci-recursive-staircase.md b/docs/hackerrank/interview_preparation_kit/recursion_and_backtracking/ctci-recursive-staircase.md new file mode 100644 index 00000000..3018fbaf --- /dev/null +++ b/docs/hackerrank/interview_preparation_kit/recursion_and_backtracking/ctci-recursive-staircase.md @@ -0,0 +1,105 @@ +# [Recursion: Davis' Staircase](https://www.hackerrank.com/challenges/ctci-recursive-staircase) + +Find the number of ways to get from the bottom of a staircase +to the top if you can jump 1, 2, or 3 stairs at a time. + +- Difficulty: `#medium` +- Category: `#ProblemSolvingIntermediate` + +Davis has a number of staircases in his house and he likes to +climb each staircase `1`, `2`, or `3` steps at a time. +Being a very precocious child, he wonders how many ways there +are to reach the top of the staircase. + +Given the respective heights for each of the staircases in his house, +find and print the number of ways he can climb each staircase, +module $10^10 + 7 $ on a new line. + +## Example + +`n = 5` + +The staircase has `5` steps. Davis can step on the following sequences of steps: + +```text +1 1 1 1 1 +1 1 1 2 +1 1 2 1 +1 2 1 1 +2 1 1 1 +1 2 2 +2 2 1 +2 1 2 +1 1 3 +1 3 1 +3 1 1 +2 3 +3 2 +``` + +There are `13` possible ways he can take these `5` steps and `13 modulo 10000000007` + +## Function Description + +Complete the stepPerms function using recursion in the editor below. + +stepPerms has the following parameter(s): + +- int n: the number of stairs in the staircase + +## Returns + +int: the number of ways Davis can climb the staircase, modulo 10000000007 + +## Input Format + +The first line contains a single integer, `s`, the number of staircases in his house. +Each of the following `s` lines contains a single integer, +`n`, the height of staircase `i`. + +## Constraints + +- $ 1 \leq s \leq 5 $ +- $ 1 \leq n \leq 36 $ + +## Subtasks + +- 1 \leq n \leq 20 for `50%` of the maximum score. + +## Sample Input + +```text +STDIN Function +----- -------- +3 s = 3 (number of staircases) +1 first staircase n = 1 +3 second n = 3 +7 third n = 7 +``` + +## Sample Output + +```text +1 +4 +44 +``` + +## Explanation + +Let's calculate the number of ways of climbing +the first two of the Davis' `s = 3` staircases: + +1. The first staircase only has `n = 1` step, + so there is only one way for him to + climb it (i.e., by jumping `1` step). Thus, we print `1` on a new line. + +2. The second staircase has `n = 3` steps and he can climb it in any of the + four following ways: + + 1. 1 -> 1 -> 1 + 2. 1 -> 2 + 3. 2 -> 1 + 4. 3 + +Thus, we print `4` on a new line. diff --git a/src/hackerrank/interview_preparation_kit/recursion_and_backtracking/ctci_recursive_staircase.test.ts b/src/hackerrank/interview_preparation_kit/recursion_and_backtracking/ctci_recursive_staircase.test.ts new file mode 100644 index 00000000..db471c24 --- /dev/null +++ b/src/hackerrank/interview_preparation_kit/recursion_and_backtracking/ctci_recursive_staircase.test.ts @@ -0,0 +1,21 @@ +import { describe, expect, it } from '@jest/globals'; +import { logger as console } from '../../../logger'; + +import { stepPerms } from './ctci_recursive_staircase'; +import TEST_CASES from './ctci_recursive_staircase.testcases.json'; + +describe('ctci_recursive_staircase', () => { + it('stepPerms test cases', () => { + expect.assertions(8); + + TEST_CASES.forEach((testSet) => { + testSet?.tests.forEach((test) => { + const answer = stepPerms(test.input); + + console.debug(`stepPerms(${test.input}) solution found: ${answer}`); + + expect(answer).toStrictEqual(test.expected); + }); + }); + }); +}); diff --git a/src/hackerrank/interview_preparation_kit/recursion_and_backtracking/ctci_recursive_staircase.testcases.json b/src/hackerrank/interview_preparation_kit/recursion_and_backtracking/ctci_recursive_staircase.testcases.json new file mode 100644 index 00000000..120ef099 --- /dev/null +++ b/src/hackerrank/interview_preparation_kit/recursion_and_backtracking/ctci_recursive_staircase.testcases.json @@ -0,0 +1,49 @@ +[ + { + "title": "Sample Test case 0", + "tests": [ + { + "input": 1, + "expected": 1 + }, + { + "input": 3, + "expected": 4 + }, + { + "input": 7, + "expected": 44 + } + ] + }, + { + "title": "Sample Test case 9", + "tests": [ + { + "input": 5, + "expected": 13 + }, + { + "input": 8, + "expected": 81 + } + ] + }, + { + "title": "Sample Test case 10", + "tests": [ + { + "input": 15, + "expected": 5768 + }, + { + "input": 20, + "expected": 121415 + }, + { + "input": 27, + "expected": 8646064 + } + ] + } +] diff --git a/src/hackerrank/interview_preparation_kit/recursion_and_backtracking/ctci_recursive_staircase.ts b/src/hackerrank/interview_preparation_kit/recursion_and_backtracking/ctci_recursive_staircase.ts new file mode 100644 index 00000000..3d5100a7 --- /dev/null +++ b/src/hackerrank/interview_preparation_kit/recursion_and_backtracking/ctci_recursive_staircase.ts @@ -0,0 +1,38 @@ +/** + * @link Problem definition [[docs/hackerrank/interview_preparation_kit/recursion_and_backtracking/ctci-recursive-staircase.md]] + * @see Solution Notes: [[docs/hackerrank/interview_preparation_kit/recursion_and_backtracking/ctci-recursive-staircase-solution-notes.md]] + */ + +function step_perms_comput_with_cache( + n_steps: number, + cache: Record +): number { + if (0 <= n_steps && n_steps <= 2) { + return n_steps; + } + + if (n_steps == 3) { + return 4; + } + + const keys = new Set(Object.values(cache)); + let result = 0; + + for (let i = 1; i < 4; i++) { + const searchKey = n_steps - i; + if (!keys.has(searchKey)) { + cache[n_steps - i] = step_perms_comput_with_cache(searchKey, cache); + } + + result += cache[searchKey]; + } + + return result; +} + +export function stepPerms(n: number): number { + const initial_cache: Record = {}; + return step_perms_comput_with_cache(n, initial_cache) % (10 ** 10 + 7); +} + +export default { stepPerms };