There is a special square room with mirrors on each of the four walls. Except for the southwest corner, there are receptors on each of the remaining corners, numbered 0
, 1
, and 2
.html
The square room has walls of length p
, and a laser ray from the southwest corner first meets the east wall at a distance q
from the 0
th receptor.git
Return the number of the receptor that the ray meets first. (It is guaranteed that the ray will meet a receptor eventually.)github
Example 1:算法
Input: p = 2, q = 1 Output: 2 Explanation: The ray meets receptor 2 the first time it gets reflected back to the left wall.
Note:布局
1 <= p <= 1000
0 <= q <= p
这道题给了咱们一个正方形的房间,说是四面都是镜子墙,而后在西南角有一个激光发射器,其他三个角都有接收装置,问咱们最终激光会被哪一个接收器接收。第一次读题时这句 "Return the number of the receptor that the ray meets first." 让博主理解错误了,觉得是让返回接收器的个数,觉得接收器也能反射激光到其对角的接收器,那么接收器2和0互相反射,就是返回通过了2个接收器,接收器1返回到反射点,就是返回通过了1个接收点,想的是一套一套的,结果人家让返回的是接收器的标号,我的以为将 number 改成 index 会减小些歧义。无所谓了,反正最终搞懂了题意就好了。其实这道题的正确解法还挺难想的,由于你们很容易走进的误区就是研究反射角啥的,而后算具体反射到了哪个位置,再算下一个位置,其实这样都将题目变复杂了。博主把这一类型归为脑筋急转弯 Brain Teaser,通常都有很巧妙的数学解法,并不须要太复杂的算法。code
首先从最简单的状况开始分析,当p和q相等的时候,那么激光直接到达接收器1,当 p/q = 2 的时候,就如例子中所示,通过右边的镜面反射后到达左上角的接受器2。那么咱们再来考虑下这三种状况 p/q = 3, p/q = 4, p/q = 3/2,并画出折射状况以下所示:htm
这里就有些比较好玩的规律了,咱们知道激光遇到镜面是会发生折射的,可是假如没有镜面,就会仍然沿直线前进,那么对于 p/q = 3 时,若咱们在右边增长大小相同的2个房间,则激光会到达右上角,因为第二个房间和原始房间是镜面对称的,而第三个房间和第二个房间也是镜面对称的,则第三个房间和原始房间就是同样的了,那么就能够假设一下,奇数房间和原始房间的布局相同。再来看上图中的 p/q = 4 时,咱们在右边复制了三个房间,在第四个房间的时候,激光到达了右上角,而第偶数个房间的布局是跟原始房间称镜面反射的,则就是接受器2了。其实有些时候,咱们不止要在右边复制房间,还须要在上面复制房间,好比当 p/q = 3/2 时,咱们须要复制出一个 2x3 大小的矩阵出来,在水平方向共有三个房间,是奇数则水平方向和原始房间布局一致,可是竖直方向也复制了房间,那么竖直方向有偶数个房间,则竖直方向和原始房间成镜面反射,则最右上角为接收器0。blog
分析到这里,咱们应该已经能总结出规律以下了:ci
那你可能会有疑问了,为啥没有p和q均为偶数的状况呢?好比 p = 4, q = 2,其实只要咱们画个图就知道,这个跟 p = 2, q = 1 的状况是一摸同样的,若p和q均为偶数,那么那么必定能够同时除以2,那么其实咱们能够先对p和q进行判断,若两者同为偶数,则同时除以2,直到不一样时为偶数时,而后再带入上面概括的三种状况求解便可,参见代码以下:leetcode
解法一:
class Solution { public: int mirrorReflection(int p, int q) { while (p % 2 == 0 && q % 2 == 0) { p /= 2; q /= 2; } if (p % 2 == 0) return 2; if (q % 2 == 0) return 0; return 1; } };
其实咱们能够进一步化简,将三种状况融为一个表达式便可,即 1 - p%2 + q%2,不信的话能够带数字验证一下,碉堡了有木有,参见代码以下:
解法二:
class Solution { public: int mirrorReflection(int p, int q) { while (p % 2 == 0 && q % 2 == 0) { p /= 2; q /= 2; } return 1 - p % 2 + q % 2; } };
其实不光是p和q同时为偶数的时候能够化简,只要p和q的最大公约数 Greatest Common Divisor 大于1时,均可以化简,好比,若 p = 6, q = 3 时跟 p = 2, q = 1 的状况也是同样,那咱们就能够先求出p和q的最大公约数,而后用p和q分别除以这个最大公约数,再带入上面的那个一行公式求解便可,参见代码以下:
解法三:
class Solution { public: int mirrorReflection(int p, int q) { return 1 - p / gcd(p, q) % 2 + q / gcd(p, q) % 2; } int gcd(int p, int q) { return q ? gcd(q, p % q) : p; } };
Github 同步地址:
https://github.com/grandyang/leetcode/issues/858
参考资料: