365. 水壶问题(详解)

题目链接如下:

365. 水壶问题 - 力扣(LeetCode)

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

你可以:

装满任意一个水壶

清空任意一个水壶

将水从一个水壶倒入另一个水壶,直到接水壶已满,或倒水壶已空。

示例 1:

输入: x = 3,y = 5,target = 4

输出: true

解释:

按照以下步骤操作,以达到总共 4 升水:

  1. 装满 5 升的水壶(0, 5)。

  2. 把 5 升的水壶倒进 3 升的水壶,留下 2 升(3, 2)。

  3. 倒空 3 升的水壶(0, 2)。

  4. 把 2 升水从 5 升的水壶转移到 3 升的水壶(2, 0)。

  5. 再次加满 5 升的水壶(2, 5)。

  6. 从 5 升的水壶向 3 升的水壶倒水直到 3 升的水壶倒满。5 升的水壶里留下了 4 升水(3, 4)。

  7. 倒空 3 升的水壶。现在,5 升的水壶里正好有 4 升水(0, 4)。

参考:来自著名的 "Die Hard"

示例 2:

输入: x = 2, y = 6, target = 5

输出: false

示例 3:

输入: x = 1, y = 2, target = 3

输出: true

解释:同时倒满两个水壶。现在两个水壶中水的总量等于 3。

提示:

1 <= x, y, target <= 10^3

cpp 复制代码
两个水壶, 容量分别是x,y => 能否通过下面的操作得到target升水

操作:
1. 装满任意一个水壶
2. 清空任意一个水壶
3. 将水从一个水壶倒入另一个水壶,直到接水壶已满,或倒水壶已空。

注:可以两个水壶同时处于满的状态

观察用例1:
输入: x = 3,y = 5,target = 4
输出: true

如果target>x+y, 直接 return false
对于用例1的具体操作如下:
(0,5) -> (3,2) -> (0,2) -> (2,0) -> (2,5) -> (3,4) -> (0,4)
过程中, 每次操作完一次之后,操作的结果是两个桶至少有一个桶是空的或者满的

//ax+by=m (a,b,m 都是整数)
//该方程有整数解的充要条件是:m是a,b最大公约数的倍数

因此, 只要target是x,y最大公约数的倍数, 操作就有效


我的疑问是方程怎么和上述操作产生关系的, 有啥突破点吗?或者突破点就是找规律吗
重复执行把x壶装满后倒到y中, 如果y满了就把y倒掉
若x=3, y=5, target=2
(3,0) => (0,3) => (3,3) => (1,5) => (1,0) => (0,1) => (3,1) => (0,4) => (3,4) => (2,5) -> (2,0)
记录B壶在每轮开始时刻的水量:0 3 1 4 2 0....
在这个循环里, y中的水量会依次变成:
(0, 3, 6≡1, 9≡4, 12≡2 mod 5)
0,  x mod y,  2x mod y,  3x mod y, ... => n*x mod y
也就等价于集合 {0, gcd(x, y), 2gcd(x, y), ...}
gcd(3,5)=1,2 3 4 
这些恰好是模5下所有1的倍数 - 也就是所有余数0到4
所以每轮B的可达水量就是gcd(x,y)的倍数

因此, 任何时刻两壶中任意一壶或总水量,都是 gcd(x,y) 的倍数;同时总水量当然不会超过 x+y。因此出现 target > x+y 必不可能;target 不是 gcd(x,y) 的倍数也必不可能。
代码实现上只需要判断target是否是gcd(x,y)的倍数即可

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

JAVA:

java 复制代码
class Solution {
    private int gcd(int x,int y){
        if(y==0) return x;
        return gcd(y,x%y);
    }
    public boolean canMeasureWater(int x, int y, int target) {
        if(x+y<target){
            return false;
        }
        return target%gcd(x,y)==0;
    }
}

JS:

javascript 复制代码
/**
 * @param {number} x
 * @param {number} y
 * @param {number} target
 * @return {boolean}
 */
var canMeasureWater = function(x, y, target) {
    if(x+y<target){
        return false;
    }
    return target%gcd(x,y)==0;
};
const gcd=(x,y)=>y==0?x:gcd(y,x%y);

欢迎指出证明中的问题

感谢大家的点赞和关注,你们的支持是我创作的动力!

相关推荐
七夜zippoe9 分钟前
Java 生态监控体系实战:Prometheus+Grafana+SkyWalking 整合全指南(二)
java·grafana·prometheus
没事学AI20 分钟前
Caffeine三种缓存过期策略总结:原理、实战与调优
java·缓存·caffeine·缓存穿透防护·caffeine缓存
Micro麦可乐21 分钟前
为什么两个看似相等的 Integer 却不相等?一次诡异的缓存折扣商品 BUG 排查
java·缓存·bug·包装类判断·integer判断
普通网友21 分钟前
C++构建缓存加速
开发语言·c++·算法
带鱼吃猫22 分钟前
高并发内存池(三):手把手从零搭建ThreadCache线程缓存
数据结构·c++·链表·visual studio
杨杨杨大侠32 分钟前
手把手教你写 httpclient 框架(七)- 异步处理与性能优化
java·http·github
情深不寿31740 分钟前
传输层————TCP
linux·网络·c++·tcp/ip
ajassi20001 小时前
开源 java android app 开发(十四)自定义绘图控件--波形图
android·java·开源
江城开朗的豌豆1 小时前
React生命周期:从诞生到更新的完整旅程
前端·javascript·react.js
一叶飘零_sweeeet1 小时前
从 0 到 1 精通 SkyWalking:分布式系统的 “透视镜“ 技术全解析
java·skywalking