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. Web页面精确定位

    Web端页面定位相关 一.获取宽高相关属性 scrollHeight:获取对象的滚动高度: scrollLeft:设置或获取位于对象左边界和窗口中目前可见内容的最左端之间的距离: scrollTop: ...

  2. logical函数

    logical函数(逻辑函数) logical(x):x ~=0时,logical(x)=1:x = 0时,logical(x)=0

  3. 使用 PDBDownloader 解决 IDA 加载 ntoskrnl.exe 时符号不完全问题

    解决 IDA 加载 ntoskrnl.exe 时符号不完全问题 1. 问题:IDA加载xp系统的 ntoskrnl.exe 加载不完全. 2. 尝试过但未成功的解决方案: 1)配置好的IDA的 pdb ...

  4. ASP.NET Core快速入门(第6章:ASP.NET Core MVC)--学习笔记

    课程链接:http://video.jessetalk.cn/course/explore 良心课程,大家一起来学习哈! 任务40:介绍 1.Individual authentication 模板 ...

  5. ABP中文网的一些BUG

    之前一些翻译了的文档没有及时更新.比如 IAsyncCrudAppService接口在很久之前的版本就已经改为了ICrudAppService,如果是在官网下载的最新实例中IAsyncCrudAppS ...

  6. 重温CLR(十八) 运行时序列化

    序列化是将对象或对象图转换成字节流的过程,反序列化是将字节流转换回对象图的过程.在对象和字节流之间转换是很有用的机制. 1 应用程序的状态(对象图)可轻松保存到磁盘文件或数据库中,并在应用程序下次运行 ...

  7. tkinter中的message

    from tkinter import * root =Tk() root.title("message练习") myText = "2019年12月13日,下午一个人, ...

  8. css中的baseline

    这是css中的一个容易被人忽略的概念,今天在知乎上看到一个问题,这个问题应该是关于baseline,才去补习了一下关于baseline的知识,首先我来还原一下问题: <div style=&qu ...

  9. ANDROID培训准备资料之项目结构简单介绍

    Android Studio项目结构初步主要介绍下面几个文件夹,后续再补充 (1)java文件夹的介绍 (2)Res文件夹的介绍 (3)R文件的介绍 (4)Manifests文件夹的介绍 我们先看看整 ...

  10. Jmeter-While控制器

    Jmeter-While控制器 背景: 用作循环的控制器里, 最常用的就’循环控制器’和’While控制器’. 循环控制器仅能定义循环次数(永远和自定义次数). 缺乏判断能力.While控制器正好弥补 ...