Skip to content

Commit

Permalink
[Hacker Rank] Interview Preparation Kit: Recursion: Davis' Staircase.…
Browse files Browse the repository at this point in the history
… Solved ✅.
  • Loading branch information
Gonzalo Diaz committed Aug 6, 2024
1 parent 245ca59 commit a0ab698
Show file tree
Hide file tree
Showing 5 changed files with 255 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -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.
Original file line number Diff line number Diff line change
@@ -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.
Original file line number Diff line number Diff line change
@@ -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);
});
});
});
});
Original file line number Diff line number Diff line change
@@ -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
}
]
}
]
Original file line number Diff line number Diff line change
@@ -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, number>
): 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<number, number> = {};
return step_perms_comput_with_cache(n, initial_cache) % (10 ** 10 + 7);
}

export default { stepPerms };

0 comments on commit a0ab698

Please sign in to comment.