LeetCode Challenge Day 16 — 1518. Water Bottles
Nitin Ahirwal / October 1, 2025
Hey folks
This is Day 16 of my LeetCode streak 🚀.
Today’s problem is 1518. Water Bottles — we’re given some initial full bottles and a rule for exchanging empty ones. The goal is to figure out the maximum number of bottles we can drink.
It’s a classic simulation-style problem with a neat greedy loop.
📌 Problem Statement
You are given two integers:
numBottles→ the number of full water bottles you initially have.numExchange→ the number of empty bottles required to exchange for one new full bottle.
Each time you drink a bottle, it becomes empty. You can keep exchanging empty bottles for new full bottles until no further exchanges are possible.
Return the maximum number of bottles you can drink.
Examples
-
Input:
numBottles = 9, numExchange = 3
Output:13
Explanation: Drink 9 → exchange for 3 → drink 3 → exchange for 1 → drink 1 → total = 13. -
Input:
numBottles = 15, numExchange = 4
Output:19
Explanation: Drink 15 → exchange for 3 → drink 3 → exchange for 1 → drink 1 → total = 19.
Constraints
1 <= numBottles <= 1002 <= numExchange <= 100
💡 Intuition
The problem mimics real life:
- Drink all bottles you have.
- Count the empty ones.
- Trade empties for full bottles as long as possible.
This can be directly simulated with a loop — each exchange reduces empty bottles and adds new full ones.
🔑 Approach
- Start with
totalDrunk = numBottles. - Keep a counter of empty bottles.
- While you have at least
numExchangeempties:- Exchange them for new full bottles.
- Add the new bottles to
totalDrunk. - Update the empty count as
(empties % numExchange) + newBottles.
- Once no more exchanges are possible, return
totalDrunk.
⏱️ Complexity Analysis
- Time complexity:
O(log numBottles)— since bottles reduce quickly per exchange. - Space complexity:
O(1)— only a few variables are used.
🧑💻 Code (JavaScript)
/**
* @param {number} numBottles
* @param {number} numExchange
* @return {number}
*/
var numWaterBottles = function(numBottles, numExchange) {
let totalDrunk = numBottles;
let empty = numBottles;
while (empty >= numExchange) {
let newBottles = Math.floor(empty / numExchange);
totalDrunk += newBottles;
empty = (empty % numExchange) + newBottles;
}
return totalDrunk;
};
// ✅ Quick tests
console.log(numWaterBottles(9, 3)); // 13
console.log(numWaterBottles(15, 4)); // 19
🧪 Edge Cases
-
numBottles < numExchange → no exchange possible, answer =
numBottles. -
Exactly divisible → the loop continues until 1 empty remains.
-
Small inputs → works fine since constraints are tiny.
🎥 Reflections
This problem highlights how simple simulation loops can solve real-world style challenges.
It’s not always about math shortcuts — sometimes just carefully simulating step by step is the cleanest approach.
That’s it for Day 16 of my LeetCode journey!
On to the next challenge 🔥
Happy Coding 👨💻