https://leetcode-cn.com/problems/water-and-jug-problem/
有两个容量分别为 x 升 和 y 升 的水壶以及无限多的水。请判断能否通过使用这两个水壶,从而可以得到恰好 z 升 的水?
如果可以,最后请用以上水壶中的一或两个来盛放取得的 z 升 水。
你允许:
题目等价于存在无限水源,通过两个容器(x升和y升)的操作,能否组合出z升水。关键操作包括:装满、倒空、相互倒水。最终z升水可以存在于任一或两个容器中。
若存在整数 a, b 使得 ax + by = z
,则 z 是 x 和 y 最大公约数(GCD)的倍数。具体判断条件如下:
z ≤ x + y
z % gcd(x, y) == 0
pythonx=3, y=5 → gcd(3,5)=1
z=4 → 4%1=0 → 可行
x=2, y=6 → gcd(2,6)=2
z=5 → 5%2=1 → 不可行
pythonimport math
def can_measure_water(x: int, y: int, z: int) -> bool:
if z == 0:
return True
if x + y < z:
return False
if x == 0 or y == 0:
return z == max(x, y)
return z % math.gcd(x, y) == 0
通过状态空间搜索,枚举所有可能的水量组合:
(remain_x, remain_y)
表示当前两容器中的水量pythonclass Solution:
def canMeasureWater(self, x: int, y: int, z: int) -> bool:
stack = [(0, 0)] # 初始状态:两容器皆空
visited = set() # 记录已探索状态
while stack:
rx, ry = stack.pop()
# 终止条件检测
if rx == z or ry == z or rx + ry == z:
return True
# 状态剪枝
if (rx, ry) in visited:
continue
visited.add((rx, ry))
# 生成所有可能状态
# 操作1:装满X
stack.append((x, ry))
# 操作2:装满Y
stack.append((rx, y))
# 操作3:倒空X
stack.append((0, ry))
# 操作4:倒空Y
stack.append((rx, 0))
# 操作5:X→Y倒水
transfer = min(rx, y - ry)
stack.append((rx - transfer, ry + transfer))
# 操作6:Y→X倒水
transfer = min(ry, x - rx)
stack.append((rx + transfer, ry - transfer))
return False
方法 | 时间复杂度 | 空间复杂度 | 适用场景 |
---|---|---|---|
数学解法 | O(log(min(x,y))) | O(1) | 任意规模,最优选择 |
DFS/BFS | O(xy) | O(xy) | 小规模数据,需要具体操作路径时 |
如何记录具体操作路径?
三容器问题扩展?
存在测量误差时的容错处理?
本文作者:Dong
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC。本作品采用《知识共享署名-非商业性使用 4.0 国际许可协议》进行许可。您可以在非商业用途下自由转载和修改,但必须注明出处并提供原作者链接。 许可协议。转载请注明出处!