Recently I challenged my co-worker to write an algorithm to solve this problem:
Find the least number of coins required that can make any change from
Inspired from this https://www.youtube.com/watch?v=GafjS0FfAC0
following
1) optimal sub problem
2) Overlapping sub problem principles
introduced in the video
using System;
using System.Collections.Generic;
using System.Linq;
namespace UnitTests.moneyChange
{
public class MoneyChangeCalc
{
private static int[] _coinTypes;
private Dictionary _solutions;
public MoneyChangeCalc(int[] coinTypes)
{
_coinTypes = coinTypes;
Reset();
}
public int Minimun(int amount)
{
for (int i = 2; i <= amount; i++)
{
IList candidates = FulfillCandidates(i);
try
{
_solutions.Add(i, candidates.Any() ? (candidates.Min() + 1) : 0);
}
catch (ArgumentException)
{
Console.WriteLine("key [{0}] = {1} already added", i, _solutions[i]);
}
}
int minimun2;
_solutions.TryGetValue(amount, out minimun2);
return minimun2;
}
internal IList FulfillCandidates(int amount)
{
IList candidates = new List(3);
foreach (int coinType in _coinTypes)
{
int sub = amount - coinType;
if (sub < 0) continue;
int candidate;
if (_solutions.TryGetValue(sub, out candidate))
candidates.Add(candidate);
}
return candidates;
}
private void Reset()
{
_solutions = new Dictionary
{
{0,0}, {_coinTypes[0] ,1}
};
}
}
}
Test cases:
using NUnit.Framework;
using System.Collections;
namespace UnitTests.moneyChange
{
[TestFixture]
public class MoneyChangeTest
{
[TestCaseSource("TestCasesData")]
public int Test_minimun2(int amount, int[] coinTypes)
{
var moneyChangeCalc = new MoneyChangeCalc(coinTypes);
return moneyChangeCalc.Minimun(amount);
}
private static IEnumerable TestCasesData
{
get
{
yield return new TestCaseData(6, new[] { 1, 3, 4 }).Returns(2);
yield return new TestCaseData(3, new[] { 2, 4, 6 }).Returns(0);
yield return new TestCaseData(10, new[] { 1, 3, 4 }).Returns(3);
yield return new TestCaseData(100, new[] { 1, 5, 10, 20 }).Returns(5);
}
}
}
}