[LeetCode] Water and Jug Problem
题目
https://leetcode.com/problems/water-and-jug-problem/
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.
If z liters of water is measurable, you must have z liters of water contained within one or both buckets by the end.
Operations allowed:
- Fill any of the jugs completely with water.
- Empty any of the jugs.
- Pour water from one jug into another till the other jug is completely full or the first jug itself is empty.
Example 1: (From the famous “Die Hard” example)
Input: x = 3, y = 5, z = 4
Output: True
Example 2:
Input: x = 2, y = 6, z = 5
Output: False
思路
注意:这里的x和y既表示两个罐子,也表示罐子中的容量。
例1:Input: x = 3, y = 5, z = 4,Output: True
需要注意的是,时时刻刻x+y都是一种z的可能值,在本文的描述中不再赘述。
z 所有取值的情况:
x,y都灌满的情况:3(x),5(y),8(x+y)
初始y是灌满的,
*倒出x这么多,y剩余水:2(y-x)
将y剩余的水倒入空的x中,x的剩余空间:1(3-2)
然后y灌满,将y倒入有部分水的x(有1),此时y剩余水:4(5-1)
然后重复*号的处理(注:冒号后面的值是变化的)。
结束条件:当某一次处理之后,x的剩余为0,或者y的剩余为0.
继续把上面的处理完:
当前y剩余4,每次倒出x(3)这么多,y剩余水:1(4-3)
将y剩余的水1倒入空的x中,x的剩余空间:2(3-1)
然后y灌满,将y倒入x,使x满,此时y剩余水:3(5-2)
当前y剩余3,倒出x(3)这么多,y没有水了(3-3),结束。
再次强调,每种情况x+y都是一种z的可能值,在本文的描述中不再赘述。
上面的描述中出现了4的情况,所以z=4是可以做到的。
例2:Input: x = 3, y = 11, z = 13,Output: True
z 所有取值的情况:
3(x),11(y),14(x+y)
从y中倒出x:8(y-x),5(y-2x),2(y-3x)
将2倒入x,再从满y中倒水将x倒满,y剩余水:10(11-(3-2)) ,(3-2)是x剩余空间。
此时y是10,从y中倒出x:7(y-x),4(y-2x),1(y-3x)
将1倒入x,再从满y中倒水将x倒满,y剩余水:9(11-(3-1)),(3-1)是x的剩余空间。
此时y是9,从y中倒出x:6(y-x),3(y-2x),0(y-3x)
y为0表示没有水了,不能再继续下去了,结束。
z=13出现在x+y上,即x=3,y=10的时候。
所以每次计算出x或者y的时候,都要判断x+y是否与z相同。
代码
33 / 33 test cases passed.
Runtime: 0 ms
注:这个时间不准,有时3ms,有时0ms。
bool canMeasureWater(int x, int y, int z) {
/*如果 x<y, 那么可能的取值有:
x,y, x+y, y-kx(k取值:0~y/x),x中储存y%x, 此时x+y也是一个z值。
然后将y倒入x,y更新为y-(x-y%x),(此时x+y也是一个z值), 然后继续y-kx的操作,
即每次更新y之后,处理y-kx,直到x=y为止,或者y==0为止。所有y-kx的值都是可能值。
*/
if (z == 0) {
return true;
}
if (x == 0) {
return (y == z);
}
if (y == 0) {
return (x == z);
}
if (x == y) {
return (z == x);
}
if (z == x + y || z == x || z == y) {
return true;
}
// 保持x < y
if (x > y) {
int temp = x;
x = y;
y = temp;
}
int orig_y = y;
while (true) {
// y - kx
int max = y/x;
int val = 0;
for (int k = 1; k <= max; k++) {
val = y - k * x;
if (z == val) {
return true;
}
}
int left = val;
if (left == 0) {
break;
}
if (left + y == z || left + x == z) {
return true;
}
// update y
y = orig_y - (x - left);// 将left倒入x,然后将满的y倒入x之后y的剩余
if (y == 0) {
break;
}
if (y == z || y+x == z) {
return true;
}
while (y < x) {
int temp = x - y;// y倒入x之后,x剩余空间
y = orig_y - temp; // 倒满x之后y的剩余
if (y == z || x+y == z) {
return true;
}
}
}
return false;
}