LeetCode-365、水壶问题-中等
有两个容量分别为 x升 和 y升 的水壶以及无限多的水。请判断能否通过使用这两个水壶,从而可以得到恰好 z升 的水?
如果可以,最后请用以上水壶中的一或两个来盛放取得的 z升 水。
你允许:
装满任意一个水壶
清空任意一个水壶
从一个水壶向另外一个水壶倒水,直到装满或者倒空
示例 1:(From the famous "Die Hard" example)
输入: x = 3, y = 5, z = 4
输出: True
示例 2:
输入: x = 2, y = 6, z = 5
输出: False
代码:
class Solution:
def canMeasureWater(self, x: int, y: int, z: int) -> bool:
if x+y < z:
return False
elif z == 0:
return True
elif x == 0:
return y == z
elif y == 0:
return x == z
else:
return z%math.gcd(x, y) == 0
# 贝祖定理:若a,b是整数,且gcd(a,b)=d(a,b的最大公约数为d),那么对于任意的整数x,y,z=ax+by都一定是d的倍数,特别地,一定存在整数x,y,使ax+by=d成立。
# 重要推论:a,b互质的充要条件是存在整数x,y使得ax+by=1。
# 题目改为:给定x,y,找到整数a,b,使得ax+by=z(z<=x+y)。ax+by=z有解的条件是,z是x,y的最大公约数的倍数,则找到x,y的最大公约数并判断z是否是其倍数就可以了。其中,a,b分别表示x,y操作的次数。
class Solution:
def canMeasureWater(self, x: int, y: int, z: int) -> bool:
if x+y < z:
return False
if z == 0:
return True
stack = [(0, 0)]
tmp = set()
while stack:
a, b = stack.pop(0)
if a == z or b == z or a+b == z:
return True
if (a, b) in tmp:
continue
tmp.add((a, b))
stack.append((x, b))
stack.append((a, y))
stack.append((0, b))
stack.append((a, 0))
stack.append((0, b+a)) if a <= y-b else stack.append((a+b-y, y))
stack.append((a+b, 0)) if b <= x-a else stack.append((x, b+a-x))
return False
# DFS:一共只有6种操作
# 倒满x
# 倒满y
# 倒空x
# 倒空y
# x倒入y中(x倒空y不一定满或者x不一定倒空y满)
# y倒入x中(x不一定满y倒空或者x满y不一定倒空)