Want Help Cracking FAANG?

(Then click this)

×
Back to Question Bank

365. Water and Jug Problem - Leetcode Solution

Problem Description

The Water and Jug Problem asks: Given two jugs with capacities x and y liters, and an unlimited water supply, determine if it is possible to measure exactly z liters using these jugs. You can perform the following operations as many times as you like:

  • Fill any jug completely.
  • Empty any jug completely.
  • Pour water from one jug to the other until one jug is either full or empty.
Constraints:
  • All values x, y, and z are non-negative integers.
  • You must determine if it is possible to measure exactly z liters (no more, no less).
  • Each operation can be repeated as needed; there is no limit on the number of operations.

Thought Process

At first glance, this problem seems to require simulating every possible sequence of fills, pours, and empties. This brute-force approach would involve exploring all possible water levels in both jugs, which quickly becomes infeasible for large jug sizes.

However, by thinking mathematically, we realize that the problem is fundamentally about whether we can measure z liters using any combination of the two jug capacities. This is related to the classic "Diophantine equation" problem, where we look for integer solutions to equations of the form ax + by = z. The key insight is that using the allowed operations, we can measure any amount of water that is a linear combination of x and y.

The conceptual shift is from simulating all possible states to recognizing that the problem reduces to checking if z is a multiple of the greatest common divisor (GCD) of x and y, and is not more than the sum of their capacities.

Solution Approach

To solve the problem efficiently, we use these steps:

  1. Check Capacity Constraint: If z is greater than x + y, it is impossible to measure z liters, since that's the maximum water you can have using both jugs.
  2. Check GCD Condition: The problem reduces to checking if z is a multiple of gcd(x, y). This is because with the allowed operations, you can only measure amounts that are linear combinations of x and y (Bézout's identity).
  3. Special Case: If z is 0, you can always measure it (by leaving both jugs empty).
  4. Algorithm:
    • Compute gcd(x, y).
    • Check if z is less than or equal to x + y and z % gcd(x, y) == 0.
    • If both are true, return true; otherwise, return false.

This approach is efficient and avoids unnecessary simulation.

Example Walkthrough

Example: x = 3, y = 5, z = 4

  • Step 1: The maximum you can measure is 3 + 5 = 8. Since z = 4 is less than 8, continue.
  • Step 2: Compute gcd(3, 5) = 1.
  • Step 3: Check if 4 % 1 == 0 (true).
  • Step 4: Both conditions are satisfied, so it is possible to measure exactly 4 liters.
  • Process (for illustration):
    • Fill the 5-liter jug (5, 0)
    • Pour from 5-liter to 3-liter jug until 3-liter is full (2, 3)
    • Empty the 3-liter jug (2, 0)
    • Pour remaining 2 liters from 5-liter to 3-liter jug (0, 2)
    • Fill the 5-liter jug again (5, 2)
    • Pour from 5-liter to 3-liter jug until 3-liter is full (4, 3)
    • Now, 4 liters remain in the 5-liter jug: solution found!

Time and Space Complexity

Brute-force Approach:

  • Would involve simulating all possible states (water levels in both jugs), leading to exponential time and space complexity in the worst case.
Optimized Mathematical Approach:
  • Calculating gcd(x, y) takes O(\log(\min(x, y))) time using the Euclidean algorithm.
  • All other checks (comparison and modulo) are constant time.
  • Space complexity is O(1) since only a few variables are used.

Thus, the optimized solution is highly efficient and suitable for large input sizes.

Summary

The Water and Jug Problem can be solved elegantly by recognizing its connection to number theory. Instead of simulating all possible moves, we use the mathematical insight that only amounts that are multiples of the GCD of the jug sizes can be measured, provided the target is not larger than the sum of both jugs. This makes the solution both efficient and conceptually satisfying, turning a seemingly complex problem into a straightforward calculation.

Code Implementation

def canMeasureWater(x: int, y: int, z: int) -> bool:
    from math import gcd
    if z == 0:
        return True
    if x + y < z:
        return False
    return z % gcd(x, y) == 0
      
class Solution {
public:
    bool canMeasureWater(int x, int y, int z) {
        if (z == 0) return true;
        if (x + y < z) return false;
        return z % std::__gcd(x, y) == 0;
    }
};
      
class Solution {
    public boolean canMeasureWater(int x, int y, int z) {
        if (z == 0) return true;
        if (x + y < z) return false;
        return z % gcd(x, y) == 0;
    }
    private int gcd(int a, int b) {
        while (b != 0) {
            int temp = a % b;
            a = b;
            b = temp;
        }
        return a;
    }
}
      
var canMeasureWater = function(x, y, z) {
    if (z === 0) return true;
    if (x + y < z) return false;
    function gcd(a, b) {
        while (b !== 0) {
            let temp = a % b;
            a = b;
            b = temp;
        }
        return a;
    }
    return z % gcd(x, y) === 0;
};