Problem overview
A box of candy costs price dollars, and you have balance dollars. The function buyCandy must return how many more dollars you would need to afford one more box than you can afford now.
Take price = 4 and balance = 9. Two boxes cost 8 dollars, so you can buy two, with 1 dollar left over. A third box would bring the total to 12 dollars, and you have 9, so you are 3 dollars short. The answer is 3.
Approach
The question is easier in three small questions:
- How many boxes can I buy now?
- What would one more box than that cost in total?
- How far is that total from what I have?
The first answer is "balance divided by price, dropping the remainder". The second is that count plus one, times the price. The third is a subtraction. There's no loop and no condition, just three lines of arithmetic.
The last step has a pleasant property: the answer is never 0. If you have exactly 8 dollars and each box costs 4, you can buy two boxes with nothing left over, and one more box still costs a full 4 dollars, so the answer is 4. A balance of 9 leaves 1 dollar over, which is why the answer for that case is 3 and not 4.
Step by step
- Count the whole boxes. Declare
boxesasbalance / price. When both operands are integers, Kotlin's/drops the fractional part, so9 / 4is2, which is exactly the number of whole boxes. - Price one more box. Declare
balanceNeededas(boxes + 1) * price. The parentheses make the addition happen first. Without them,boxes + 1 * pricewould multiply before it adds and give a different number. - Find the gap. Declare
extraBalanceasbalanceNeeded - balance. This is the money you are missing. - Return it. The challenge asks for that gap, so
extraBalanceis the result.
The three variables are declared with val because none of them changes after it is set.
The solution in Kotlin
class Solution {
fun buyCandy(price: Int, balance: Int): Int {
val boxes = balance / price
val balanceNeeded = (boxes + 1) * price
val extraBalance = balanceNeeded - balance
return extraBalance
}
}
Details worth knowing:
- Integer division truncates. Both
balanceandpriceareInt, so the division produces anIntwith the fraction dropped. For positive numbers that is rounding down. It does not produce 2.25 for9 / 4. - Type inference. No variable has a written type. Kotlin infers
Intfrom the expressions, soval boxes = balance / priceis the same asval boxes: Int = balance / price. valcan't be reassigned. Each name is set once. Trying to assignboxesagain later is a compile error.- The intermediate names are optional. The whole function could be one line,
return ((balance / price) + 1) * price - balance. Naming the steps makes each one easy to read and check.
Complexity
The function does one division, one addition, one multiplication and one subtraction, whatever the inputs are. It runs in constant time, O(1), and uses constant extra space, O(1).
Edge cases and common mistakes
- Exact multiples. With
price = 4andbalance = 8,boxesis 2 andbalanceNeededis 12, so the answer is 4, a whole price. Returning 0 here is a common slip. - Not enough for any box. With
price = 4andbalance = 3,boxesis 0,balanceNeededis 4 and the answer is 1. - Zero balance. With
balance = 0, the answer is the full price. - A price of 0. Dividing an
Intby zero throws anArithmeticExceptionwith the message/ by zero. The challenge doesn't ask for this case, but it explains why a price is expected to be positive. - Forgetting the parentheses around
boxes + 1, which changes the order of operations. - Using the remainder instead. The remainder
balance % priceis the money left over, and the missing amount isprice - balance % price. That also works, but it is a different route from the one this lesson takes.
Testing
buyCandy(4, 9)returns3.buyCandy(4, 8)returns4.buyCandy(4, 3)returns1.buyCandy(4, 0)returns4.