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
參考資料: