leetcode365.Water And Jug Problem
题目
1 | You are given two jugs with capacities x and y litres. There is an infinite amount of water supply available. You need to determine whether it is possible to measure exactly z litres using these two jugs. |
假设现在有两个杯子,每个杯子分别最多可以装x和y升水,假设现在水的供应量是无限的,问是否有可能用这两个杯子共同承装z升水,可以用两个杯子执行的操作如下:
- 将任何一个杯子装满水
- 倒掉任何一个杯子中的所有水
- 将一个杯子中的水倒进另一个杯子,直到另一个杯子满了或者是当前的杯子已经空了
比如,如果现在两个杯子A和B分别能装3升水和5升水,需要在两个杯子中共装4升水。我们可以找到这样一个序列满足题目要求:
- 将B杯倒满水并导入A中,此时A:3 B:2
- 将A杯倒空,并将B中的水倒入A中,此时A:2 B:0
- 将B杯装满并倒A中,此时A:3 B:4
- 将A杯倒掉,此时A:0 B:4
##思路一:搜索##
这里可以说我们变相的利用了深度/广度优先搜索来实现。通过深度/广度优先搜索我们可以实现遍历所有可能的场景,直到找到我们最终想要的结果,或者得到该结果无法达到的结论。假设我们知道当前水杯的情况为A最多可以放置x升水,B最多可以放置Y升水,而且A当前水杯中有a升水,B中有b升水,则由当前情况在一次操作之后可能产生以下几种情况:
- 倒光A中的水:A:0 | B:b
- 倒光B中的水:A:a | B:0
- 装满A中的水:A:x | B:b
- 装满B中的水:A:a | B:y
- 将A中的水倒进B中:A:a - min(a, y-b) | B:b + min(a, y-b)
- 将B中的水倒进A中:A:a + min(x-a, y) | B:b - min(x-a, y)
最后两种情况需要判断两个杯子的剩余水情况和可倒入水的情况
如果以上几种情况都不满足z,则我们再以以上几种情况为基础继续寻找可能的情况。这里可以使用HashSet来避免对情况的重复遍历。代码如下:
1 | public class Status{ |
思路二:数学
这里使用了一个数学结论叫做Bézout’s identity,在该理论中,假设数字a和b有一个最大公约数d,则一定存在x和y满足ax+by=d。x,y的其它组合所得到的值一定是d的倍数。
这里x为负值时代表将杯子倒空,x为正值时代表将杯子装满。
1 | public boolean canMeasureWater(int x, int y, int z) { |