Leetcode.365 水壶问题

题目链接

Leetcode.365 水壶问题 mid

题目描述

有两个水壶,容量分别为 xy升。水的供应是无限的。确定是否有可能使用这两个壶准确得到 z升。

如果可以得到 z升水,最后请用以上水壶中的一或两个来盛放取得的 z升水。

你可以:

  • 装满任意一个水壶
  • 清空任意一个水壶
  • 从一个水壶向另外一个水壶倒水,直到装满或者倒空

示例 1:

输入: jug1Capacity = 3, jug2Capacity = 5, targetCapacity = 4
输出: true
解释:来自著名的 “Die Hard”

示例 2:

输入: jug1Capacity = 2, jug2Capacity = 6, targetCapacity = 5
输出: false

示例 3:

输入: jug1Capacity = 1, jug2Capacity = 2, targetCapacity = 3
输出: true

提示:

  • 1 < = x , y , z < = 1 0 6 1 <= x, y, z <= 10^6 1<=x,y,z<=106

解法一:bfs

由于题目给定的操作,我们可以将两个水壶看成一个整体,总的水量 t t t 看成是一个状态,每次操作之后只会有如下四个状态:

  • t + x t + x t+x ( t + x ≤ x + y ) (t + x \leq x + y) (t+xx+y)
  • t + y t + y t+y ( t + y ≤ x + y ) (t + y \leq x + y) (t+yx+y)
  • t − x t - x tx ( t − x ≥ 0 ) (t - x \geq 0) (tx0)
  • t − y t - y ty ( t − y ≥ 0 ) (t - y \geq 0) (ty0)

我们就可以用从初始状态 0 开始(初始两个水壶都为空,故 t = 0 t = 0 t=0bfs,在这个过程中,我们用一个哈希表记录 已经访问过的状态。如果存在一个状态 t ′ = z t' = z t=z,说明两个水壶可以得到 z z z 升水,故返回 true

bfs 结束,返回 false

时间复杂度: O ( n ) O(n) O(n)

C++代码:

class Solution {
public:
    bool canMeasureWater(int x, int y, int z) {
        if(z > x + y) return false;

        unordered_set<int> vis;
        queue<int> q;
        q.push(0);
        vis.insert(0);

        while(!q.empty()){
            auto t = q.front();
            q.pop();
            if(t == z) return true;

            if(t + x <= x + y && !vis.count(t + x)){
                vis.insert(t + x);
                q.push(t + x);
            }

            if(t + y <= x + y && !vis.count(t + y)){
                vis.insert(t + y);
                q.push(t + y);
            }

            if(t - x >= 0 && !vis.count(t - x)){
                vis.insert(t - x);
                q.push(t - x);
            }

            if(t - y >= 0 && !vis.count(t - y)){
                vis.insert(t - y);
                q.push(t - y);
            }

         }

        return false;
    }
};

解法二:裴蜀定理

对于题目给定的操作,我们可以认为每次操作只会让 两个水壶的总的水量 增加 x x x , 减少 x x x ,增加 y y y,减少 y y y

  • 因为不会出现 两个桶同时有水并且都不是满的。题目给定的三种操作,无论怎么组合使用,一定至少会有一个桶为空 或者 满。
  • 对一个没满的桶加水是无意义的。因为如果另一个桶是空的,那么这个操作的结果等价于直接从初始状态给这个桶加满水;而如果另一个桶是满的,那么这个操作的结果等价于从初始状态分别给两个桶加满。
  • 另外,把一个不满的桶里面的水倒掉也是无意义的。因为如果另一个桶是空的,那么这个操作的结果等价于回到初始状态;而如果另一个桶是满的,那么这个操作的结果等价于从初始状态直接给另一个桶倒满。

所以实际上,每次操作只会给总的水量带来 x x x 或者 y y y 的变化量,可以用下面的式子表示:

a x + b y = z ax + by = z ax+by=z

即,裴蜀定理。

该式成立的条件是 z z z 是否能整除 g c d ( a , b ) gcd(a,b) gcd(a,b)

时间复杂度: O ( l o g ( m i n ( x , y ) ) ) O(log(min(x,y))) O(log(min(x,y)))

C++代码:


class Solution {
public:
    bool canMeasureWater(int x, int y, int target) {
        if(target > x + y) return false;
        return target % gcd(x,y) == 0;
    }
};

你可能感兴趣的:(Leetcode,bfs,裴蜀定理)