美文网首页
365. Water and Jug Problem

365. Water and Jug Problem

作者: codingXue | 来源:发表于2016-09-12 10:41 被阅读31次

问题描述

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 = 4Output: True
Example 2:
Input: x = 2, y = 6, z = 5Output: False

问题分析

这是一个很常见的问题,但之前我没有把它当成编程题做过,而只做过实例。
做法很简单,若z是x和y最大公约数的整数倍,则其可以被两个杯子称量。
问题是为什么是这么做的。
证明
裴蜀定理:对任意整数a、b和它们的最大公约数d,关于未知数x,y的线性丢番图方程(称为裴蜀等式
ax + by = m
有整数解当且仅当m是d的倍数。

设d = gcd(a, b), 则d|a且d|b,对任意整数x、y,有d|(xa + yb);
设s为xa + yb的最小正值,显然d|s;
设q = ⌊a/s⌋, r = a % s,则r = a - q*s = a - q * (x0a + y0b) = (1-qx0)a + (-qy0)b,可见r也是a、b的线性组合;
而0<=r<s,因此r=0,即s|a,同样s|b,因此s|d;
因此s = d,即由a、b线性组成的值最小为d,由a、b线性组成的值可为d的任意整数倍。

最大公约数和最小公倍数
辗转相除法求最大公约数gcd:
例如,求(319,377):
∵ 319÷377=0(余319)
∴(319,377)=(377,319);
∵ 377÷319=1(余58)
∴(377,319)=(319,58);
∵ 319÷58=5(余29),
∴ (319,58)=(58,29);
∵ 58÷29=2(余0),
∴ (58,29)= 29;
∴ (319,377)=29。
辗转相除法的时间复杂度:

参考关于欧几里得算法的时间复杂度
我们来看辗转相除法最多要做多少次模运算。设a>b>=1,构造数列{un}, u0 = a,u1 = b,uk = uk-2 mod uk-1,若总共需要n次模运算,则un = gcd(a, b),un+1 = 0。
我们比较数列{un}和斐波那契数列{Fn}, F0 = 1<=un , F1 =1<=un-1,因为uk+2 >= uk+1 + uk,因此uk >= Fn-k,因此,a = u0 >= Fn,b = u1 >= Fn-1,这就是说,如果辗转相除法要做n次模运算,则b >= Fn-1, 若b < Fn-1,则模运算次数必小于n。
根据斐波那契数列的性质:Fn-1 > (1.618)n / sqrt(5), 因此模运算次数为O(logn)。

最小公倍数:
a、b的最小公倍数=a * b / gcd(a, b)。

AC代码

class Solution(object):
    def canMeasureWater(self, x, y, z):
        """
        :type x: int
        :type y: int
        :type z: int
        :rtype: bool
        """
        if z == 0:
            return True
        if z > x + y:
            return False
        if x == 0:
            if y == 0:
                return False
            else:
                return z % y == 0
        elif y == 0:
            return z % x == 0
        gcd = self.getGCD(x, y)
        if z % gcd == 0:
            return True
        return False

    def getGCD(self, x, y):
        while x % y != 0:
            x, y = y, x % y
        return y

相关文章

网友评论

      本文标题:365. Water and Jug Problem

      本文链接:https://www.haomeiwen.com/subject/htdpettx.html