Daily Coding Problem: Minimum Coins Count

Written by nicolam94 | Published 2023/09/12
Tech Story Tags: programming | algorithms | daily-coding-problem | golang | python | math | coding | python-programming

TLDRCounting the minimum numbers of coin to reach a certain amount, given the standard USA coin systemvia the TL;DR App

Welcome everyone with another problem to solve! Today, we are dealing with coins and the minimum number of coins to obtain a certain amount. We are going to use American coins: specifically, 1, 5, 10, and 25 cents coins. This problem will also be the occasion to seeĀ two different algorithms, one better than the other, and aĀ comparison between two languages: Go and Python.

As always, these problems are provided by the wonderful newsletter DailyCodingProblem, which you can subscribe toĀ here. Check it out and try to solve your challenges, too!

Ready then? Letā€™s jump to the problem!


The problem

This problem was asked by Google in an interview, but itā€™s also a classic problem in math and statistics, expressed in many many versions:

Find the minimum number of coins required to makeĀ nĀ cents.

You can use standard American denominations, that is, 1Ā¢, 5Ā¢, 10Ā¢, and 25Ā¢.

For example, givenĀ n = 16, returnĀ 3Ā since we can make it with a 10Ā¢, a 5Ā¢, and a 1Ā¢.

The problem does not need further explanations: using 1Ā¢, 5Ā¢, 10Ā¢ and 25Ā¢ coins, we need to find the minimum number of coins to reach a target valueĀ n.

Letā€™s put down some initial considerations first and then see how to write the code to solve this. This will be a long article, but stick with me: I promise it will be interesting!


The logic behind the algorithm

First off, letā€™s look at the coins:Ā each one of them, except for the 1Ā¢, is a multiple of 5.Ā This means that it is really easy, with this system, to build amounts that are multiples of 5.

Given this, we can then use theĀ 1Ā¢ to ā€œadjustā€Ā the value to the amount that we need: in the example above, we can get a value of 16Ā¢ by using one 10Ā¢ coin, one 5Ā¢ coin, and one 1Ā¢ coin. We can add 1Ā¢ coins until we reach another multiple of 5, at which point it is not convenient anymore, and we should use 5Ā¢, 10Ā¢ or 25Ā¢. For example, to build 30Ā¢, we can use one 25Ā¢ and five 1Ā¢, but at that point we should swap for a 5Ā¢ to use less coins.

So,Ā how many 1Ā¢ coins are we forced to use at most?Ā Since each number ending with a 0 or a 5 is a multiple of 5,Ā we are forced to use at most four 1Ā¢Ā coins before swapping all of them with a 5Ā¢. Hereā€™s a graphic explanation:


Besides that,which coins should we use first?Ā Itā€™s pretty obvious, of course, but using a 25Ā¢ coin is much more worthwhile (ā€¦literally, in this case) than using a 10Ā¢ or a 5Ā¢ coin. This is because sinceĀ we are reaching our target amount faster, we are also using fewer coins to do so. So, we should always focus on using higher-value coins first, followed by the others in decreasing order.

Letā€™s recap a bit:

  • First off,Ā we need to find the nearest multiple lesser than our target values. At that point, we need to start adding 1Ā¢ coins. To do so, we can reverse the process: finding the nearest multiple of 5 by subtracting 1Ā¢ coins from the target value;

  • After that,Ā we can add coins for each coin value and update our value, starting from the highest 25Ā¢ to the lowest 5Ā¢ coin,Ā until our coin value exceeds the remaining target value.

Letā€™s try to build some code.


The code (version one)

Hereā€™s a first version of the code, written in Go language:

https://gist.github.com/NicolaM94/46f9098540343593a8cb6b5c86778641?embedable=true

Letā€™s break it down: we first init a variableĀ coinsĀ to store the coins we used during the process. After that, we apply the first point of our previous argument: ourĀ targetValueĀ is not a multiple of 5 (Ā targetValue % 5 != 0Ā ) weĀ increase the coin counter by one and decreaseĀ targetValueĀ by one:Ā This way, we add 1Ā¢ coins until we hit a multiple of 5.

