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
思路1:
数学方法。
已知往未满的水壶中倒水是没有意义的,每次操作给水的总量带来的变化为x或y。
因此可以得出存在一个整数a、b满足ax+by=z时,满足题意。
根据裴蜀定理量分别为 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
思路1:
数学方法。
已知往未满的水壶中倒水是没有意义的,每次操作给水的总量带来的变化为x或y。
因此可以得出存在一个整数a、b满足ax+by=z时,满足题意。
根据裴蜀定理当且仅当z是a、b的最小公约数倍数时有整数解a、b。
代码:
class Solution { public boolean canMeasureWater(int x, int y, int z) { if(x == 0 && y == 0) return z == 0; return z == 0 || (z % gcd(x,y) == 0 && x + y >= z); } static int gcd(int x,int y){ if(y == 0) return x; int r = x % y; return gcd(y,r); } }
思路2:
总共只有4种操作,将x、y灌满或清空,用哈希表存放所有可能的状态,用队列存放当前存活的各种状态。
通过BFS查找满足题意的操作方法。
代码(某一题解):
class Solution { public boolean canMeasureWater(int x, int y, int z) { //1.边界判断 if (x + y < z || z < 0) return false; //2.存放所有可能的状态,并用来防止重复进入同一状态 Set<Integer> set = new HashSet<>(); //3.存放当前存活的各种状态 Queue<Integer> queue = new LinkedList<>(); queue.offer(0); while (!queue.isEmpty()) { int curr = queue.poll(); //1.将x灌满;(curr + x <= x + y -->说明curr<=y,可以将curr 全部放入 y 中,x此时为空) if (curr + x <= x + y && set.add(curr + x)) queue.offer(curr + x); //2.将y灌满 if (curr + y <= x + y && set.add(curr + y)) queue.offer(curr + y); //3.将x清空 if (curr - x >= 0 && set.add(curr - x)) queue.offer(curr - x); //4.将y清空 if (curr - y >= 0 && set.add(curr - y)) queue.offer(curr - y); if (set.contains(z)) return true; } return false; } }