Find the least number of coins required that can make any change from 1 to 99 cents

后端 未结 27 2009
生来不讨喜
生来不讨喜 2020-12-07 10:08

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

相关标签:
27条回答
  • 2020-12-07 10:32

    This the code in c# to find the solution.

    public struct CoinCount
    {
        public int coinValue;
        public int noOfCoins;
    }
    
    /// <summary>
    /// Find and returns the no of coins in each coins in coinSet
    /// </summary>
    /// <param name="coinSet">sorted coins value in assending order</param>
    /// <returns></returns>
    public CoinCount[] FindCoinsCountFor1to99Collection(int[] coinSet)
    {
        // Add extra coin value 100 in the coin set. Since it need to find the collection upto 99.
        CoinCount[] result = new CoinCount[coinSet.Length];
        List<int> coinValues = new List<int>();
        coinValues.AddRange(coinSet);
        coinValues.Add(100);
    
        // Selected coin total values
        int totalCount = 0;
        for (int i = 0; i < coinValues.Count - 1; i++)
        {
            int count = 0;
            if (totalCount <= coinValues[i])
            {
                // Find the coins count
                int remainValue = coinValues[i + 1] - totalCount;
                count = (int)Math.Ceiling((remainValue * 1.0) / coinValues[i]);
            }
            else
            {
                if (totalCount <= coinValues[i + 1])
                    count = 1;
                else
                    count = 0;
            }
            result[i] = new CoinCount() { coinValue =  coinValues[i], noOfCoins = count };
            totalCount += coinValues[i] * count;
        }
        return result;
    }
    
    0 讨论(0)
  • 2020-12-07 10:37

    I wrote this algorithm for similar kind of problem with DP, may it help

    public class MinimumCoinProblem {
    
        private static void calculateMinumCoins(int[] array_Coins, int sum) {
    
            int[] array_best = new int[sum];
    
            for (int i = 0; i < sum; i++) {
                for (int j = 0; j < array_Coins.length; j++) {
                        if (array_Coins[j] <= i  && (array_best[i] == 0 || (array_best[i - array_Coins[j]] + 1) <= array_best[i])) {
                            array_best[i] = array_best[i - array_Coins[j]] + 1;
                        }
                }
            }
            System.err.println("The Value is" + array_best[14]);
    
        }
    
    
        public static void main(String[] args) {
            int[] sequence1 = {11, 9,1, 3, 5,2 ,20};
            int sum = 30;
            calculateMinumCoins(sequence1, sum);
        }
    
    }
    
    0 讨论(0)
  • 2020-12-07 10:37

    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<int, int> _solutions;
    
            public MoneyChangeCalc(int[] coinTypes)
            {
                _coinTypes = coinTypes;
                Reset();
            }
    
            public int Minimun(int amount)
            {
                for (int i = 2; i <= amount; i++)
                {
                    IList<int> 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<int> FulfillCandidates(int amount)
            {
                IList<int> candidates = new List<int>(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<int, int>
                    {
                        {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);
                }
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-07 10:39

    You can very quickly find an upper bound.

    Say, you take three quarters. Then you would only have to fill in the 'gaps' 1-24, 26-49, 51-74, 76-99 with other coins.

    Trivially, that would work with 2 dimes, 1 nickel, and 4 pennies.

    So, 3 + 4 + 2 + 1 should be an upper bound for your number of coins, Whenever your brute-force algorithm goes above thta, you can instantly stop searching any deeper.

    The rest of the search should perform fast enough for any purpose with dynamic programming.

    (edit: fixed answer as per Gabe's observation)

    0 讨论(0)
  • 2020-12-07 10:39

    Here's a simple c# solution using Linq.

    internal class Program
    {
        public static IEnumerable<Coin> Coins = new List<Coin>
        {
            new Coin {Name = "Dime", Value = 10},
            new Coin {Name = "Penny", Value = 1},
            new Coin {Name = "Nickel", Value = 5},
            new Coin {Name = "Quarter", Value = 25}
        };
        private static void Main(string[] args)
        {
            PrintChange(34);
            Console.ReadKey();
        }
        public static void PrintChange(int amount)
        {
            decimal remaining = amount;
            //Order coins by value in descending order
            var coinsDescending = Coins.OrderByDescending(v => v.Value);
            foreach (var coin in coinsDescending)
            {
                //Continue to smaller coin when current is larger than remainder
                if (remaining < coin.Value) continue;
                // Get # of coins that fit in remaining amount
                var quotient = (int)(remaining / coin.Value);
    
                Console.WriteLine(new string('-',28));
                Console.WriteLine("{0,10}{1,15}", coin.Name, quotient);
                //Subtract fitting coins from remaining amount
                remaining -= quotient * coin.Value;
                if (remaining <= 0) break; //Exit when no remainder left
            }
            Console.WriteLine(new string('-', 28));
        }
        public class Coin
        {
            public string Name { get; set; }
            public int Value { get; set; }
        }
    }    
    
    0 讨论(0)
  • 2020-12-07 10:40

    You need at least 4 pennies, since you want to get 4 as a change, and you can do that only with pennies.

    It isn't optimal to have more than 4 pennies. Instead of 4+x pennies, you can have 4 pennies and x nickels - they span at least the same range.

    So you have exactly 4 pennies.

    You need at least 1 nickel, since you want to get 5 as a change.

    It isn't optimal to have more than 1 nickel. Instead of 1+x nickels, you can have 1 nickel and x dimes - they span at least the same range.

    So you have exactly 1 nickel.

    You need at least 2 dimes, since you want to get 20.

    This means you have 4 pennies, 1 nickel and at least 2 dimes.

    If you had less than 10 coins, you would have less than 3 quarters. But then the maximal possible change you could get using all coins is 4 + 5 + 20 + 50 = 79, not enough.

    This means you have at least 10 coins. Thomas's answer shows that in fact if you have 4 pennies, 1 nickel, 2 dimes and 3 quarters, all is well.

    0 讨论(0)
提交回复
热议问题