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

    我的LeetCode:https://leetcode-cn.com/u/ituring/

    我的LeetCode刷题源码[GitHub]:https://github.com/izhoujie/Algorithmcii

    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
    

    解题思路

    思路1-我无法证明的一生二、二生四、四生万物算法...

    • 我的想法:x、y、x+y、|x-y|是四个基本数(去重后可能更少),若再更相递减能再获得一个不重复数(总数大于4个),说明由xy能获得的z范围是[1,x+y],否则z的值只能由四个基本数组合获得;
    • 按想法实现的算法通过了,效率不高,但是我好像不会证明这个东西;
    • 看了官解,感觉我这个跟贝祖定理有点靠近...有可以证明我这个想法数学实现的大佬麻烦指教一下;

    思路2-贝祖定理+GCD(算法思路说明来自LeetCode官方解答)

    预备知识:贝祖定理

    我们认为,每次操作只会让桶里的水总量增加 x,增加 y,减少 x,或者减少 y。

    你可能认为这有问题:如果往一个不满的桶里放水,或者把它排空呢?那变化量不就不是 x 或者 y 了吗?接下来我们来解释这一点:

    • 首先要清楚,在题目所给的操作下,两个桶不可能同时有水且不满。因为观察所有题目中的操作,操作的结果都至少有一个桶是空的或者满的;

    • 其次,对一个不满的桶加水是没有意义的。因为如果另一个桶是空的,那么这个操作的结果等价于直接从初始状态给这个桶加满水;而如果另一个桶是满的,那么这个操作的结果等价于从初始状态分别给两个桶加满;

    • 再次,把一个不满的桶里面的水倒掉是没有意义的。因为如果另一个桶是空的,那么这个操作的结果等价于回到初始状态;而如果另一个桶是满的,那么这个操作的结果等价于从初始状态直接给另一个桶倒满。

    因此,我们可以认为每次操作只会给水的总量带来 x 或者 y 的变化量。因此我们的目标可以改写成:找到一对整数 a, b,使得

    • ax + by = z

    而只要满足 z ≤ x+y,且这样的 a,b 存在,那么我们的目标就是可以达成的。这是因为:

    • 若 a≥0,b≥0,那么显然可以达成目标。

    • 若 a<0,那么可以进行以下操作:

    1. 往 y 壶倒水;

    2. 把 y 壶的水倒入 x 壶;

    3. 如果 y 壶不为空,那么 x 壶肯定是满的,把 x 壶倒空,然后再把 y 壶的水倒入 x 壶。

    4. 重复以上操作直至某一步时 x 壶进行了 a 次倒空操作,y 壶进行了 b 次倒水操作。

    • 若 b<0,方法同上,x 与 y 互换。

    而贝祖定理告诉我们,ax+by=z 有解当且仅当 z 是 x, y 的最大公约数的倍数。因此我们只需要找到 x,y 的最大公约数并判断 z 是否是它的倍数即可。

    复杂度分析

    时间复杂度:O(log(min(x,y))),取决于计算最大公约数所使用的辗转相除法。

    空间复杂度:O(1),只需要常数个变量。

    总结:数学很强大,数学是算法的基石啊...

    算法源码示例

    package leetcode;
    
    import java.util.Iterator;
    import java.util.TreeSet;
    
    /**
     * @author ZhouJie
     * @date 2020年3月21日 下午1:59:07 
     * @Description: 365. 水壶问题
     *
     */
    public class LeetCode_0365 {
    }
    
    class Solution_0365 {
    	/**
    	 * @author: ZhouJie
    	 * @date: 2020年3月21日 下午2:39:59 
    	 * @param: @param x
    	 * @param: @param y
    	 * @param: @param z
    	 * @param: @return
    	 * @return: boolean
    	 * @Description: 1-除去xy本身,x y互相加减及递归一次的加减值组成的set,
    	 * 				若set总数大于4说明可以生成1~x+y之间的任意z数,否则z只能是set的某两个散列数的组合
    	 * 				::这个无法证明...但是算法通过了,虽然效率不高。
    	 *
    	 */
    	public boolean canMeasureWater_1(int x, int y, int z) {
    		if (z == 0 || z == x || z == y) {
    			return true;
    		}
    		if (z > (x + y)) {
    			return false;
    		}
    		TreeSet<Integer> treeSet = new TreeSet<Integer>();
    		int a = Math.abs(x + y);
    		int b = Math.abs(x - y);
    		int c = Math.abs(x - b);
    		int d = Math.abs(y - b);
    		treeSet.add(a);
    		treeSet.add(b);
    		treeSet.add(c);
    		treeSet.add(d);
    		treeSet.add(x);
    		treeSet.add(y);
    		treeSet.remove(0);
    		int min = treeSet.first();
    		int size = treeSet.size();
    		if (size > 4) {
    			return true;
    		} else if (z < min) {
    			return false;
    		} else {
    			Iterator<Integer> ite = treeSet.iterator();
    			while (ite.hasNext()) {
    				if (treeSet.contains(z - ite.next().intValue())) {
    					return true;
    				}
    			}
    			return false;
    		}
    	}
    
    	/**
    	 * @author: ZhouJie
    	 * @date: 2020年3月21日 下午3:16:54 
    	 * @param: @param x
    	 * @param: @param y
    	 * @param: @param z
    	 * @param: @return
    	 * @return: boolean
    	 * @Description: 2-贝祖定理+GCD
    	 *
    	 */
    	public boolean canMeasureWater_2(int x, int y, int z) {
    		if (z == 0 || z == x || z == y) {
    			return true;
    		} else if (z > (x + y)) {
    			return false;
    		} else {
    			return z % gcd(x, y) == 0;
    		}
    	}
    
    	private int gcd(int x, int y) {
    		return y == 0 ? x : gcd(y, x % y);
    	}
    }
    
    
  • 相关阅读:
    html pre 元素
    获取不重复随机数
    CSS查找匹配原理和简洁高效
    排序
    javascript 去数组重复项
    asp.net页面生命周期
    经典 Javascript 正则表达式
    深入理解JavaScript定时机制
    排序简介
    理解 JavaScript 闭包
  • 原文地址:https://www.cnblogs.com/izhoujie/p/12539686.html
Copyright © 2011-2022 走看看