Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions solutions/pete_haskell/coins.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import Test.Hspec
import Data.Array

main :: IO ()
main = hspec $
describe "change calculator" $
it "should find the minimum number of coins required to reach a target value" $ do
minNumCoins [1,2,5] 0 `shouldBe` 0
minNumCoins [1,2,5] 1 `shouldBe` 1
minNumCoins [1,2,5] 2 `shouldBe` 1
minNumCoins [1,2,5] 3 `shouldBe` 2
minNumCoins [1,2,5] 4 `shouldBe` 2
minNumCoins [1,2,5] 5 `shouldBe` 1
minNumCoins [1,2,5] 6 `shouldBe` 2
minNumCoins [1,2,5] 7 `shouldBe` 2
minNumCoins [1,2,5] 8 `shouldBe` 3
minNumCoins [1,2,5] 9 `shouldBe` 3
minNumCoins [1,2,5] 10 `shouldBe` 2
minNumCoins [1,2,5] 20 `shouldBe` 4
minNumCoins [1,2,5] 30 `shouldBe` 6
minNumCoins [1,2,5, 10, 20, 50, 100] 999 `shouldBe` 15
minNumCoins [1,2,5, 21, 25] 63 `shouldBe` 3

minNumCoins :: [Int] -> Int -> Int
minNumCoins coins target = lookup ! target
where
lookup = listArray (0, target) $ map numCoins [0..]
numCoins 0 = 0
numCoins i | i `elem` coins = 1
numCoins i = minimum [1 + lookup ! (i-c) | c <- coins, c < i]
1 change: 1 addition & 0 deletions solutions/pete_php/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
vendor
37 changes: 37 additions & 0 deletions solutions/pete_php/Coin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

function minNumCoins(array $coins, int $target): int
{
return count(minCoins($coins, $target));
}

function minCoins(array $coins, int $target): array
{
if ($target <= 0) {
return [];
}
if ($target < min($coins)) {
throw new InvalidArgumentException('No coins small enough to make the change!');
}

$minCoinMap = [];

for ($i = 0; $i <= $target; ++$i) {
if (in_array($i, $coins)) {
$minCoinMap[$i] = [$i];
} else {
$smallerCoins = array_filter($coins, function ($coin) use ($i) {
return $coin < $i;
});

foreach ($smallerCoins as $c) {
$v = $i - $c;
if (!array_key_exists($i, $minCoinMap) || count($minCoinMap[$v]) + 1 < count($minCoinMap[$i])) {
$minCoinMap[$i] = array_merge([$c], $minCoinMap[$v]);
}
}
}
}

return $minCoinMap[$target];
}
73 changes: 73 additions & 0 deletions solutions/pete_php/CoinTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php
require __DIR__ . "/vendor/phpunit/phpunit/src/Framework/Assert/Functions.php";
require __DIR__ . "/Coin.php";

class CoinTest extends PHPUnit_Framework_TestCase
{
public function test_it_returns_the_minimum_number_of_coins_needed_to_make_change()
{
$this->isEqual(0, minNumCoins([1, 2, 5], 0));
$this->isEqual(1, minNumCoins([1, 2, 5], 1));
$this->isEqual(1, minNumCoins([1, 2, 5], 2));
$this->isEqual(2, minNumCoins([1, 2, 5], 3));
$this->isEqual(2, minNumCoins([1, 2, 5], 4));
$this->isEqual(1, minNumCoins([1, 2, 5], 5));
$this->isEqual(2, minNumCoins([1, 2, 5], 6));
$this->isEqual(2, minNumCoins([1, 2, 5], 7));
$this->isEqual(3, minNumCoins([1, 2, 5], 8));
$this->isEqual(3, minNumCoins([1, 2, 5], 9));
$this->isEqual(2, minNumCoins([1, 2, 5], 10));
$this->isEqual(3, minNumCoins([1, 2, 5], 11));
$this->isEqual(3, minNumCoins([1, 2, 5], 12));
$this->isEqual(4, minNumCoins([1, 2, 5], 13));
$this->isEqual(4, minNumCoins([1, 2, 5], 14));
$this->isEqual(3, minNumCoins([1, 2, 5], 15));
$this->isEqual(5, minNumCoins([1, 2, 5, 10, 20, 50, 100], 256));
$this->isEqual(15, minNumCoins([1, 2, 5, 10, 20, 50, 100], 999));
}

public function test_lower_elbonia_coins()
{
$this->isEqual(3, minNumCoins([1, 2, 5, 10, 21, 25], 24));
$this->isEqual(3, minNumCoins([1, 2, 5, 10, 21, 25], 40));
$this->isEqual(3, minNumCoins([1, 2, 5, 10, 21, 25], 63));
$this->isEqual(8, minNumCoins([1, 2, 5, 10, 21, 25], 158));
}

/**
* @expectedException InvalidArgumentException
*/
public function test_it_throws_an_exception_if_there_is_no_coin_small_enough_to_make_change()
{
minNumCoins([5, 10], 2);
}

public function test_it_records_the_coins_needed_to_make_change()
{
$this->isEqual([], minCoins([1, 2, 5], 0));
$this->isEqual([1], minCoins([1, 2, 5], 1));
$this->isEqual([2], minCoins([1, 2, 5], 2));
$this->isEqual([1, 2], minCoins([1, 2, 5], 3));
$this->isEqual([2, 2], minCoins([1, 2, 5], 4));
$this->isEqual([5], minCoins([1, 2, 5], 5));
$this->isEqual([1, 5], minCoins([1, 2, 5], 6));
$this->isEqual([5, 2], minCoins([1, 2, 5], 7));
$this->isEqual([1, 2, 5], minCoins([1, 2, 5], 8));
$this->isEqual([5, 2, 2], minCoins([1, 2, 5], 9));
$this->isEqual([5, 5], minCoins([1, 2, 5], 10));
$this->isEqual([100, 100, 100, 100, 100, 100, 100, 100, 100, 50, 20, 20, 5, 2, 2], minCoins([1, 2, 5, 10, 20, 50, 100], 999));
}

public function test_it_records_the_lower_elbonia_coins_needed_for_change()
{
$this->isEqual([21, 2, 1], minCoins([1, 2, 5, 10, 21, 25], 24));
$this->isEqual([25, 5, 10], minCoins([1, 2, 5, 10, 21, 25], 40));
$this->isEqual([21, 21, 21], minCoins([1, 2, 5, 10, 21, 25], 63));
$this->isEqual([25, 25, 25, 25, 25, 21, 10, 2], minCoins([1, 2, 5, 10, 21, 25], 158));
}

private function isEqual($expected, $actual)
{
return $this->assertEquals($expected, $actual, '', 0.0, 10, true);
}
}
13 changes: 13 additions & 0 deletions solutions/pete_php/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# A solution to the minimum coin/change problem in PHP

Install PHPUnit dependency with composer

```
$ composer install
```

Run the tests

```
$ ./vendor/bin/phpunit CoinTest.php
```
5 changes: 5 additions & 0 deletions solutions/pete_php/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"require-dev": {
"phpunit/phpunit": "^5.3"
}
}
Loading