Start learning free

LESSON 250 OF 569 · FUNCTIONS & CLASSES

Water Bottle in Python: A Class With a Limit

Practice O(1) Read the full explanation

A water bottle holds at most a fixed amount of water: you can't pour in more than fits, and you can't drink more than is in it. Write a class WaterBottle that keeps track of how much water is in one bottle as you fill it and drink from it. Amounts are whole milliliters.

Implement the class WaterBottle:

  • WaterBottle(capacity) creates an empty bottle that holds at most capacity.
  • fill(amount) pours in amount, but only as much as fits: the water never goes above the capacity. It returns how much actually went in.
  • drink(amount) drinks amount, but only as much as is in the bottle: the water never goes below 0. It returns how much was actually drunk.
  • level() returns how much water is in the bottle now.

The input is a bottle's capacity and a list of operations, applied in order to one new WaterBottle. The output lists what the fill, drink and level calls return, in order. The starter code spells these names the way your language does (in Go and Rust, WaterBottle is a struct with methods). Give the fields names that differ from the methods' names: in several languages a field named level would clash with the method level().

 

Example 1:

Input:
    WaterBottle(500)
    fill(200)
    drink(50)
    level()
Output: 200 50 150
Explanation: The empty bottle has room for 500, so all 200 go in. Drinking 50 of them leaves 150.

Example 2:

Input:
    WaterBottle(300)
    fill(250)
    fill(100)
    level()
    fill(10)
Output: 250 50 300 0
Explanation: After the first fill, only 50 more fit: fill(100) pours in 50 and returns 50, and the bottle
is full. A full bottle takes nothing more, so fill(10) returns 0.

Example 3:

Input:
    WaterBottle(100)
    drink(10)
    fill(60)
    drink(100)
    level()
    drink(5)
Output: 0 60 60 0 0
Explanation: The bottle starts empty, so the first drink gets nothing. drink(100) can only drink
the 60 that are there, which empties the bottle again.

 

Constraints:

  • 1 <= capacity <= 104
  • 0 <= amount <= 104
  • At most 250 operations on one WaterBottle.

Note:

Each method should run in O(1) time: the bottle only needs to remember its capacity and how much water it holds.

STEP 1 OF 9
    Ctrl + Enter to check

    PYTHON · FUNCTIONS & CLASSES

    Water Bottle in Python, explained

    Problem overview

    A bottle holds at most a fixed amount of water. You can't pour in more than fits, and you can't drink more than is inside. The class WaterBottle keeps track of one bottle, in whole milliliters:

    • WaterBottle(capacity) creates an empty bottle.
    • fill(amount) pours in as much as fits and returns how much actually went in.
    • drink(amount) drinks as much as is there and returns how much was actually drunk.
    • level() returns the water in the bottle now.

    For a bottle of capacity 300, fill(250) returns 250. Then fill(100) has room for only 50 more, so it returns 50 and the bottle is full. The level is 300, and a further fill(10) returns 0.

    Approach: ask for a lot, take what is possible

    The bottle needs two numbers: its capacity, which never changes, and the water it holds now. For fill, the room left is capacity - water. The amount that goes in is the smaller of the requested amount and the room left. If everything fits, that is the request. If not, it is the room left, and the bottle ends up exactly full. A full bottle has no room, so the amount is 0.

    drink works the same way from the other side: the amount drunk is the smaller of the request and the water inside. The water can't go below 0 because you never subtract more than it holds. Using min removes the need for separate "does it fit?" branches.

    The water attribute is called water, not level. An attribute named level would hide the method level(), and bottle.level() would fail.

    Step by step

    1. Store the capacity in self.capacity. fill needs it later to know how much still fits.
    2. Set self.water to 0. A new bottle is empty.
    3. In fill, compute added as min(amount, self.capacity - self.water).
    4. Add added to the water with +=. Adding added, not amount, keeps the water within the capacity.
    5. Return added, so the caller learns how much really went in.
    6. In drink, compute drunk as min(amount, self.water).
    7. Subtract drunk from the water with -=.
    8. Return drunk.
    9. level returns self.water.

    The solution in Python

    class WaterBottle:
        def __init__(self, capacity: int):
            self.capacity = capacity
            self.water = 0
        def fill(self, amount: int) -> int:
            added = min(amount, self.capacity - self.water)
            self.water += added
            return added
        def drink(self, amount: int) -> int:
            drunk = min(amount, self.water)
            self.water -= drunk
            return drunk
        def level(self) -> int:
            return self.water
    

    A run with two bottles:

    b = WaterBottle(300)
    print(b.fill(250), b.fill(100), b.level(), b.fill(10))
    c = WaterBottle(100)
    print(c.drink(10), c.fill(60), c.drink(100), c.level(), c.drink(5))
    
    250 50 300 0
    0 60 60 0 0
    

    The second bottle shows the other limit. Drinking from the empty bottle gets 0. After fill(60), drink(100) can only take the 60 that are there, which empties it again.

    Edge cases and common mistakes

    • Adding amount instead of added. The bottle would overflow: with capacity 300, two fills of 250 would leave 500 in it.
    • Returning amount instead of added. The water stays correct, but the caller is told that everything fit.
    • A full or empty bottle. fill on a full bottle and drink on an empty one both return 0 and change nothing.
    • An amount of 0. Both methods return 0, since min(0, ...) is 0.
    • Naming the attribute level. It hides the method of the same name.
    • Complexity. Each method does a few arithmetic operations, so each runs in O(1) time.
    Keep going with Python500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free