Skip to content

Commit cb9d7a0

Browse files
committed
feat(interview-io): add coins problem
1 parent fd8dc8f commit cb9d7a0

File tree

2 files changed

+122
-0
lines changed

2 files changed

+122
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,4 @@ More information about hashign on [wikipedia](https://en.wikipedia.org/wiki/Hash
4545
* https://projecteuler.net
4646
* https://www.codeabbey.com
4747
* https://adriann.github.io/programming_problems.html
48+
* https://exercism.io

interview-io/coins.test.js

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
Split coins in a way where the least number of coins are returned
3+
*/
4+
5+
import test from 'ava'
6+
7+
test('coins', t => {
8+
t.is(numberOfCoins([25, 10, 5, 1], 6), 2)
9+
t.is(numberOfCoins([25, 10, 1], 31), 4)
10+
t.is(numberOfCoins([25, 10, 1], 131), 8) // if amount >= lcm take largest coin
11+
})
12+
13+
test('lcm', t => {
14+
t.is(lcm([25, 10, 5, 1]), 50)
15+
t.is(lcm([15, 5, 3]), 15)
16+
})
17+
18+
test('multiplesFor', t => {
19+
t.deepEqual(multiplesFor(2), {2: 1})
20+
t.deepEqual(multiplesFor(4), {2: 2})
21+
t.deepEqual(multiplesFor(50), {2: 1, 5: 2})
22+
t.deepEqual(multiplesFor(15), {3: 1, 5: 1})
23+
t.deepEqual(multiplesFor(13), {13: 1})
24+
})
25+
26+
const cacheAndReturn = (key, value, cache) => {
27+
cache[key] = value
28+
return value
29+
}
30+
31+
// numberOfCoins :: (Number[], Number) -> Number
32+
const numberOfCoins = (nominals, amount, cache = {}) => {
33+
if (amount === 0) {
34+
return 0
35+
}
36+
37+
if (amount >= lcm(nominals)) {
38+
const [firstNominal] = nominals
39+
return numberOfCoins(nominals, amount - firstNominal, cache) + 1
40+
}
41+
42+
if (cache[amount]) {
43+
return cache[amount]
44+
}
45+
46+
const validNominals = nominals.filter((x) => x <= amount)
47+
48+
return cacheAndReturn(
49+
amount,
50+
validNominals.reduce((acc, cur) =>
51+
Math.min(
52+
acc,
53+
numberOfCoins(validNominals, amount - cur, cache) + 1
54+
),
55+
Infinity
56+
),
57+
cache
58+
)
59+
}
60+
61+
/*
62+
* input: [25, 10, 5, 1], 6
63+
* output: 2
64+
*
65+
* noc([25, 10, 5, 1], 6) + 1 -> min(2, 2) -> 2
66+
* noc([5, 1], 1) + 1 -> 1
67+
* noc([1], 0) -> 0
68+
* noc([5, 1], 5) + 1 -> min(1, 5) -> 1
69+
* noc([5, 1], 0) -> 0
70+
* noc([5, 1], 4) + 1 -> 4
71+
* noc([1], 3) + 1 -> 3
72+
* noc([1], 2) + 1 -> 2
73+
* noc([1], 1) + 1 -> 1
74+
* noc([1], 0) -> 0
75+
*/
76+
77+
const takeBiggest = (x, y) =>
78+
Object.entries(y).reduce(
79+
(acc, [key, value]) => Object.assign(
80+
acc,
81+
{[key]: Math.max(acc[key] || 0, value)}
82+
),
83+
x
84+
)
85+
86+
const lcm = (numbers) => {
87+
const commonMultipliers = numbers.reduce(
88+
(acc, x) => takeBiggest(acc, multiplesFor(x)),
89+
{}
90+
)
91+
return Object.entries(commonMultipliers).reduce(
92+
(acc, [key, value]) => acc * (key ** value),
93+
1
94+
)
95+
}
96+
97+
const multiplesFor = (x) => {
98+
let multiples = {}
99+
let current = x
100+
for (let i = 2; i <= x; i++) {
101+
if (dividesBy(current, i)) {
102+
multiples = incrementKey(i, multiples)
103+
current /= i
104+
i--
105+
}
106+
if (current === 1) {
107+
return multiples
108+
}
109+
}
110+
111+
return multiples
112+
}
113+
114+
const dividesBy = (x, y) =>
115+
Math.ceil(x / y) * y === x
116+
117+
const incrementKey = (key, dict) =>
118+
Object.assign(
119+
dict,
120+
{[key]: (dict[key] || 0) + 1}
121+
)

0 commit comments

Comments
 (0)