前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >leetcode365. Water and Jug Problem

leetcode365. Water and Jug Problem

作者头像
眯眯眼的猫头鹰
发布2019-03-13 16:45:02
3120
发布2019-03-13 16:45:02
举报
文章被收录于专栏:眯眯眼猫头鹰的小树杈

题目

代码语言:javascript
复制
You are given two jugs with capacities x and y litres. There is an infinite amount of water supply available. You need to determine whether it is possible to measure exactly z litres using these two jugs.

If z liters of water is measurable, you must have z liters of water contained within one or both buckets by the end.

Operations allowed:

Fill any of the jugs completely with water.
Empty any of the jugs.
Pour water from one jug into another till the other jug is completely full or the first jug itself is empty.
Example 1: (From the famous "Die Hard" example)

Input: x = 3, y = 5, z = 4
Output: True
Example 2:

Input: x = 2, y = 6, z = 5
Output: False

假设现在有两个杯子,每个杯子分别最多可以装x和y升水,假设现在水的供应量是无限的,问是否有可能用这两个杯子共同承装z升水,可以用两个杯子执行的操作如下:

  1. 将任何一个杯子装满水
  2. 倒掉任何一个杯子中的所有水
  3. 将一个杯子中的水倒进另一个杯子,直到另一个杯子满了或者是当前的杯子已经空了

比如,如果现在两个杯子A和B分别能装3升水和5升水,需要在两个杯子中共装4升水。我们可以找到这样一个序列满足题目要求:

  1. 将B杯倒满水并导入A中,此时A:3 B:2
  2. 将A杯倒空,并将B中的水倒入A中,此时A:2 B:0
  3. 将B杯装满并倒A中,此时A:3 B:4
  4. 将A杯倒掉,此时A:0 B:4

思路一:搜索

这里可以说我们变相的利用了深度/广度优先搜索来实现。通过深度/广度优先搜索我们可以实现遍历所有可能的场景,直到找到我们最终想要的结果,或者得到该结果无法达到的结论。假设我们知道当前水杯的情况为A最多可以放置x升水,B最多可以放置Y升水,而且A当前水杯中有a升水,B中有b升水,则由当前情况在一次操作之后可能产生以下几种情况:

  • 倒光A中的水:A:0 | B:b
  • 倒光B中的水:A:a | B:0
  • 装满A中的水:A:x | B:b
  • 装满B中的水:A:a | B:y
  • 将A中的水倒进B中:A:a - min(a, y-b) | B:b + min(a, y-b)
  • 将B中的水倒进A中:A:a + min(x-a, y) | B:b - min(x-a, y)

最后两种情况需要判断两个杯子的剩余水情况和可倒入水的情况

如果以上几种情况都不满足z,则我们再以以上几种情况为基础继续寻找可能的情况。这里可以使用HashSet来避免对情况的重复遍历。代码如下:

代码语言:javascript
复制
    public class Status{
        private int x;
        private int y;
        
        public int getX() {
            return x;
        }
        
        public int getY() {
            return y;
        }
        
        public int getWater() {
            return this.getX() + this.getY();
        }
        
        public Status(int x, int y) {
            this.x = x;
            this.y = y;
        }
        
        @Override
        public boolean equals(Object o) {
            if(o==null || !(o instanceof Status)) return false;
            if(this == o) return true;
            Status s = (Status) o;
            return this.getX() == s.getX() && this.getY() == s.getY();
        }
        
        @Override
        public int hashCode() {
            return this.getX() + 17 * this.getY();
        }
    }
    
    Set<Status> statusSet = new HashSet<Status>();
    public boolean canMeasureWaterDFS(int x, int y, int z) {
        if(x + y < z) return false;
        if(x == z || y == z || x + y == z) return true;
        return canMeasureWaterDFS(x, y , new Status(0, 0), z);
    }
    
    public boolean canMeasureWaterDFS(int x, int y, Status curStatus, int z) {
        if(statusSet.contains(curStatus)) return false;
        else if(curStatus.getWater() == z) return true;
        else{
            statusSet.add(curStatus);
            
            return canMeasureWaterDFS(x, y, new Status(x, curStatus.getY()), z)
                || canMeasureWaterDFS(x, y, new Status(curStatus.getX(), y), z)
                || canMeasureWaterDFS(x, y, new Status(curStatus.getX(), 0), z)
                || canMeasureWaterDFS(x, y, new Status(0, curStatus.getY()), z)
                || canMeasureWaterDFS(x, y, new Status(
                                curStatus.getX() - Math.min(curStatus.getX(), y-curStatus.getY()),
                                curStatus.getY() + Math.min(curStatus.getX(), y-curStatus.getY())
                        ),
                        z)
                || canMeasureWaterDFS(x, y, new Status(
                                curStatus.getX() + Math.min(x - curStatus.getX(), curStatus.getY()),
                                curStatus.getY() - Math.min(x - curStatus.getX(), curStatus.getY())
                        ), 
                        z);
        
        }
    }

思路二:数学

这里使用了一个数学结论叫做Bézout's identity,在该理论中,假设数字a和b有一个最大公约数d,则一定存在x和y满足ax+by=d。x,y的其它组合所得到的值一定是d的倍数。 这里x为负值时代表将杯子倒空,x为正值时代表将杯子装满。

代码语言:javascript
复制
    public boolean canMeasureWater(int x, int y, int z) {
        if(x == z || y == z || x + y == z) return true;
        if(x + y < z) return false;
        
        while( (x %= y) != 0 && (y %= x) != 0);
        return z % (x+y) == 0;
    }
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-11-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 题目
  • 思路一:搜索
  • 思路二:数学
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档