diff options
author | Vincent Ambo <mail@tazj.in> | 2021-12-13T22·51+0300 |
---|---|---|
committer | Vincent Ambo <mail@tazj.in> | 2021-12-13T23·15+0300 |
commit | 019f8fd2113df4c5247c3969c60fd4f0e08f91f7 (patch) | |
tree | 76a857f61aa88f62a30e854651e8439db77fd0ea /users/wpcarro/scratch/deepmind/part_two/coin.ts | |
parent | 464bbcb15c09813172c79820bcf526bb10cf4208 (diff) | |
parent | 6123e976928ca3d8d93f0b2006b10b5f659eb74d (diff) |
subtree(users/wpcarro): docking briefcase at '24f5a642' r/3226
git-subtree-dir: users/wpcarro git-subtree-mainline: 464bbcb15c09813172c79820bcf526bb10cf4208 git-subtree-split: 24f5a642af3aa1627bbff977f0a101907a02c69f Change-Id: I6105b3762b79126b3488359c95978cadb3efa789
Diffstat (limited to 'users/wpcarro/scratch/deepmind/part_two/coin.ts')
-rw-r--r-- | users/wpcarro/scratch/deepmind/part_two/coin.ts | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/users/wpcarro/scratch/deepmind/part_two/coin.ts b/users/wpcarro/scratch/deepmind/part_two/coin.ts new file mode 100644 index 000000000000..8aa8de8bb87a --- /dev/null +++ b/users/wpcarro/scratch/deepmind/part_two/coin.ts @@ -0,0 +1,102 @@ +// The denomination of a coin. +type Coin = number; + +// The amount of change remaining. +type Amount = number; + +// Mapping of Coin -> Int +type CoinBag = Map<Coin, number>; + +function createCoinBag(coins: Coin[]): CoinBag { + const result = new Map(); + + for (const coin of coins) { + result.set(coin, 0); + } + + return result; +} + +// This algorithm should work conceptual, but it does not actually +// work. JavaScript uses reference equality when constructing a Set<Map<A,B>>, +// so my result.size returns a higher number than I expect because it contains +// many duplicate entries. +// +// Conceptually, I'm not sure this solution is optimal either -- even after I +// can dedupe the entries in `result`. +function changePossibilities(amt: Amount, coins: Coin[]): number { + if (amt === 0) { + return 1; + } + const result: Set<CoinBag> = new Set(); + + const q: [Coin, Amount, CoinBag][] = []; + + for (const coin of coins) { + const bag = createCoinBag(coins); + bag.set(coin, 1); + q.push([coin, amt - coin, bag]); + } + + while (q.length > 0) { + const [coin, amt, bag] = q.shift(); + + console.log([coin, amt, bag]); + + if (amt === 0) { + result.add(bag); + } else if (amt < 0) { + continue; + } else { + for (const c of coins) { + const bagCopy = new Map(bag); + const value = bagCopy.get(c); + bagCopy.set(c, value + 1); + q.push([c, amt - c, bagCopy]); + } + } + } + console.log(result); + return result.size; +} + +// Tests +let desc = "sample input"; +let actual = changePossibilities(4, [1, 2, 3]); +let expected = 4; +assertEqual(actual, expected, desc); + +desc = "one way to make zero cents"; +actual = changePossibilities(0, [1, 2]); +expected = 1; +assertEqual(actual, expected, desc); + +desc = "no ways if no coins"; +actual = changePossibilities(1, []); +expected = 0; +assertEqual(actual, expected, desc); + +desc = "big coin value"; +actual = changePossibilities(5, [25, 50]); +expected = 0; +assertEqual(actual, expected, desc); + +desc = "big target amount"; +actual = changePossibilities(50, [5, 10]); +expected = 6; +assertEqual(actual, expected, desc); + +// I think InterviewCake designed this assertion to be computationally +// expensive. +desc = "change for one dollar"; +actual = changePossibilities(100, [1, 5, 10, 25, 50]); +expected = 292; +assertEqual(actual, expected, desc); + +function assertEqual(a, b, desc) { + if (a === b) { + console.log(`${desc} ... PASS`); + } else { + console.log(`${desc} ... FAIL: ${a} != ${b}`); + } +} |