leetcode 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
刚开始的思路想直接但模拟水壶这个过程看可能的取值,后面绝的是在模拟不了啦。看了以下官方的解答。
第一种解法:利用深度优先遍历搜索所有可能满足的情况, 每次总共右六种情况, X倒满, X倒控, Y倒满, Y倒空, X倒到Y, Y倒到X
由于情况实在太多,我们需要记录每次计算过的数据,防止重复计算。实现的时候出现一个问题,重写equals后,没有重写hashCode方法导致重复计算问题。
static class Point { int remainX; int remainY; public Point(int remainX, int remainY) { this.remainX = remainX; this.remainY = remainY; } @Override public int hashCode() { return Integer.hashCode(remainX)+Integer.hashCode(remainY); } @Override public boolean equals(Object obj) { Point point = (Point) obj; return point.remainX == this.remainX && point.remainY == this.remainY; } } /** * 深度优先遍历 * @param x * @param y * @param z * @return */ public boolean canMeasureWater2(int x, int y, int z) { Stack<Point> stack = new Stack<>(); stack.push(new Point(0, 0)); HashSet<Point> allVisitedDatas = new HashSet<>(); while (!stack.isEmpty()) { Point point = stack.pop(); int remainX = point.remainX; int remainY = point.remainY; if (remainX + remainY == z) return true; if (allVisitedDatas.contains(point)) continue; else allVisitedDatas.add(point); // X倒满 stack.push(new Point(x, remainY)); // X倒空 stack.push(new Point(0, remainY)); // Y倒满 stack.push(new Point(remainX, y)); // Y倒空 stack.push(new Point(remainX, 0)); // X倒到Y stack.push(new Point(remainX - Math.min(remainX, y - remainY), remainY + Math.min(remainX, y - remainY))); // Y倒到X stack.push(new Point(remainX + Math.min(x - remainX, remainY), remainY - Math.min(remainY, x - remainX))); } return false; }
第二种方法使用贝祖定理, 本质上倒水问题可以看作ax+by=z, 此问题存在解的条件是z是x和y最大公约数的倍数。当然,我们还需要知道最终最多只能有两个水壶装水,同时最终至少有一个水壶为空或者满。
// 贝祖定理 ax+by=z 存在z是a,b的最大公约数的倍数 public boolean canMesureWater1(int x, int y, int z){ // 首先判断约束条件
if (x + y < z) return false; if (x == 0 || y == 0) { return z == 0 || x + y == z; } int tmpt = -1; if (y > x) { // 始终保持x>=y tmpt = x; x = y; y = tmpt; } while ((tmpt = x % y) != 0) { x = y; y = tmpt; } return z % y == 0; }