Skip to content

Commit 920d18d

Browse files
author
Gonzalo Diaz
committed
[Hacker Rank] Interview Preparation Kit: Recursion: Davis' Staircase. Test cases separated from test file. Test cases added. New test for generalized version.
1 parent d4659ed commit 920d18d

File tree

5 files changed

+156
-58
lines changed

5 files changed

+156
-58
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
@@ -36,3 +36,35 @@ so that repeated cases are not recalculated.
3636

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

src/hackerrank/interview_preparation_kit/recursion_and_backtracking/ctci_recursive_staircase.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# pylint: disable=line-too-long
22
# @link Problem definition [[docs/hackerrank/interview_preparation_kit/recursion_and_backtracking/ctci-recursive-staircase.md]] # noqa
3+
# @see Solution Notes: [[docs/hackerrank/interview_preparation_kit/recursion_and_backtracking/ctci-recursive-staircase-solution-notes.md]] # noqa
34
# pylint: enable=line-too-long
45

56
from typing import Dict
@@ -28,10 +29,7 @@ def step_perms_comput_with_cache(
2829
steps_limit
2930
)
3031

31-
result += cache[n_steps - i]
32-
33-
# if n_steps <= steps_limit:
34-
# result += 1
32+
result += cache[search_key]
3533

3634
return (result + 1) if n_steps <= steps_limit else result
3735

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
[
2+
{
3+
"title": "Sample Test case 0",
4+
"tests": [
5+
{
6+
"input": 1,
7+
"expected": 1
8+
},
9+
{
10+
"input": 3,
11+
"expected": 4
12+
},
13+
{
14+
"input": 7,
15+
"expected": 44
16+
}
17+
]
18+
},
19+
{
20+
"title": "Sample Test case 9",
21+
"tests": [
22+
{
23+
"input": 5,
24+
"expected": 13
25+
},
26+
{
27+
"input": 8,
28+
"expected": 81
29+
}
30+
]
31+
},
32+
{
33+
"title": "Sample Test case 10",
34+
"tests": [
35+
{
36+
"input": 15,
37+
"expected": 5768
38+
},
39+
{
40+
"input": 20,
41+
"expected": 121415
42+
},
43+
{
44+
"input": 27,
45+
"expected": 8646064
46+
}
47+
]
48+
}
49+
]
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+
]
Lines changed: 41 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,26 @@
11
import unittest
2-
from .ctci_recursive_staircase import step_perms
2+
import json
3+
from pathlib import Path
4+
from typing import Dict
5+
6+
from .ctci_recursive_staircase import step_perms, step_perms_comput_with_cache
37
from .ctci_recursive_staircase_alternative import step_perms as step_perms_alt
48

5-
TEST_CASES = [
6-
{
7-
'title': 'Sample Test case 0',
8-
'tests': [
9-
{
10-
'input': 1,
11-
'answer': 1
12-
},
13-
{
14-
'input': 3,
15-
'answer': 4
16-
},
17-
{
18-
'input': 7,
19-
'answer': 44
20-
}
21-
]
22-
},
23-
{
24-
'title': 'Sample Test case 9',
25-
'tests': [
26-
{
27-
'input': 5,
28-
'answer': 13
29-
},
30-
{
31-
'input': 8,
32-
'answer': 81
33-
}
34-
]
35-
},
36-
{
37-
'title': 'Sample Test case 10',
38-
'tests': [
39-
{
40-
'input': 15,
41-
'answer': 5768
42-
},
43-
{
44-
'input': 20,
45-
'answer': 121415
46-
},
47-
{
48-
'input': 27,
49-
'answer': 8646064
50-
}
51-
]
52-
}
53-
]
9+
FILE_PATH = str(Path(__file__).resolve().parent)
10+
11+
with open(
12+
FILE_PATH +
13+
'/ctci_recursive_staircase.testcases.json',
14+
encoding="utf-8"
15+
) as file1:
16+
TEST_CASES = json.load(file1)
17+
18+
with open(
19+
FILE_PATH +
20+
'/ctci_recursive_staircase_generalized.testcases.json',
21+
encoding="utf-8"
22+
) as file2:
23+
TEST_CASES_GENERALIZED = json.load(file2)
5424

5525

5626
class TestRecursionFibonacciNumbers(unittest.TestCase):
@@ -73,9 +43,26 @@ def test_step_perms(self):
7343
for _, _tt in enumerate(testset['tests']):
7444

7545
self.assertEqual(
76-
step_perms(_tt['input']), _tt['answer'],
46+
step_perms(_tt['input']), _tt['expected'],
7747
f"{_} | step_perms({_tt['input']}) must be "
78-
f"=> {_tt['answer']} in {testset['title']}")
48+
f"=> {_tt['expected']} in {testset['title']}")
49+
50+
def test_step_perms_comput_with_cache(self):
51+
52+
for _, testset in enumerate(TEST_CASES_GENERALIZED):
53+
54+
for _, _tt in enumerate(testset['tests']):
55+
56+
initial_cache: Dict[int, int] = {}
57+
58+
self.assertEqual(
59+
step_perms_comput_with_cache(
60+
_tt['input'], initial_cache,
61+
_tt['limit']),
62+
_tt['expected'],
63+
f"{_} | step_perms_comput_with_cache("
64+
f"{_tt['input']}, {initial_cache}, {_tt['limit']}) must be "
65+
f"=> {_tt['expected']} in {testset['title']}")
7966

8067
def test_step_perms_alt(self):
8168

@@ -84,6 +71,6 @@ def test_step_perms_alt(self):
8471
for _, _tt in enumerate(testset['tests']):
8572

8673
self.assertEqual(
87-
step_perms_alt(_tt['input']), _tt['answer'],
74+
step_perms_alt(_tt['input']), _tt['expected'],
8875
f"{_} | step_perms_alt({_tt['input']}) must be "
89-
f"=> {_tt['answer']} in {testset['title']}")
76+
f"=> {_tt['expected']} in {testset['title']}")

0 commit comments

Comments
 (0)