After that, we apply the second point:Ā we add the other coins, starting from the 25Ā¢ one, until they canā€™t fit in theĀ targetValueĀ anymore. So whileĀ targetValueĀ is lesser or equal to 25, we can use 25Ā¢s to reach it. Again, we add one coin at each loop and subtract 25 from theĀ targetValueĀ to update it. OnceĀ targetValueĀ is lesser than 25, we canā€™t use a 25Ā¢ coin to get to it, so we stop.

This same process is also run for the 10Ā¢ coins: once theĀ targetValueĀ is less than 10, we must stop using 10Ā¢ coins.

At this point, ourĀ targetValueĀ holds a value that is less than 10. Since the first step, though, we are carrying on a value that must be a multiple of 5. And since we only divided by 25 and 10,Ā targetValueĀ must still be a multiple of 5. Multiples of 5 below 10 are only 0 and 5, meaning that we only need one more coin or we need none. For this reason, we can simply add to our coin counterĀ targetValue/5Ā , which will be 1 ifĀ targetValueĀ is 5 and 0 ifĀ targetValueĀ is 0.

Then, we simply return the coins counter.


The code (version two)

We can do better, though. In the last paragraph, we talked about ā€œdividing by 25 and 10ā€, becauseĀ if we look closer at the process, it really is simple division. Suppose we have aĀ targetValueĀ of 90. Itā€™s already a multiple of 5, so we skip the first point and start adding 25Ā¢ coins. At each step of the loop, we add one coin and subtract 25 fromĀ targetValueĀ : This is basically dividing!

After the division,Ā we get rid of the remainder and keep the integer part, and thatā€™s it.Ā For this reason, we can substitute the for loops in the algorithm with a simple division! Hereā€™s the new algorithm:

https://gist.github.com/NicolaM94/77c30143d002d21342bcf33bcac30246?embedable=true#file-minimumcoinstwo-go

The algorithm is pretty much the same; the only difference resides in the missing for loops. Here, we substitute them with the simple division ofĀ targetValueĀ by the coin we are considering. We first add as many coins asĀ targetValue/{coinValue}Ā and then we subtract the coin value fromĀ targetValueĀ as many times as the coins we just added. This simplifies the process a lot, as weā€™ll see later when talking about time complexity.


A Python version

Maybe you noticed that there is somethingĀ wrongĀ with the division. For example, for aĀ targetValue = 90Ā ,Ā targetValue/25 = 3.6Ā : how come we can simply add the result to our coins, obtaining 3 instead?Ā This is because the Go language, as many others, treats the two un-typed numbers as integers and gives back ā€˜the result of the same type.Ā For this reason, a division between two un-typed integers gives back an integer, the integer part of 3,6. Unlike Go,Ā Python has a more practical approach: the result of any division is always a floating point number.Ā For this reason, the same algorithm in Python would need some more type conversions here and there. Hereā€™s the result:

https://gist.github.com/NicolaM94/45cd6b82d45a473a3b7e24355486100c?embedable=true#file-minimumcoinstwo-py

PS: While doing some research about Pythonā€™s division return type, I also discovered you could use the double divide signĀ //Ā , which I did not know existed, instead of usingĀ intĀ for conversion. For example then:

print(90/25)   #3.6
print(90//25)  #3


Time complexity

Letā€™s start withĀ the first algorithm. Itā€™s pretty clear that itĀ runs in linear time, with a time complexity O(n): the number of operations depends entirely on the size of the inputĀ targetValueĀ .Ā The first for loop only runs from 1 to 4 times, so we can consider it constant time. The other two for loops run in linear time instead, depending on the size ofĀ targetValueĀ .

The second algorithm, though, and also its Python variant, of course,Ā is way better: since we were able to remove all the for loops, its execution time does not depend on the input size anymore. This means the algorithm nowĀ runs in constant time O(1), requiring at most 10 steps to give out a solution.


Conclusion

Thatā€™s it for todayā€™s problem: I hope you find it interesting and if you read it to the end, well: thank you so much!

If you found the article useful, please leave a clap or two and share it with someone who could find it useful, too: that would really make my day! I also opened aĀ Ko-fiĀ page, so if you can, and you are willing to share a Kofi, feel free to do so!

As always, a big thanks for reading

Nicola


Also published here.


Written by nicolam94 | Developer, math enthusiast, D&D wizard. The first two only in role play games.
Published by HackerNoon on 2023/09/12