Problem overview
A box of candy costs price dollars and you have balance dollars. The function buy_candy must return how many more dollars you need to afford one more box than you can buy right now.
Take price = 4 and balance = 9. Two boxes cost 4 * 2 = 8 dollars, so you can buy two. A third box would bring the total to 12 dollars, so you are 12 - 9 = 3 dollars short. The answer is 3.
Approach
The question breaks into three small facts.
- How many boxes can you afford now? That is the whole number of times
pricefits intobalance. - How much money does one more box than that require in total?
- How far is that total from what you hold?
Each fact is one line of arithmetic and each gets its own named variable, which makes the code read like the explanation.
Integer division does the first part
When both operands of / are integers, Rust divides without a fractional part and drops what is left over. With 9 / 4 the result is 2, not 2.25, which is exactly the count of whole boxes. For positive numbers this rounds down. For negative numbers it truncates toward zero, but a price and a balance are not negative here.
Step by step
- Count the whole boxes. Bind
boxestobalance / price. For 9 and 4 this is 2. - Price one more box. To own
boxes + 1boxes you need(boxes + 1) * pricedollars. The parentheses make the+ 1happen before the multiplication. Without them,boxes + 1 * pricewould multiply first and give the wrong total. Store the amount inbalanceNeeded. For the example it is 3 * 4 = 12. - Find the gap. Subtract your
balancefrom that total and bind the result toextraBalance. For the example, 12 - 9 = 3. - Return the gap. That is the money still missing.
Each variable is introduced with an immutable let. Nothing changes after it is set, so no mut is needed.
The solution in Rust
impl Solution {
fn buy_candy(price: i32, balance: i32) -> i32 {
let boxes = balance / price;
let balanceNeeded = (boxes + 1) * price;
let extraBalance = balanceNeeded - balance;
return extraBalance;
}
}
Rust details
- Types are inferred. All three variables are
i32because the parameters are. Rust works that out without annotations. - Naming. Rust style prefers snake case, like
balance_needed. The namesbalanceNeededandextraBalanceare legal, and the compiler only issues a style warning about them. - return. The final line could be written as just
extraBalance, with noreturnand no semicolon. Both forms return the same value.
Complexity
The function does a fixed number of arithmetic operations, so it runs in O(1) time and uses O(1) memory.
Edge cases and common mistakes
- An exact multiple. With
price = 4andbalance = 8you can buy two boxes with nothing left over. The answer is still 4, a full price, because "one more box" always costs the full price. The result is never 0. An approach that rounds up to the next multiple and answers 0 here is wrong, because you can already afford exactly two boxes. - Not enough for a single box. With
price = 5andbalance = 3,boxesis 0 and the answer is 5 - 3 = 2. With a balance of 0, the answer is the price itself. - Forgetting the parentheses.
boxes + 1 * priceis not(boxes + 1) * price. - A price of 0. Dividing an integer by zero panics at run time in Rust. The problem implies a positive price, so the code does not guard against it.
- Very large values. In the optimized builds the lessons use, an
i32that goes past its limit wraps around silently, so a huge price timesboxes + 1can produce a wrong number. Normal inputs stay far from the limit.
Testing
buy_candy(4, 9)returns 3.buy_candy(4, 8)returns 4.buy_candy(5, 3)returns 2.buy_candy(4, 0)returns 4.
