Leetcode.365 水壶问题
题目链接
Leetcode.365 水壶问题 mid
题目描述
有两个水壶,容量分别为 x
和 y
升。水的供应是无限的。确定是否有可能使用这两个壶准确得到 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<=1061 <= x, y, z <= 10^61<=x,y,z<=106
解法一:bfs
由于题目给定的操作,我们可以将两个水壶看成一个整体,总的水量 ttt 看成是一个状态,每次操作之后只会有如下四个状态:
- t+xt + xt+x (t+x≤x+y)(t + x \\leq x + y)(t+x≤x+y)
- t+yt + yt+y (t+y≤x+y)(t + y \\leq x + y)(t+y≤x+y)
- t−xt - xt−x (t−x≥0)(t - x \\geq 0)(t−x≥0)
- t−yt - yt−y (t−y≥0)(t - y \\geq 0)(t−y≥0)
我们就可以用从初始状态 0 开始(初始两个水壶都为空,故 t=0t = 0t=0) bfs,在这个过程中,我们用一个哈希表记录 已经访问过的状态。如果存在一个状态 t′=zt' = zt′=z,说明两个水壶可以得到 zzz 升水,故返回 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;}
};
解法二:裴蜀定理
对于题目给定的操作,我们可以认为每次操作只会让 两个水壶的总的水量 增加xxx , 减少 xxx ,增加 yyy,减少 yyy。
- 因为不会出现 两个桶同时有水并且都不是满的。题目给定的三种操作,无论怎么组合使用,一定至少会有一个桶为空 或者 满。
- 对一个没满的桶加水是无意义的。因为如果另一个桶是空的,那么这个操作的结果等价于直接从初始状态给这个桶加满水;而如果另一个桶是满的,那么这个操作的结果等价于从初始状态分别给两个桶加满。
- 另外,把一个不满的桶里面的水倒掉也是无意义的。因为如果另一个桶是空的,那么这个操作的结果等价于回到初始状态;而如果另一个桶是满的,那么这个操作的结果等价于从初始状态直接给另一个桶倒满。
所以实际上,每次操作只会给总的水量带来 xxx 或者 yyy 的变化量,可以用下面的式子表示:
ax+by=zax + by = z ax+by=z
即,裴蜀定理。
该式成立的条件是 zzz 是否能整除 gcd(a,b)gcd(a,b)gcd(a,b)。
时间复杂度: O(log(min(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;}
};