欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Leetcode 365.水壶问题

程序员文章站 2022-04-05 11:55:36
...

Leetcode 365.水壶问题

有明确的初始状态和最终状态

可以使用BFS来解决,主要考虑下一步可能状态next的求解,是个体力活

import java.util.*;

class Solution {
    private int x;
    private int y;
    private HashSet<String> status = new HashSet<>();
    public boolean canMeasureWater(int x, int y, int z) {
        this.x = x;
        this.y = y;
        if(z == 0) return true;
        Queue<String> que = new LinkedList<>();
        que.add(x + " " + y);
        while (!que.isEmpty()) {
            String poll = que.remove();
            for (String next : next(poll)) {
                que.add(next);
                int num1, num2;
                String[] s = poll.split(" ");
                num1 = Integer.parseInt(s[0]);
                num2 = Integer.parseInt(s[1]);
                if(num1 ==  z || num2 == z || (num1 + num2 == z)){
                    return true;
                }
            }

        }
        return false;
    }

    private HashSet<String> next(String poll) {
        HashSet<String> nexts = new HashSet<>();
        int num1, num2;
        String[] s = poll.split(" ");
        num1 = Integer.parseInt(s[0]);
        num2 = Integer.parseInt(s[1]);
        //装满
        if (num1 < x && !status.contains(x + " " + num2)) {
            nexts.add(x + " " + num2);
            status.add(x + " " + num2);
        }
        if (num2 < y && !status.contains(num1 + " " + y)) {
            nexts.add(num1 + " " + y);
            status.add(num1 + " " + y);
        }
        //清空
        if (num1 > 0 && !status.contains(0 + " " + num2)) {
            status.add(x + " " + num2);
            nexts.add(x + " " + num2);
        }
        if (num2 > 0 && !status.contains(num1 + " " + 0)) {
            nexts.add(num1 + " " + 0);
            status.add(num1 + " " + 0);
        }
        //倒
        if (num1 > 0 && num2 < y) {
            int left = y - num2;
            if(num1 > left && !status.contains((num1 - left)+" "+ y)) {
                nexts.add((num1 - left) + " " + y);
                status.add((num1 - left) + " " + y);
            }
            if(num1 == left && !status.contains(0+" "+y)) {
                nexts.add(0 + " " + y);
                status.add(0 + " " + y);
            }
            if(num1 < left && !status.contains(0+" "+(num1+num2))) {
                nexts.add(0 + " " + (num1 + num2));
                status.add(0 + " " + (num1 + num2));
            }
        }
        if (num2 > 0 && num1 < x) {
            int left = x - num1;
            if(num2 > left && !status.contains(x+" "+ (num2 - left))) {
                nexts.add(x + " " + (num2 - left));
                status.add(x + " " + (num2 - left));
            }
            if(num2 == left && !status.contains(x+" "+0)) {
                nexts.add(x + " " + 0);
                status.add(x+" "+0);
            }
            if(num2 < left && !status.contains((num1+num2)+" "+0)) {
                nexts.add((num1 + num2) + " " + 0);
                status.add((num1+num2)+" "+0);
            }
        }
        return nexts;
    }
}

解法二:贝祖定理

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

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

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

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

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

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

ax+by=z

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

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

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

y 壶倒水;

y壶的水倒入 x 壶;

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

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

b<0,方法同上,xy 互换。

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

class Solution {
    boolean canMeasureWater(int x, int y, int z) {
        if (x + y < z) return false;
        if (x == 0 || y == 0) return z == 0 || x + y == z;
        return z % gcd(x, y) == 0;
    }

    private int gcd(int x, int y) {
        if(y%x == 0)
            return x;
        return gcd(y%x,x);
    }
    
}
相关标签: leetcode解题