[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 題目講解彙總(持續更新中...)

相關文章
相關標籤/搜索