[LeetCode] 858. Mirror Reflection 镜面反射



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 01, 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 0th 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. 1 <= p <= 1000
  2. 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为奇数时,到达接收器1。
  • p为奇数,q为偶数时,到达接收器0。
  • p为偶数,q为奇数时,到达接收器2。

那你可能会有疑问了,为啥没有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



参考资料:

https://leetcode.com/problems/mirror-reflection/

https://leetcode.com/problems/mirror-reflection/discuss/141765/Java-short-solution-with-a-sample-drawing

https://leetcode.com/problems/mirror-reflection/discuss/141826/1-line-C%2B%2B-solution-using-gcd-only-4ms

https://leetcode.com/problems/mirror-reflection/discuss/141773/C%2B%2BJavaPython-1-line-without-using-any-package-or



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

相关文章
相关标签/搜索