leetcode
leetcode 2651 ~ 2700
水壶问题

水壶问题

难度:

标签:

题目描述

You are given two jugs with capacities x liters and y liters. You have an infinite water supply. Return whether the total amount of water in both jugs may reach target using the following operations:

  • Fill either jug completely with water.
  • Completely empty either jug.
  • Pour water from one jug into another until the receiving jug is full, or the transferring jug is empty.

 

Example 1:

Input: x = 3, y = 5, target = 4

Output: true

Explanation:

Follow these steps to reach a total of 4 liters:

  1. Fill the 5-liter jug (0, 5).
  2. Pour from the 5-liter jug into the 3-liter jug, leaving 2 liters (3, 2).
  3. Empty the 3-liter jug (0, 2).
  4. Transfer the 2 liters from the 5-liter jug to the 3-liter jug (2, 0).
  5. Fill the 5-liter jug again (2, 5).
  6. Pour from the 5-liter jug into the 3-liter jug until the 3-liter jug is full. This leaves 4 liters in the 5-liter jug (3, 4).
  7. Empty the 3-liter jug. Now, you have exactly 4 liters in the 5-liter jug (0, 4).

Reference: The Die Hard example.

Example 2:

Input: x = 2, y = 6, target = 5

Output: false

Example 3:

Input: x = 1, y = 2, target = 3

Output: true

Explanation: Fill both jugs. The total amount of water in both jugs is equal to 3 now.

 

Constraints:

  • 1 <= x, y, target <= 103

代码结果

运行时间: 34 ms, 内存: 16.0 MB


/*
题目思路:
1. 如果x + y < target,那么无论如何都无法达到目标。
2. 使用数学方法可以确定是否可以通过水壶操作达到目标。具体来说,如果目标体积是x和y的最大公约数的倍数,并且不超过x和y的总容量,那么就可以实现目标。
3. 因此,问题可以归结为计算x和y的最大公约数,然后检查target是否是其倍数。
*/
import java.util.stream.IntStream;
public class WaterJugProblemStream {
    public boolean canMeasureWater(int x, int y, int target) {
        if (x + y < target) return false;
        return target % IntStream.iterate(x, n -> n > 0, n -> y % n).filter(n -> y % n == 0).findFirst().getAsInt() == 0;
    }

    public static void main(String[] args) {
        WaterJugProblemStream wjp = new WaterJugProblemStream();
        System.out.println(wjp.canMeasureWater(3, 5, 4)); // true
        System.out.println(wjp.canMeasureWater(2, 6, 5)); // false
        System.out.println(wjp.canMeasureWater(1, 2, 3)); // true
    }
}

解释

方法:

这个题解利用了贝祖定理(Bézout's identity)的性质。贝祖定理指出,对于任意两个整数 x 和 y,存在整数 a 和 b 使得 ax + by = gcd(x, y),其中 gcd(x, y) 表示 x 和 y 的最大公约数。 题解的思路是: 1. 如果目标水量 target 大于两个水壶的容量之和 x+y,那么无论如何都无法达到目标水量,返回 False。 2. 否则,检查目标水量 target 是否可以被 x 和 y 的最大公约数整除。如果可以整除,那么可以通过某种倒水方案达到目标水量;否则无法达到目标水量。

时间复杂度:

O(1)

空间复杂度:

O(1)

代码细节讲解

🦆
在题解中,如何理解贝祖定理在此问题中的应用,特别是其中的ax + by = gcd(x, y)表达式如何与倒水操作关联?
在水壶问题中,贝祖定理的运用是基于这样一个事实:任意使用两个容量分别为x和y的水壶,我们能够通过不断倒入或倒出水来组合出的水量必须是两个水壶容量的最大公约数(gcd)的倍数。这里的ax + by = gcd(x, y)表达式中的a和b可以是任意整数(包括负数),代表向水壶中加水或从水壶中倒水,其中x和y是两个水壶的容量。例如,如果a为正,则表示往容量为x的水壶中加a次水;如果a为负,则表示从容量为x的水壶中倒出|a|次水。因此,只有当目标水量是x和y的最大公约数的倍数时,我们才能通过这样的加水或倒水操作达到目标水量。
🦆
题解提到如果目标水量大于两个水壶的容量之和,结果为False。能否详细解释为什么这种情况下不能达到目标水量?
如果目标水量大于两个水壶的总容量之和,那么无论如何操作都无法达到这个目标。因为两个水壶的容量加起来都无法达到目标水量,即使两个水壶都装满水也无法满足要求的水量。这是一个基本的容量限制问题,容量的总和设置了能够达到的最大水量的上限。
🦆
题解中未详细阐述如何实际操作倒水以达到目标水量。能否提供一个具体的操作步骤例子,说明如何利用两个水壶的最大公约数达到目标水量?
假设有两个水壶,容量分别为3升和5升,目标水量为1升。这两个水壶的最大公约数为1。根据贝祖定理,我们可以找到整数a和b,使得3a + 5b = 1。一个可能的操作步骤如下: 1. 先将5升水壶装满,然后将其水倒入3升水壶,直到3升水壶满。此时5升水壶中剩下2升。 2. 将3升水壶中的水倒掉,再将5升水壶中的2升水倒入3升水壶。 3. 再次将5升水壶装满,然后继续向3升水壶中倒水,直到3升水壶满。此时5升水壶中剩下1升水,即达到了目标水量。 这个过程中,我们通过反复填充和倒空水壶,最终利用水壶的容量关系达到目标水量。

相关问题