zoukankan      html  css  js  c++  java
  • 水壶问题

    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; }
  • 相关阅读:
    icePDF去水印方法
    JAVA中pdf转图片的方法
    使用jQuery的ajax调用action的例子
    win7下JAVA环境变量配置方法
    Keil MDK仿真调试STM32的时候直接进入SystemInit函数
    山大王的个人勤奋和制度设计
    海思HI2115芯片-NB-IOT模块向外发短信测试
    UCOS III的时间片轮转调度的一个问题
    STM32F405的 ADC参考电压选择问题
    ACS712电流传感器应用
  • 原文地址:https://www.cnblogs.com/09120912zhang/p/12571608.html
Copyright © 2011-2022 走看看