A clear explanation of Mirror Reflection using room unfolding, least common multiples, and parity.
Problem Restatement
We have a square room with mirrored walls.
The side length of the room is p.
A laser starts from the southwest corner. It first hits the east wall at a distance q from receptor 0.
There are three receptors:
| Receptor | Corner |
|---|---|
0 | Southeast corner |
1 | Northeast corner |
2 | Northwest corner |
The southwest corner has no receptor.
The laser reflects from the mirrors until it reaches one of the receptors.
Return the receptor number that the laser reaches first.
Input and Output
| Item | Meaning |
|---|---|
| Input | p, the side length of the square room |
| Input | q, the height where the laser first hits the east wall |
| Output | The receptor number: 0, 1, or 2 |
| Constraint | 1 <= q <= p <= 1000 |
| Guarantee | The laser eventually reaches a receptor |
Function shape:
class Solution:
def mirrorReflection(self, p: int, q: int) -> int:
...Examples
Example 1:
p = 2
q = 1The room has side length 2.
The laser first reaches the east wall at height 1.
After reflecting, it eventually reaches the northwest corner.
So the answer is:
2Example 2:
p = 3
q = 1The laser reaches the northeast corner.
So the answer is:
1First Thought: Simulate the Reflection
One direct idea is to simulate the ray.
Track:
- Current position
- Current direction
- Which wall the ray hits next
- How the direction changes after reflection
This is possible, but it is unnecessarily complicated.
The ray can bounce many times. Handling floating-point positions and mirror direction changes also makes the implementation more error-prone.
A cleaner approach is to avoid reflection entirely.
Key Insight
Instead of reflecting the laser, reflect the room.
When the laser hits a wall, imagine that it continues straight into a mirrored copy of the room.
So the laser travels in a straight line across repeated square rooms.
The ray first hits the east wall at height q, so for every horizontal distance p, the vertical height increases by q.
We need the first time the laser reaches a corner.
That happens when the vertical distance traveled is a multiple of p.
So we need the smallest positive distance that is a multiple of both p and q.
That value is:
lcm(p, q)Let:
vertical_rooms = lcm(p, q) // p
horizontal_rooms = lcm(p, q) // qThese values tell us which repeated room contains the receptor.
Only their parity matters.
horizontal_rooms | vertical_rooms | Receptor |
|---|---|---|
| odd | odd | 1 |
| odd | even | 0 |
| even | odd | 2 |
The case where both are even cannot be the first receptor hit, because then we could divide both by 2 and find an earlier corner.
Algorithm
Compute:
g = gcd(p, q)Then reduce:
p_reduced = p // g
q_reduced = q // gThese reduced values carry the same parity information as the LCM room counts.
Now decide by parity:
- If
p_reducedis even, return2. - Else if
q_reducedis even, return0. - Otherwise, return
1.
This corresponds to:
Reduced p | Reduced q | Result |
|---|---|---|
| even | odd | 2 |
| odd | even | 0 |
| odd | odd | 1 |
Correctness
In the unfolded-room view, the laser travels in a straight line instead of reflecting.
The laser reaches a receptor exactly when it reaches a corner of some copied room. A copied room corner occurs when both the horizontal and vertical distances align with multiples of p.
The vertical distance grows by q for every horizontal room width p, so the first corner hit occurs at the least common multiple of p and q.
After dividing by gcd(p, q), the remaining parity tells us whether the final corner is on the left or right side, and whether it is on the top or bottom side.
If reduced p is even and reduced q is odd, the ray ends on the left top corner, which is receptor 2.
If reduced p is odd and reduced q is even, the ray ends on the right bottom corner, which is receptor 0.
If both are odd, the ray ends on the right top corner, which is receptor 1.
These are all possible first-hit cases, so the algorithm returns the correct receptor.
Complexity
| Metric | Value | Why |
|---|---|---|
| Time | O(log min(p, q)) | Computing gcd uses Euclid’s algorithm |
| Space | O(1) | Only a few integers are stored |
Implementation
from math import gcd
class Solution:
def mirrorReflection(self, p: int, q: int) -> int:
g = gcd(p, q)
p //= g
q //= g
if p % 2 == 0:
return 2
if q % 2 == 0:
return 0
return 1Code Explanation
First, compute the greatest common divisor:
g = gcd(p, q)Then reduce both numbers:
p //= g
q //= gThis removes the shared scale. We only care whether the reduced values are odd or even.
If reduced p is even:
if p % 2 == 0:
return 2the laser reaches receptor 2.
If reduced q is even:
if q % 2 == 0:
return 0the laser reaches receptor 0.
Otherwise both reduced values are odd:
return 1so the laser reaches receptor 1.
Testing
def test_mirror_reflection():
s = Solution()
assert s.mirrorReflection(2, 1) == 2
assert s.mirrorReflection(3, 1) == 1
assert s.mirrorReflection(4, 3) == 2
assert s.mirrorReflection(5, 2) == 0
assert s.mirrorReflection(6, 4) == 0
assert s.mirrorReflection(6, 3) == 2
print("all tests passed")
test_mirror_reflection()Test meaning:
| Test | Why |
|---|---|
p = 2, q = 1 | Standard example, reaches receptor 2 |
p = 3, q = 1 | Standard example, reaches receptor 1 |
p = 4, q = 3 | Reduced p even, receptor 2 |
p = 5, q = 2 | Reduced q even, receptor 0 |
p = 6, q = 4 | Reduction changes parity |
p = 6, q = 3 | Shared factor leaves reduced p even |