镜面反射

标签: 几何 数学 数论

难度: Medium

有一个特殊的正方形房间,每面墙上都有一面镜子。除西南角以外,每个角落都放有一个接受器,编号为 0, 1,以及 2

正方形房间的墙壁长度为 p,一束激光从西南角射出,首先会与东墙相遇,入射点到接收器 0 的距离为 q

返回光线最先遇到的接收器的编号(保证光线最终会遇到一个接收器)。

 

示例 1:

输入:p = 2, q = 1
输出:2
解释:这条光线在第一次被反射回左边的墙时就遇到了接收器 2 。

示例 2:

输入:p = 3, q = 1
输入:1

提示:

  • 1 <= q <= p <= 1000

Submission

运行时间: 21 ms

内存: 16.2 MB

class Solution:
    def mirrorReflection(self, p: int, q: int) -> int:
        # 我们可以假设没有北面的墙壁,无限延长东西两面镜子的长度,则光线会通过东西两面镜子的反射一直往北走,每次增加的纵向距离为 q。
        # 当光线走过的纵向距离为 p 的整数倍时,光线到达某个接收器。现在问题转化为了怎么求纵向距离以及怎么通过这个距离来判断光线最终将到达哪一个接收器。
        # 光线停止时最终向上走的距离肯定既是 p 的倍数,又是 q 的倍数,即为 p 和 q 的最小公倍数,设其为 k,可以根据 k 的奇偶性分为两种情况:
        #   1.当 k 是 p 的奇数倍时,光线到达北墙;
        #   2.当 k 为 p 的偶数倍时,光线到达南墙。
        # 因为题中保证了光线最终会遇到一个接收器,所以光线最终到达南墙必定会遇到接收器 0。
        # 若光线最终到达北墙,我们可以通过光线与东西墙接触的次数的奇偶性即 k%q 来确定光线最终会到达接收器 1 还是 2。
        # 若 k 是 q 的奇数倍,则光线最终会遇到接收器 1,否则会遇到接收器 2。

        # 求最大公约数
        # k = math.gcd(p, q)
        # # 相当于最小公倍数除以p
        # q //= k
        # # 相当于最小公倍数除以q
        # p //= k
        # if q % 2 and p % 2:
        #     return(1)
        # elif q % 2 and p % 2 == 0:
        #     return(2)
        # return(0)

        left = True
        upward = True
        y = 0
        while(True):
            if y == p:
                if not upward:
                    return(0)
                if left:
                    return(2)
                return(1)
            if y > p:
                y %= p 
                upward = not upward
            else:
                y += q
                left = not left

Explain

题解使用了模拟的思路。我们可以假设没有北面的墙壁,无限延长东西两面镜子的长度,光线会通过东西两面镜子的反射一直往北走,每次增加的纵向距离为 q。当光线走过的纵向距离为 p 的整数倍时,光线到达某个接收器。题解中使用了 left 和 upward 两个布尔变量分别表示光线当前是向左运动还是向右运动,以及是向上运动还是向下运动。通过模拟光线的运动过程,当光线到达北面或南面的墙壁时,根据光线的运动方向和位置来判断遇到了哪个接收器。

时间复杂度: O(p)

空间复杂度: O(1)

class Solution:
    def mirrorReflection(self, p: int, q: int) -> int:
        left = True # 表示光线当前是否向左运动
        upward = True # 表示光线当前是否向上运动
        y = 0 # 光线当前的纵坐标
        while(True):
            if y == p: # 光线到达北面或南面的墙壁
                if not upward: # 光线向下运动
                    return(0) # 光线遇到接收器 0
                if left: # 光线向左运动
                    return(2) # 光线遇到接收器 2
                return(1) # 光线遇到接收器 1
            if y > p: # 光线超出了北面墙壁
                y %= p # 光线从南面墙壁射入
                upward = not upward # 光线改变运动方向
            else:
                y += q # 光线向北运动 q 的距离
                left = not left # 光线改变运动方向

Explore

在物理中,光线的反射遵循反射定律,即入射角等于反射角,且反射只与光线到达时的角度和被反射面的性质有关。在此题中,墙面被视作完美镜面,因此每次光线到达墙面的行为只依赖于它到达那一刻的状态(即当前位置和前进方向),而与之前的路径或反射次数无关。这种处理简化了模型,使得问题更易于通过计算和编程解决。

在题解中,将y对p取余是为了模拟光线在无限延长的墙面中的行为。当光线超出北面墙壁时,实际上是光线达到了墙的边界并需要从对面(南面)重新进入,这相当于光线在垂直方向上的周期性行为。改变光线的向上运动状态模拟了光线在到达墙顶后向下反射的物理现象。这种处理是一种抽象的逻辑模拟,虽然简化了问题,但基本保持了光的反射行为的物理本质。

在题解中,当光线y等于p时,根据光线的水平运动方向来判断遇到的接收器。如果光线刚好在角落处反射,按照题解的逻辑,光线的方向已经足够决定它会遇到哪个接收器。在实际物理中,确实可能存在光线同时触及角落的两个接收器的情况,但在题解的模型中,这种不确定性通过假设光线在角落点只能触及一个特定接收器的方式被排除了,这是为了简化问题和避免复杂的边界处理。

在数学和物理模型中,假设无限延长的墙面是一种理想化的条件,用于简化问题的复杂性和方便计算。通过这种假设,可以将问题的空间转化为具有周期性质的环境,从而使得光线的行为可以通过较简单的数学表示来描述。这种假设虽然与现实情况有所出入,但它允许我们忽略边界效应,专注于光线的反射和传播行为,是问题解决中常用的一种抽象方法。