Skip to content

Commit 0f42047

Browse files
authored
Merge pull request #438 from sir-gon/feature/ctci-ice-cream-parlor
Feature/ctci ice cream parlor
2 parents 90aa172 + b966912 commit 0f42047

10 files changed

+469
-0
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# [Hash Tables: Ice Cream Parlor](https://www.hackerrank.com/challenges/ctci-ice-cream-parlor)
2+
3+
- Difficulty: `#medium`
4+
- Category: `#ProblemSolvingIntermediate`
5+
6+
## Failed tries
7+
8+
### Brute force
9+
10+
First attempt: Brute force. Complexity O(n^2)
11+
Fails to pass additional test cases due to excessive time.
12+
13+
### Binary search
14+
15+
This attempt use the editorial suggestion: do a binary search.
16+
17+
For each flavor of ice cream on the cost list, the searched one
18+
is "trimmed" in a search from half (then half of half and so on) of the list.
19+
Complexity O(log n)
20+
21+
For some reason that I have not reviewed in detail,
22+
it works with the test cases in the examples,
23+
but fails in the result with all the hidden test cases.
24+
25+
The preliminary guess is that the "edges" may be poorly thought out,
26+
and it may also not properly account for cases where there may be
27+
"repeated" values in the search.
28+
29+
## Editorial-based solution
30+
31+
Using editorial C++ based solution, I can notice about that solution in O(n) space,
32+
realy do 3 times (3*O(n)) pass over data list.
33+
34+
## Final working solution
35+
36+
This solution has a complexity of O(N) in just one iteration.
37+
It is based on a very simple idea.
38+
39+
A dictionary (key-value object) is created.
40+
41+
Then for each item (current ice cream):
42+
43+
- The difference between the budget and the current item is calculated.
44+
It tells us the value of the element to search for.
45+
46+
- We look for the element if it is in the "cache" (dictionary).
47+
We look for the value of the current element among the cache keys.
48+
49+
- If the element is NOT found in the dictionary,
50+
then we store the currently searched element in the cache,
51+
using the element's value as the cache key and the position
52+
(what we care about returning) as the cache value.
53+
54+
If the element is found, then we return the key of the current element
55+
and the key of the element found in the cache.
56+
57+
This mechanism also returns the smallest element that matches,
58+
in the case of repeated values (because the search is from start to finish,
59+
without reordering). In the case of passing by repeated values,
60+
the current element to be stored in the cache,
61+
steps on the previous position value with the new one,
62+
but since it is not the searched value, it is irrelevant.
63+
64+
- Source: [Hackerrank Hash Tables - Ice Cream Parlor Python solution](https://medium.com/@xww0701/hackerrank-hash-tables-ice-cream-parlor-python-solution-fac434523ec7)
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# [Hash Tables: Ice Cream Parlor](https://www.hackerrank.com/challenges/ctci-ice-cream-parlor)
2+
3+
- Difficulty: `#medium`
4+
- Category: `#ProblemSolvingIntermediate`
5+
6+
Each time Sunny and Johnny take a trip to the Ice Cream Parlor,
7+
they pool their money to buy ice cream.
8+
On any given day, the parlor offers a line of flavors.
9+
Each flavor has a cost associated with it.
10+
11+
Given the value of `money` and the `cost` of each flavor for `t`
12+
trips to the Ice Cream Parlor, help Sunny and Johnny choose two
13+
distinct flavors such that they spend their entire pool of money during each visit.
14+
ID numbers are the 1-based index number associated with a `cost`.
15+
For each trip to the parlor, print the ID numbers for the two
16+
types of ice cream that Sunny and Johnny purchase as
17+
two space-separated integers on a new line. You must print the smaller
18+
ID first and the larger ID second.
19+
20+
## Example
21+
22+
`cost = [2, 1, 3, 5, 6]`
23+
24+
`money = 5`
25+
26+
They would purchase flavor ID's `1` and `3` for a cost of `2 + 3 = 5`.
27+
Use 1-based indexing for your response.
28+
29+
**Note**:
30+
31+
- Two ice creams having unique IDs and may have the same cost
32+
(i.e., $ cost[i] \equiv cost[j] $).
33+
34+
- There will always be a unique solution.
35+
36+
## Function Description
37+
38+
Complete the function whatFlavors in the editor below.
39+
40+
whatFlavors has the following parameter(s):
41+
42+
- `int cost[n]`: the prices for each flavor
43+
- `int money`: the amount of money they have to spend
44+
45+
## Prints
46+
47+
- `int int`: the indices of the two flavors they will purchase as
48+
two space-separated integers on a line
49+
50+
## Input Format
51+
52+
The first line contains an integer, `t`, the number of trips to the ice cream parlor.
53+
54+
Each of the next sets of lines is as follows:
55+
56+
- The first line contains `money`.
57+
- The second line contains an integer, `n`, the size of the array `cost`.
58+
- The third line contains `n` space-separated integers denoting the `cost[i]`.
59+
60+
## Constraints
61+
62+
- $ 1 \leq t \leq 50$
63+
- $ 2 \leq money \leq 10^9 $
64+
- $ 2 \leq n \leq 5 * 10^4 $
65+
- $ 1 \leq cost[i] \leq 10^9 $
66+
67+
## Sample Input
68+
69+
```text
70+
STDIN Function
71+
----- --------
72+
2 t = 2
73+
4 money = 4
74+
5 cost[] size n = 5
75+
1 4 5 3 2 cost = [1, 4, 5, 3, 2]
76+
4 money = 4
77+
4 cost[] size n = 4
78+
2 2 4 3 cost = [2, 2, 4, 3]
79+
```
80+
81+
## Sample Output
82+
83+
```text
84+
1 4
85+
1 2
86+
```
87+
88+
## Explanation
89+
90+
Sunny and Johnny make the following two trips to the parlor:
91+
92+
1. The first time, they pool together $ money = 4 $ dollars.
93+
There are five flavors available that day and
94+
flavors `1` and `4` have a total cost of `1 + 3 = 4`.
95+
2. The second time, they pool together `money = 4` dollars.
96+
There are four flavors available that day and
97+
flavors `1` and `2` have a total cost of `2 + 2 = 4`.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[
2+
{
3+
"title": "Sample Test Case 0",
4+
"tests": [
5+
{
6+
"costs": [1, 4, 5, 3, 2],
7+
"money": 90,
8+
"expected": []
9+
}
10+
]
11+
}
12+
]
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { describe, expect, it } from '@jest/globals';
2+
import { logger as console } from '../../../logger';
3+
4+
import { whatFlavors, whatFlavorsCompute } from './ctci_ice_cream_parlor';
5+
import TEST_CASES from './ctci_ice_cream_parlor.testcases.json';
6+
import TEST_CASES_BORDER_CASES from './ctci_ice_cream_parlor.border_testcases.json';
7+
8+
describe('ctci_ice_cream_parlor', () => {
9+
it('whatFlavorsCompute test cases', () => {
10+
expect.assertions(10);
11+
12+
TEST_CASES.forEach((testSet) => {
13+
testSet?.tests.forEach((test) => {
14+
const answer = whatFlavorsCompute(test.costs, test.money);
15+
16+
console.debug(
17+
`whatFlavorsCompute(${test.costs}, ${test.money}) solution found: ${answer}`
18+
);
19+
20+
expect(answer).toStrictEqual(test.expected);
21+
expect(whatFlavors(test.costs, test.money)).toBeUndefined();
22+
});
23+
});
24+
});
25+
26+
it('whatFlavors border test cases', () => {
27+
expect.assertions(2);
28+
29+
TEST_CASES_BORDER_CASES.forEach((testSet) => {
30+
testSet?.tests.forEach((test) => {
31+
expect(whatFlavorsCompute(test.costs, test.money)).toStrictEqual(
32+
test.expected
33+
);
34+
expect(whatFlavors(test.costs, test.money)).toBeUndefined();
35+
});
36+
});
37+
});
38+
39+
it('whatFlavors test caller function', () => {
40+
expect.assertions(1);
41+
42+
const cost: number[] = [];
43+
const money: number = 100;
44+
45+
expect(whatFlavors(cost, money)).toBeUndefined();
46+
});
47+
});
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
[
2+
{
3+
"title": "Sample Test Case 0",
4+
"tests": [
5+
{
6+
"costs": [1, 4, 5, 3, 2],
7+
"money": 4,
8+
"expected": [1, 4]
9+
},
10+
{
11+
"costs": [2, 2, 4, 3],
12+
"money": 4,
13+
"expected": [1, 2]
14+
}
15+
]
16+
},
17+
{
18+
"title": "Sample Test Case 1",
19+
"tests": [
20+
{
21+
"costs": [1, 2, 3, 5, 6],
22+
"money": 5,
23+
"expected": [2, 3]
24+
}
25+
]
26+
},
27+
{
28+
"title": "Sample Test Case 2",
29+
"tests": [
30+
{
31+
"costs": [4, 3, 2, 5, 7],
32+
"money": 8,
33+
"expected": [2, 4]
34+
},
35+
{
36+
"costs": [7, 2, 5, 4, 11],
37+
"money": 12,
38+
"expected": [1, 3]
39+
}
40+
]
41+
}
42+
]
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/**
2+
* @link Problem definition [[docs/hackerrank/interview_preparation_kit/search/ctci-ice-cream-parlor.md]]
3+
*/
4+
5+
export function whatFlavorsCompute(
6+
cost: number[],
7+
money: number
8+
): number[] | null {
9+
const cache: Record<number, number> = {};
10+
11+
for (const [key, price] of Object.entries(cost)) {
12+
const i = parseInt(key);
13+
const diff = money - price;
14+
15+
if (Number.isInteger(cache?.[diff])) {
16+
return [i + 1, cache[diff] + 1].sort((a, b) => a - b);
17+
}
18+
19+
cache[price] = i;
20+
}
21+
22+
return [];
23+
}
24+
25+
export function whatFlavors(cost: number[], money: number): void {
26+
console.log(whatFlavorsCompute(cost, money)?.join(' '));
27+
}
28+
29+
export default { whatFlavorsCompute, whatFlavors };
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { describe, expect, it } from '@jest/globals';
2+
import { logger as console } from '../../../logger';
3+
4+
import {
5+
whatFlavors,
6+
what_flavors_bruteforce_compute
7+
} from './ctci_ice_cream_parlor_bruteforce';
8+
import TEST_CASES from './ctci_ice_cream_parlor.testcases.json';
9+
import TEST_CASES_BORDER_CASES from './ctci_ice_cream_parlor.border_testcases.json';
10+
11+
describe('ctci_ice_cream_parlor_bruteforce', () => {
12+
it('whatFlavors test cases', () => {
13+
expect.assertions(10);
14+
15+
TEST_CASES.forEach((testSet) => {
16+
testSet?.tests.forEach((test) => {
17+
const answer = what_flavors_bruteforce_compute(test.costs, test.money);
18+
19+
console.debug(
20+
`${testSet.title} ctci_ice_cream_parlor_bruteforce(${test.costs}, ${test.money}) solution found: ${answer}`
21+
);
22+
23+
expect(answer).toStrictEqual(test.expected);
24+
expect(whatFlavors(test.costs, test.money)).toBeUndefined();
25+
});
26+
});
27+
});
28+
29+
it('whatFlavors border test cases', () => {
30+
expect.assertions(2);
31+
32+
TEST_CASES_BORDER_CASES.forEach((testSet) => {
33+
testSet?.tests.forEach((test) => {
34+
expect(
35+
what_flavors_bruteforce_compute(test.costs, test.money)
36+
).toStrictEqual(test.expected);
37+
expect(whatFlavors(test.costs, test.money)).toBeUndefined();
38+
});
39+
});
40+
});
41+
42+
it('whatFlavors test caller function', () => {
43+
expect.assertions(1);
44+
45+
const cost: number[] = [];
46+
const money: number = 100;
47+
48+
expect(whatFlavors(cost, money)).toBeUndefined();
49+
});
50+
});
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* @link Problem definition [[docs/hackerrank/interview_preparation_kit/search/ctci-ice-cream-parlor.md]]
3+
*/
4+
5+
export function what_flavors_bruteforce_compute(
6+
cost: number[],
7+
money: number
8+
): number[] {
9+
for (const _i in cost) {
10+
const i: number = parseInt(_i);
11+
const x: number = cost[i];
12+
13+
const budget = money - x;
14+
15+
for (let j = i + 1; j < cost.length; j++) {
16+
if (budget - cost[j] == 0) {
17+
console.log(`${i + 1} ${j + 1}`);
18+
return [i + 1, j + 1];
19+
}
20+
}
21+
}
22+
23+
return [];
24+
}
25+
26+
export function whatFlavors(cost: number[], money: number): void {
27+
console.log(what_flavors_bruteforce_compute(cost, money)?.join(' '));
28+
}
29+
30+
export default { what_flavors_bruteforce_compute, whatFlavors };

0 commit comments

Comments
 (0)