Skip to content

Commit 2fd8921

Browse files
author
Gonzalo Diaz
committed
[Hacker Rank] Interview Preparation Kit: Recursion: Davis' Staircase. Clean code improvements and new generalized solution.
1 parent a0ab698 commit 2fd8921

File tree

4 files changed

+107
-12
lines changed

4 files changed

+107
-12
lines changed

docs/hackerrank/interview_preparation_kit/recursion_and_backtracking/ctci-recursive-staircase-solution-notes.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,35 @@ so that repeated cases are not recalculated.
4040

4141
The trade-off is that the algorithm now requires
4242
more memory to run in less time.
43+
44+
## Generalized solution
45+
46+
In order to comply with some clean code best practices,
47+
I noticed that the step limit in the algorithm is a hard-coded number,
48+
so to comply with the "no magic numbers" rule,
49+
I was forced to find a more generalized solution.
50+
51+
Then I found the following pattern:
52+
53+
- First cases are:
54+
55+
$$ \begin{matrix}
56+
\text{stepPerms(0)} = 0 \\
57+
\text{stepPerms(1)} = 1 \\
58+
\text{stepPerms(2)} = 2 \\
59+
\end{matrix}
60+
$$
61+
62+
- Next step combinations above 2 and less than the step limit are:
63+
64+
$$ \text{stepPerms(number of steps)} = 2^\text{number of steps} + 1 $$
65+
66+
- When `number of steps` are above the limit, the pattern is
67+
the sum of latest `number of steps` previous calls of
68+
`stepPerms(x)` results as follows:
69+
70+
$$ \displaystyle\sum_{
71+
i=\text{number of steps} - \text{limit}}
72+
^\text{number of steps}
73+
stepPerms(\text{number of steps} - i)
74+
$$

src/hackerrank/interview_preparation_kit/recursion_and_backtracking/ctci_recursive_staircase.test.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
import { describe, expect, it } from '@jest/globals';
22
import { logger as console } from '../../../logger';
33

4-
import { stepPerms } from './ctci_recursive_staircase';
4+
import {
5+
stepPerms,
6+
step_perms_comput_with_cache
7+
} from './ctci_recursive_staircase';
58
import TEST_CASES from './ctci_recursive_staircase.testcases.json';
9+
import TEST_CASES_GENERALIZED from './ctci_recursive_staircase_generalized.testcases.json';
610

711
describe('ctci_recursive_staircase', () => {
812
it('stepPerms test cases', () => {
@@ -18,4 +22,25 @@ describe('ctci_recursive_staircase', () => {
1822
});
1923
});
2024
});
25+
26+
it('step_perms_comput_with_cache test cases', () => {
27+
expect.assertions(3);
28+
29+
TEST_CASES_GENERALIZED.forEach((testSet) => {
30+
testSet?.tests.forEach((test) => {
31+
const initial_cache: Record<number, number> = {};
32+
const answer = step_perms_comput_with_cache(
33+
test.input,
34+
initial_cache,
35+
test.limit
36+
);
37+
38+
console.debug(
39+
`step_perms_comput_with_cache(${test.input}, ${initial_cache}, ${test.limit}) solution found: ${answer}`
40+
);
41+
42+
expect(answer).toStrictEqual(test.expected);
43+
});
44+
});
45+
});
2146
});

src/hackerrank/interview_preparation_kit/recursion_and_backtracking/ctci_recursive_staircase.ts

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,36 +3,42 @@
33
* @see Solution Notes: [[docs/hackerrank/interview_preparation_kit/recursion_and_backtracking/ctci-recursive-staircase-solution-notes.md]]
44
*/
55

6-
function step_perms_comput_with_cache(
6+
const TOP_LIMIT = 10 ** 10 + 7;
7+
const STEPS_LIMIT = 3;
8+
9+
export function step_perms_comput_with_cache(
710
n_steps: number,
8-
cache: Record<number, number>
11+
cache: Record<number, number>,
12+
steps_limit: number
913
): number {
1014
if (0 <= n_steps && n_steps <= 2) {
1115
return n_steps;
1216
}
1317

14-
if (n_steps == 3) {
15-
return 4;
16-
}
17-
1818
const keys = new Set(Object.values(cache));
1919
let result = 0;
2020

21-
for (let i = 1; i < 4; i++) {
21+
for (let i = 1; i <= Math.min(steps_limit, n_steps); i++) {
2222
const searchKey = n_steps - i;
2323
if (!keys.has(searchKey)) {
24-
cache[n_steps - i] = step_perms_comput_with_cache(searchKey, cache);
24+
cache[searchKey] = step_perms_comput_with_cache(
25+
searchKey,
26+
cache,
27+
steps_limit
28+
);
2529
}
2630

2731
result += cache[searchKey];
2832
}
2933

30-
return result;
34+
return result + (n_steps <= steps_limit ? 1 : 0);
3135
}
3236

3337
export function stepPerms(n: number): number {
3438
const initial_cache: Record<number, number> = {};
35-
return step_perms_comput_with_cache(n, initial_cache) % (10 ** 10 + 7);
39+
return (
40+
step_perms_comput_with_cache(n, initial_cache, STEPS_LIMIT) % TOP_LIMIT
41+
);
3642
}
3743

38-
export default { stepPerms };
44+
export default { stepPerms, step_perms_comput_with_cache };
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
[
2+
{
3+
"title": "Own sample 1",
4+
"tests": [
5+
{
6+
"input": 4,
7+
"limit": 3,
8+
"expected": 7
9+
}
10+
]
11+
},
12+
{
13+
"title": "Own sample 2",
14+
"tests": [
15+
{
16+
"input": 5,
17+
"limit": 4,
18+
"expected": 15
19+
}
20+
]
21+
},
22+
{
23+
"title": "Own sample 3",
24+
"tests": [
25+
{
26+
"input": 6,
27+
"limit": 2,
28+
"expected": 13
29+
}
30+
]
31+
}
32+
]

0 commit comments

Comments
 (0)