[LeetCode] Water and Jug Problem

[LeetCode] Water and Jug Problem

题目

https://leetcode.com/problems/water-and-jug-problem/

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既表示两个罐子,也表示罐子中的容量。

例1:Input: x = 3, y = 5, z = 4,Output: True

需要注意的是,时时刻刻x+y都是一种z的可能值,在本文的描述中不再赘述。

z 所有取值的情况:
x,y都灌满的情况:3(x),5(y),8(x+y)
初始y是灌满的,
*倒出x这么多,y剩余水:2(y-x)
将y剩余的水倒入空的x中,x的剩余空间:1(3-2)
然后y灌满,将y倒入有部分水的x(有1),此时y剩余水:4(5-1)
然后重复*号的处理(注:冒号后面的值是变化的)。

结束条件:当某一次处理之后,x的剩余为0,或者y的剩余为0.

继续把上面的处理完:
当前y剩余4,每次倒出x(3)这么多,y剩余水:1(4-3)
将y剩余的水1倒入空的x中,x的剩余空间:2(3-1)
然后y灌满,将y倒入x,使x满,此时y剩余水:3(5-2)

当前y剩余3,倒出x(3)这么多,y没有水了(3-3),结束。

再次强调,每种情况x+y都是一种z的可能值,在本文的描述中不再赘述。

上面的描述中出现了4的情况,所以z=4是可以做到的。

例2:Input: x = 3, y = 11, z = 13,Output: True

z 所有取值的情况:
3(x),11(y),14(x+y)
从y中倒出x:8(y-x),5(y-2x),2(y-3x)
将2倒入x,再从满y中倒水将x倒满,y剩余水:10(11-(3-2)) ,(3-2)是x剩余空间。
此时y是10,从y中倒出x:7(y-x),4(y-2x),1(y-3x)
将1倒入x,再从满y中倒水将x倒满,y剩余水:9(11-(3-1)),(3-1)是x的剩余空间。
此时y是9,从y中倒出x:6(y-x),3(y-2x),0(y-3x)
y为0表示没有水了,不能再继续下去了,结束。

z=13出现在x+y上,即x=3,y=10的时候。
所以每次计算出x或者y的时候,都要判断x+y是否与z相同。

代码

33 / 33 test cases passed.
Runtime: 0 ms

注:这个时间不准,有时3ms,有时0ms。

bool canMeasureWater(int x, int y, int z) {
    /*如果 x<y, 那么可能的取值有:
    x,y, x+y, y-kx(k取值:0~y/x),x中储存y%x, 此时x+y也是一个z值。
    然后将y倒入x,y更新为y-(x-y%x),(此时x+y也是一个z值), 然后继续y-kx的操作,
    即每次更新y之后,处理y-kx,直到x=y为止,或者y==0为止。所有y-kx的值都是可能值。
    */
    if (z == 0) {
        return true;
    }
    if (x == 0) {
        return (y == z);
    }
    if (y == 0) {
        return (x == z);
    }
    if (x == y) {
        return (z == x);
    }
    if (z == x + y || z == x || z == y) {
        return true;
    }

    // 保持x < y
    if (x > y) {
        int temp = x;
        x = y;
        y = temp;
    }
    int orig_y = y;
    while (true) {
        // y - kx
        int max = y/x;
        int val = 0;
        for (int k = 1; k <= max; k++) {
            val = y - k * x;
            if (z == val) {
                return true;
            }
        }
        int left = val;
        if (left == 0) {
            break;
        }
        if (left + y == z || left + x == z) {
            return true;
        }
        // update y
        y = orig_y - (x - left);// 将left倒入x,然后将满的y倒入x之后y的剩余
        if (y == 0) {
            break;
        }
        if (y == z || y+x == z) {
            return true;
        }
        while (y < x) {
            int temp = x - y;// y倒入x之后,x剩余空间
            y = orig_y - temp; // 倒满x之后y的剩余
            if (y == z || x+y == z) {
                return true;
            }
        }
    }

    return false;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值