问题描述:【Math】858. Mirror Reflection
解题思路:
镜面反射。给一个四面都是镜子的正方形房间,除西南角外每个角落都放有一个接受器。墙壁长度为 p,一束激光从西南角射出与东墙相遇,入射点到右下角距离为 q 。返回光线最先遇到接收器编号(保证光线最终会遇到一个接收器)。
这道题刚开始画了一些图,也观察到一些规律,但没有总结好。参考一个大牛的思路:
把这个射线无限延长,肯定会到达某个方块的右上角(方块你在草稿纸上补齐)。这样,水平方向假设 x 个方块,垂直方向假设 y 个方块,y / x = q / p。它给的数据 p 和 q 都是整数,实际水平扩展到 p 个方块,垂直扩展到 q 个方块就满足了。自己看一下规律:x 是奇数,y 是奇数时,右上角是 1;x 是奇数,y 是偶数时,右上角是 0;x 是偶数,y 是奇数时,右上角是 2;x 是偶数,y 是偶数,右上角是发射点。最后一种情况把 x,y 同时除以 2 直到某一方不是偶数就行了。
为什么上述的思想是可行的呢?假设没有镜子,我们观察以下几种情况:

- 对于 p/q = 3 时,激光会到达右上角,由于第二个房间和原始房间是镜面对称的,而第三个房间和第二个房间也是镜面对称的,则第三个房间和原始房间就是一样的了,那么就可以假设一下,奇数房间和原始房间的布局相同,则是接收器 1。
- 对于 p/q = 4 时,激光到达了右上角,而偶数房间的布局是跟原始房间呈镜面反射的,则就是接受器 2 了。
- 对于 p/q = 3/2 时,我们需要复制出一个 2x3 大小的矩阵出来,在水平方向共有三个房间,水平方向有奇数个房间,和原始房间布局一致;竖直方向有偶数个房间,和原始房间呈镜面反射,则最右上角为接收器 0。
因此可以得出规律:
- p 为奇数,q 为奇数时,到达接收器 1。
- p 为偶数,q 为奇数时,到达接收器 2。
- p 为奇数,q 为偶数时,到达接收器 0。
为什么没有 p 和 q 均为偶数的情况呢?比如 p = 4, q = 2,其实只要我们画个图就知道,这个跟 p = 2, q = 1 的情况是一模一样的,若 p 和 q 均为偶数,那么那么一定可以同时除以 2。我们可以先对 p 和 q 进行判断,若二者同为偶数,则同时除以 2,直到不同时为偶数时,然后再带入上面归纳的三种情况求解即可。
Python3 实现:
class Solution:
def mirrorReflection(self, p: int, q: int) -> int:
while p % 2 == 0 and q % 2 == 0: # p和q同时为偶数,先进行同时除以2操作
p //= 2
q //= 2
if p % 2 == 0 and q % 2 == 1: #三种归纳情况的返回值
return 2
elif p % 2 == 1 and q % 2 == 1:
return 1
elif p % 2 == 1 and q % 2 == 0:
return 0
问题描述:【Math】1006. Clumsy Factorial
解题思路:
笨阶乘。给一个正整数 N,按照 *、/、+、- 顺序计算阶乘。
方法1(常规方法):
常规方法就是找规律,比如 N = 19,结果为: 19 * 18 / 17 + 16 - 15 * 14 / 13 + 12 - 11 * 10 / 9 + 8 - ..., 因为先计算乘除法,所以以每 4 项为一个整体,计算结果累加到总结果上,然后将 N 减 4 继续计算,直到 N < 4 停止。最后,对于 N < 4 单独处理,累加到结果上即可。
Python3 实现:
class Solution:
def clumsy(self, N: int) -> int:
if N == 1: return 1
elif N == 2: return 2
elif N == 3: return 6
ans = N * (N-1) // (N-2) + (N-3) # 前四项为正数
N -= 4
while N >= 4:
tmp = N * (N-1) // (N-2) # -30//4=-8而不是-7
ans += -tmp + (N-3) # tmp前面为负号
N -= 4
if N == 1: ans -= 1
elif N == 2: ans -= 2
elif N == 3: ans -= 6
return ans
上面是迭代方法,还可以递归计算,思路相同,即 f(19) = 19 * 18 / 17 + 16 - f(15),略。
方法2(数学证明):
这道题还可以采取精妙的数学证明的方法求解。可以证明这样的一个式子:
- i ∗ (i−1) / (i−2) = i ∗ (1 + 1 / (i−2)) = i + i / (i-2) = (i+1) + 2 / (i - 2)
因为我们要保留整数,所以我们希望:
- 2 / (i−2) < 1,即 i > 4
此时,我们知道 i ∗ (i−1) / (i−2) = i+1,当 i > 4 时。
所以我们的问题就变成了:
- i ∗ (i−1) / (i−2) + (i−3) − (i−4) ∗ (i−5) / (i−6) + rest = (i+1) + (i−3) − (i−3) + rest = (i+1) + rest
- 其中至少保证 (i - 4) > 4,即 i > 8
- rest 只有四种可能的情况,即 (+ 2 - 1)、(+ 3 - 2 * 1)、(+ 4 - 3 * 2 / 1)、(+ 5 - 4 * 3 / 2 + 1),分别对应 N % 4 == 1、N % 4 == 2、N % 4 == 3 以及 N % 4 == 0 四种情况,其中 N > 8。
因此,对于 N <= 8,我们可以直接计算出结果;对于 N > 8,我们将 N 模 4 取余,判断属于上述哪种情况,然后得到最后的结果。
Python3 实现:
class Solution:
def clumsy(self, N: int) -> int:
ansTo8 = [0, 1, 2, 6, 7, 7, 8, 6, 9] # N<=8的结果单独计算
if N <= 8:
return ansTo8[N]
if N % 4 == 0: # N>8的数字%4判断结果
return N + 1
elif N % 4 == 1:
return N + 2
elif N % 4 == 2:
return N + 2
elif N % 4 == 3:
return N - 1
网友评论