A move consists of taking a point (x, y) and transforming it to either (x, x+y) or (x+y, y).

Given a starting point (sx, sy) and a target point (tx, ty), return True if and only if a sequence of moves exists to transform the point (sx, sy) to (tx, ty). Otherwise, return False.

Examples:
Input: sx = 1, sy = 1, tx = 3, ty = 5
Output: True
Explanation:
One series of moves that transforms the starting point to the target is:
(1, 1) -> (1, 2)
(1, 2) -> (3, 2)
(3, 2) -> (3, 5) Input: sx = 1, sy = 1, tx = 2, ty = 2
Output: False Input: sx = 1, sy = 1, tx = 1, ty = 1
Output: True

Note:

  • sx, sy, tx, ty will all be integers in the range [1, 10^9].

这道题说有一个点的变换方式,就是可以将 (x, y) 变成 (x + y, y) 或 (x, x + y),然后给了我们两个坐标点,一个是起始点 (sx, sy),一个是目标点 (tx, ty),问利用这种转换方式能否将起始点转换为目标点。这题给了一个很大的限定条件,就是所有坐标的数字都是正数,即所有的点都在第一象限里。这是个很大的限定条件,因为这样的话,坐标数字变换的过程中总是在不断的变大,因为没有负数的存在,就不会缩小。这样的话,只要发现只要起始点中的横纵坐标有任意一个大于了目标点的横纵坐标,那么直接返回 false 就可以了。首先,可以先来想想 brute force 怎么做,非常的直截了当,先判断之前说的返回 false 的两种情况,再判断如果起始点等于了目标点,返回 true,然后就是调用两个递归函数了,毫无悬念的 TLE 了,可以参见官方解法贴中的代码。令博主感到意外的是,这道题的时间要求很苛刻啊,官方解题贴中的前三种解法全都 TLE 了,但是经过分析后发现,前三种方法 TLE 是必然的,因为没用使用到此题想考察的核心要点。这道题的标签是 Math,对于博主来说,标记为 Math 的题跟脑筋急转弯 brainteaser 没啥区别,因为都很难想出来。再想想为啥 brute force 的解法会超时,如果起始点的数字很小的话,而目标点的数字特别的巨大,那么仅仅通过加法来慢慢的累加到的一个巨大的数,怎么可能不超时。快速累加的高效方法是乘法,但要知道需要累加的个数,就需要用除法来计算,其实我们对累加的个数也不那么感兴趣,而是对余数感兴趣,那么求余运算就是很高效的方法。求余运算是将数字变小的操作,可以将目标数字缩小,看能否缩小到起始位置,也是符合题意的,只不过此时的变换方式由加法变为了减法而已。

我们的目标是将 tx 和 ty 分别缩小到 sx 和 sy,不可能一步就缩小到位,那么这肯定是一个循环,终止条件是 tx 和 ty 中任意一个小于了 sx 和 sy,在循环内部,想要缩小 tx 或 ty,先缩小两者中较大的那个,若 tx 大于 ty,可以尝试缩小 tx,但是如果此时 ty 等于 sy 了话,可以迅速判断出结果,通过计算此时 tx 和 sx 的差值是否是 ty 的倍数,因为此时 ty 不能改变了,只能缩小 tx,若能通过减去整数倍数个 ty 得到 sx 的,就表示可以到达。如果 ty 不等于 sy 的话,那么直接 tx 对 ty 取余即可。同理,若 ty 大于 tx,我们可以尝试缩小 ty,但是如果此时 tx 等于 sx 了话,我们可以迅速判断出结果,通过计算此时 ty 和 sy 的差值是否是 tx 的倍数,如果 tx 不等于 sx 的话,那么直接 ty 对 tx 取余即可。循环退出后检测起始点和目标点是否相等,参见代码如下:

解法一:

class Solution {
public:
bool reachingPoints(int sx, int sy, int tx, int ty) {
while (tx >= sx && ty >= sy) {
if (tx > ty) {
if (ty == sy) return (tx - sx) % ty == ;
tx %= ty;
} else {
if (tx == sx) return (ty - sy) % tx == ;
else ty %= tx;
}
}
return tx == sx && ty == sy;
}
};

下面这种解法将没有在循环内部处理相等的情况,而是无脑缩小 tx 和 ty,最后循环退出后,再来判断 tx 和 ty 的关系,然后快速的判断,由于取余运算缩小的太快了,所以博主不认为二者的运行效率能差多少,参见代码如下:

解法二:

class Solution {
public:
bool reachingPoints(int sx, int sy, int tx, int ty) {
while (tx >= sx && ty >= sy) {
if (tx > ty) tx %= ty;
else ty %= tx;
}
if (tx > ty) return tx == sx && ty == sy % sx;
return ty == sy && tx == sx % sy;
}
};

下面这种写法跟上面的没有太大的区别,就看起来更加整齐一些,博主有强迫症吗???不过需要注意的是,需要在最前面加一个判定条件,目标点的横纵坐标都必须大于等于起始点的横纵坐标,因为坐标点横纵坐标都是正数,变换方式是加法,所以只能越加越大,参见代码如下:

解法三:

class Solution {
public:
bool reachingPoints(int sx, int sy, int tx, int ty) {
if (tx < sx || ty < sy) return false;
while (tx >= sx && ty >= sy) {
if (tx > ty) tx %= ty;
else ty %= tx;
}
if (tx == sx) return (ty - sy) % sx == ;
if (ty == sy) return (tx - sx) % sy == ;
return false;
}
};

再来看一种递归的写法,就四行啊,其实就是用取余运算代替加法优化了 brute force 的解法,参见代码如下:

解法四:

class Solution {
public:
bool reachingPoints(int sx, int sy, int tx, int ty) {
if (tx < sx || ty < sy) return false;
if (tx == sx && (ty - sy) % sx == ) return true;
if (ty == sy && (tx - sx) % sy == ) return true;
return reachingPoints(sx, sy, tx % ty, ty % tx);
}
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/780

参考资料:

https://leetcode.com/problems/reaching-points/solution/

https://leetcode.com/problems/reaching-points/discuss/114726/C++-Simple-iterative.

https://leetcode.com/problems/reaching-points/discuss/122916/concise-c++-solution

https://leetcode.com/problems/reaching-points/discuss/116110/C++-iterative-solution

https://leetcode.com/problems/reaching-points/discuss/114732/Java-Simple-solution-with-explanation

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] 780. Reaching Points 到达指定点的更多相关文章

  1. [LeetCode] Reaching Points 到达指定点

    A move consists of taking a point (x, y) and transforming it to either (x, x+y) or (x+y, y). Given a ...

  2. LeetCode 780. Reaching Points

    题目链接:https://leetcode.com/problems/reaching-points/ 题意:给定操作可以使点(x,y)变为点(x+y,y)或者点(x,x+y).现已知初始点(sx,s ...

  3. 780. Reaching Points

    idea: 1.从后向前找 2.while (tx > ty) tx -= ty; 替为 % 操作 3.经过循环后,必定只有两种情况才true sx == tx && sy &l ...

  4. 【leetcode】Reaching Points

    题目如下: A move consists of taking a point (x, y) and transforming it to either (x, x+y) or (x+y, y). G ...

  5. 【NX二次开发】Block UI 指定点

    属性说明 属性   类型   描述   常规           BlockID    String    控件ID    Enable    Logical    是否可操作    Group    ...

  6. [Swift]LeetCode780. 到达终点 | Reaching Points

    A move consists of taking a point (x, y) and transforming it to either (x, x+y) or (x+y, y). Given a ...

  7. Java实现 LeetCode 780 到达终点(逻辑题)

    780. 到达终点 从点 (x, y) 可以转换到 (x, x+y) 或者 (x+y, y). 给定一个起点 (sx, sy) 和一个终点 (tx, ty),如果通过一系列的转换可以从起点到达终点,则 ...

  8. [LeetCode] 149. Max Points on a Line 共线点个数

    Given n points on a 2D plane, find the maximum number of points that lie on the same straight line. ...

  9. 【leetcode】Max Points on a Line

    Max Points on a Line 题目描述: Given n points on a 2D plane, find the maximum number of points that lie ...

随机推荐

  1. 《一起学mysql》5

    基准函数   用于评估不同机器之间的性能差别   MariaDB [jason]> select benchmark(10000000,md5('test')); +-------------- ...

  2. Comment file

    /// This is the head comment of a file. /*********************************************************** ...

  3. mysql id 自增实现

    1.在mysql中建表 2.使用: >insert into 表名 values(id,'www',66); 连续运行5次后结果: =============================== ...

  4. CSS3实现文字描边的2种方法

    问题 最近遇到一个需求,需要实现文字的描边效果,如下图           解决方法一     首先想到去看CSS3有没有什么属性可以实现,后来被我找到了text-stroke     该属性是一个复 ...

  5. openssl编译安装

    最新版本可以在这个网站下载: https://www.openssl.org/source/ wget https://www.openssl.org/source/openssl-1.1.1c.ta ...

  6. 关于 BenchmarkDotNet

    using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Order; using System.Reflection; namespace Be ...

  7. 【转】asp.Net Core免费开源分布式异常日志收集框架Exceptionless安装配置以及简单使用图文教程

    最近在学习张善友老师的NanoFabric 框架的时了解到Exceptionless : https://exceptionless.com/ !因此学习了一下这个开源框架!下面对Exceptionl ...

  8. Docker 指定数据储存目录

    Docker 指定储存目录(原参数 --graph 已经失效 .) 方法一 一.在 Docker 配置文件中配置 /etc/docker/daemon.json 下面的命令是在 daemon.json ...

  9. C 输入和输出、char类型

    参考链接:https://www.runoob.com/cprogramming/c-input-output.html 标准输入输出头文件stdio.h #include是一个预处理指令,用于引入s ...

  10. 1-HTTPS之SNI介绍

    原文:https://blog.51cto.com/zengestudy/2170245 介绍 早期的SSLv2根据经典的公钥基础设施PKI(Public Key Infrastructure)设计, ...