3种解法 : 计算两水壶拼水问题

题目

有两个容量分别为 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


解法一(暴力法)

思路:目标容量是通过当前两个瓶子相互减,通过递归相减遍历出所有可能组合的,没去探寻规律,因此称为暴力法,不过其搜索的方式也可以称为深度优先搜索。如果递归找到返回True,如果遍历所有可能后没找到,则返回False

  1. 如果目标大于两个瓶子容量和或目标为0,特殊处理
  2. 如果目标大于两个瓶子容量,则减去大容量作为新目标容量,即原目标容量是新目标容量加上大容量
  3. 递归里面不断通过x和y对当前差值进行处理
  • 时间复杂度:O(x*y)
  • 空间复杂度:O(x*y)

递归的写法,在测试用例数值比较大的时候会超出递归深度,因此最前面两行是修改了Python默认的递归深度。(如果不修改深度,超出深度的测试用例为:104597,104623,123)。

# author: suoxd123@126.com
import sys 
sys.setrecursionlimit(1000000) 
class Solution:
    def deIn(self,s,x,y,z,t):
        if z == t:# 找到
            return True
        if s.__contains__(t):# 已经出现过,则不再递归
            return False
        s.add(t)
        return self.deIn(s,x,y,z,abs(x-t)) or self.deIn(s,x,y,z,abs(y-t))

    def canMeasureWater(self, x: int, y: int, z: int) -> bool:
        if z > x + y:
            return False
        if z in (0,x,y):#简单特例
            return True
        if z > max(x,y):
            z = z - max(x,y)
        s = set()
        return self.deIn(s,x,y,z,max(x,y)-min(x,y))

解法二(直线方程)

思路:由于每次倒水操作都是全部倒掉或者倒满,都可以看做是对x,y的整数次组合操作,即使用一个二元一次方程进行求解判断,将题目抽象为数学问题,可以理解为:

  1. 已知x,y,z三个正整数
  2. 判断是否存在两个整数a,b,使得线性方程可以满足:ax + by = z,即在以ab为变量构成的二维坐标系中,直线方程是否经过整数坐标
  3. a,b的约束条件为:不能同时大于等于1(同时等于1除外),即要检查的坐标点不考虑第一象限中(1,b)(a,1)的那一部分

在数论中有个贝祖定理,是这么说的:

  1. 若x,y是整数,且x和y的最大公约数为k,一定存在整数a和b,使得ax+by=k成立
  2. 进一步,等式ax+by=z有解的充要条件是:z是k的整数倍
  3. 另外,等式有解时必然有无穷多个整数解

从贝祖定理知道,本题目可以转换为判断,z是否能够整除x和y的最大公约数。

  1. ab的约束条件首先剔除(思路中的第3点)
  2. 辗转相除得到最大公约数
  3. 判断是否能整除最大公约数
class Solution:
# author: suoxd123@126.com
    def canMeasureWater(self, x: int, y: int, z: int) -> bool:
        if z > x + y:#剔除约束条件
            return False
        if z in (0,x,y):#简单特例
            return True
        x, y = max(x,y), min(x,y)
        while y > 0:#辗转相除 得到 最大公约数
            y, x = x % y, y        
        return z % x == 0

解法三(深度优先搜索)

思路:每次把每种可能的操作都执行一遍,如果满足条件则返回True,否则每次把操作结果存入栈,每次取栈顶元素后持续查找,直到将每次操作的可能性都遍历完,本算法使用栈来达到深度优先搜索算法,也可以使用队列来达到广度优先搜索算法。

每次操作最多有以下6种操作方式:

  1. 把X倒满
  2. 把Y倒满
  3. 把X倒空
  4. 把Y倒空
  5. 把X倒入Y,可能把X倒空,也可能把Y倒满
  6. 把Y倒入X,可能把Y倒空,也可能把X倒满

为了减少重复遍历,引入visited集合进行过滤来判断,这种方式跟解法一类似,也可以理解成暴力法,即基于具体规则的暴力破解。

本解法使用循环来代替递归,用于避免超出Python的默认最大递归深度,当然也可以类似解法一使用递归的方式实现,其时间和空间复杂度跟解法一一样。。

class Solution:
# author: suoxd123@126.com
    def canMeasureWater(self, x: int, y: int, z: int) -> bool:
        stack = [(0,0)]
        visited = set()
        while stack:
            cx,cy = stack.pop()
            if z in (cx,cy,cx+cy):
                return True
            if (cx,cy) in visited:
                continue
            visited.add((cx,cy)) #加入标签减少重复遍历
            stack.append((x,cy))#1. 把X倒满
            stack.append((cx,y))#2. 把Y倒满
            stack.append((0,cy))#3. 把X倒空
            stack.append((cx,0))#4. 把Y倒空
            stack.append((cx-min(cx,y-cy),cy+min(y-cy,cx)))#5. 把X倒入Y,可能把X倒空,也可能把Y倒满
            stack.append((cx+min(x-cx,cy),cy-min(cy,x-cx)))#6. 把Y倒入X,可能把Y倒空,也可能把X倒满
        return False

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容

  • 水壶问题 题目来源:https://leetcode-cn.com/problems/water-and-jug-...
    大梦三千秋阅读 867评论 0 2
  • 在C语言中,五种基本数据类型存储空间长度的排列顺序是: A)char B)char=int<=float C)ch...
    夏天再来阅读 3,323评论 0 2
  • 【Description】有两个容量分别为 x升 和* y*升 的水壶以及无限多的水。请判断能否通过使用这两个水壶...
    Chiduru阅读 218评论 0 0
  • 本节我们将汇总一些 LeetCode 和数学相关的题。 数学是什么,我们就不需要长篇累牍地说了,从小学到大的。数学...
    思想永不平凡阅读 620评论 0 3
  • 由俭入奢易,由奢入俭难。 这话不仅仅适用于物质生活。用在小叮当的情感生活上也很恰当。 小叮当在妈妈不在的时候,无...
    cf6250bdae56阅读 215评论 0 0