[LeetCode] 780. 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 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 到达指定点的更多相关文章
- [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 ...
- LeetCode 780. Reaching Points
题目链接:https://leetcode.com/problems/reaching-points/ 题意:给定操作可以使点(x,y)变为点(x+y,y)或者点(x,x+y).现已知初始点(sx,s ...
- 780. Reaching Points
idea: 1.从后向前找 2.while (tx > ty) tx -= ty; 替为 % 操作 3.经过循环后,必定只有两种情况才true sx == tx && sy &l ...
- 【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 ...
- 【NX二次开发】Block UI 指定点
属性说明 属性 类型 描述 常规 BlockID String 控件ID Enable Logical 是否可操作 Group ...
- [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 ...
- Java实现 LeetCode 780 到达终点(逻辑题)
780. 到达终点 从点 (x, y) 可以转换到 (x, x+y) 或者 (x+y, y). 给定一个起点 (sx, sy) 和一个终点 (tx, ty),如果通过一系列的转换可以从起点到达终点,则 ...
- [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. ...
- 【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 ...
随机推荐
- PCL学习之:将超声数据按照PCL点云方式发布出去
前言:基于2D激光雷达的机器人,想让它跑自动导航,众所周知有2个比较明显的缺陷,1,那就是普通的激光雷达无法对玻璃或是镜面物体有反映; 2,机器人避障时只能对某一个平面的物体有反映,超过或者低于这个平 ...
- 大话设计模式Python实现-原型模式
原型模式(Prototype Pattern):用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象 一个原型模式的简单demo: #!/usr/bin/env python # -*- c ...
- LeetCode 21:合并两个有序链表 Merge Two Sorted Lists
将两个有序链表合并为一个新的有序链表并返回.新链表是通过拼接给定的两个链表的所有节点组成的. Merge two sorted linked lists and return it as a new ...
- .NET WebFrom跨时区项目时间问题处理方法
前段时间因为公司的一个 WebFrom 项目设计到跨时区的问题,处理了一段时间,终于解决了,写个博客记录一下,方便以后回顾以及给他人提供一个参考的方法. 本次的项目因为跨越了多个时区,在一些时间上会受 ...
- python——Tkinter图形化界面及threading多线程
Tkinter模块("Tk 接口")是Python的标准Tk GUI工具包的接口.Tk和Tkinter可以在大多数的Unix平台下使用,同样可以应用在Windows和Macinto ...
- web前端-bootstrap
1.什么是bootstrap 前端开发开源工具包 ,包含css样式库+jq插件 ,ui效果非常好 ,都是通过给标签加class选择器来实现功能的 2.特点 响应式布局:使用栅格系统可以把页面呈现在不同 ...
- JS初始
简单只和复杂值的区别 1.简单值 简单值表示JS中可用的数据或信息的最底层简单形式. 注:简单之不可被细化. 也就是说,数字是数字,字符是字符,布尔值是true或false,null和undefi ...
- memory一致性模型
https://homes.cs.washington.edu/~bornholt/post/memory-models.html https://www.cs.cmu.edu/afs/cs/acad ...
- youtube视频在线下载
youtube视频在线下载网站: https://www.clipconverter.cc/ youtube视频样例: https://www.youtube.com/watch?v=NMkgz0AR ...
- 理解Java方法增强
在实际开发中,我们往往需要对某些方法进行增强,常用的方法增强的方式有三种. 类继承 .方法覆盖 必须控制对象创建,才能使用该方式 装饰者模式方法加强 必须和目标对象实现相同接口或继续相同父类,特殊构造 ...