题目链接
题目描述
有两个水壶,容量分别为 x x x 和 y y y 升。水的供应是无限的。确定是否有可能使用这两个壶准确得到 z z z 升。
如果可以得到 ` z z z 升水,最后请用以上水壶中的一或两个来盛放取得的 z z z 升水。
你可以:
- 装满任意一个水壶
- 清空任意一个水壶
- 从一个水壶向另外一个水壶倒水,直到装满或者倒空
示例 1:
输入: jug1Capacity = 3, jug2Capacity = 5, targetCapacity = 4
输出: true
解释:来自著名的 “Die Hard”
示例 2:
输入: jug1Capacity = 2, jug2Capacity = 6, targetCapacity = 5
输出: false
示例 3:
输入: jug1Capacity = 1, jug2Capacity = 2, targetCapacity = 3
输出: true
提示:
- 1 ≤ x , y , z ≤ 1 0 6 1 \leq x, y, z \leq 10^6 1≤x,y,z≤106
解法一:bfs
由于题目给定的操作,我们可以将两个水壶看成一个整体,总的水量 t t t 看成是一个状态,每次操作之后只会有如下四个状态:
- t + x t + x t+x ( t + x ≤ x + y ) (t + x \leq x + y) (t+x≤x+y)
- t + y t + y t+y ( t + y ≤ x + y ) (t + y \leq x + y) (t+y≤x+y)
- t − x t - x t−x ( t − x ≥ 0 ) (t - x \geq 0) (t−x≥0)
- t − y t - y t−y ( t − y ≥ 0 ) (t - y \geq 0) (t−y≥0)
我们就可以用从初始状态 0 开始(初始两个水壶都为空,故 t = 0 t = 0 t=0) bfs,在这个过程中,我们用一个哈希表记录 已经访问过的状态。如果存在一个状态 t ′ = z t' = z t′=z,说明两个水壶可以得到 z z z 升水,故返回 `true。
bfs 结束,返回 false
。
时间复杂度: O ( n ) O(n) O(n)
C++代码:
class Solution {
public:
bool canMeasureWater(int x, int y, int z) {
if(z > x + y) return false;
unordered_set<int> vis;
queue<int> q;
q.push(0);
vis.insert(0);
while(!q.empty()){
auto t = q.front();
q.pop();
if(t == z) return true;
if(t + x <= x + y && !vis.count(t + x)){
vis.insert(t + x);
q.push(t + x);
}
if(t + y <= x + y && !vis.count(t + y)){
vis.insert(t + y);
q.push(t + y);
}
if(t - x >= 0 && !vis.count(t - x)){
vis.insert(t - x);
q.push(t - x);
}
if(t - y >= 0 && !vis.count(t - y)){
vis.insert(t - y);
q.push(t - y);
}
}
return false;
}
};
解法二:裴蜀定理
对于题目给定的操作,我们可以认为每次操作只会让 两个水壶的总的水量 增加 x x x , 减少 x x x ,增加 y y y,减少 y y y。
- 因为不会出现 两个桶同时有水并且都不是满的。题目给定的三种操作,无论怎么组合使用,一定至少会有一个桶为空 或者 满。
- 对一个没满的桶加水是无意义的。因为如果另一个桶是空的,那么这个操作的结果等价于直接从初始状态给这个桶加满水;而如果另一个桶是满的,那么这个操作的结果等价于从初始状态分别给两个桶加满。
- 另外,把一个不满的桶里面的水倒掉也是无意义的。因为如果另一个桶是空的,那么这个操作的结果等价于回到初始状态;而如果另一个桶是满的,那么这个操作的结果等价于从初始状态直接给另一个桶倒满。
所以实际上,每次操作只会给总的水量带来 x x x 或者 y y y 的变化量,可以用下面的式子表示:
a x + b y = z ax + by = z ax+by=z
即,裴蜀定理。
该式成立的条件是 z z z 是否能整除 g c d ( a , b ) gcd(a,b) gcd(a,b)。
时间复杂度: O ( l o g ( m i n ( x , y ) ) ) O(log(min(x,y))) O(log(min(x,y)))
C++代码:
class Solution {
public:
bool canMeasureWater(int x, int y, int target) {
if(target > x + y) return false;
return target % gcd(x,y) == 0;
}
};