356. Line Reflection 🔒
Problem Description
You are given n
points on a 2D plane. Your task is to determine if there exists a vertical line (parallel to the y-axis) such that when all points are reflected across this line, the resulting set of points is identical to the original set.
A reflection across a vertical line means that for a point (x, y)
and a vertical line at position x = c
, the reflected point would be at (2c - x, y)
. The y-coordinate remains unchanged while the x-coordinate is mirrored across the line.
The problem asks you to return true
if such a line of reflection exists, and false
otherwise.
Key points to consider:
- The line of reflection must be vertical (parallel to the y-axis)
- After reflection, the set of points must be exactly the same as the original set
- Points can be repeated in the input (duplicates are allowed)
- The reflection line doesn't need to pass through any of the given points
For example:
- Points
[(1,1), (3,1)]
can be reflected across the linex = 2
to get the same set - Points
[(1,1), (2,2)]
cannot be reflected across any vertical line to get the same set
The solution works by finding the minimum and maximum x-coordinates among all points. If a line of reflection exists, it must be at x = (min_x + max_x) / 2
. Then it checks if every point (x, y)
has its corresponding reflected point (min_x + max_x - x, y)
in the original set.
Intuition
To find if points can be reflected across a vertical line to produce the same set, we need to first identify where this line of reflection could possibly be located.
Think about what happens when we reflect points across a vertical line - the leftmost point becomes the rightmost point and vice versa. This means the line of reflection must be exactly in the middle of the leftmost and rightmost points. If we have a minimum x-coordinate of min_x
and maximum x-coordinate of max_x
, the line of reflection must be at x = (min_x + max_x) / 2
.
Why is this the only possible location? Consider any other position for the line:
- If the line is to the left of center, the reflected rightmost point would extend beyond the original rightmost point
- If the line is to the right of center, the reflected leftmost point would extend beyond the original leftmost point
- Either case would create new points not in the original set
Once we know where the line must be, we need to verify that every point has its reflection in the original set. For a point (x, y)
and reflection line at x = c
, the reflected point is at (2c - x, y)
. Since c = (min_x + max_x) / 2
, we get 2c = min_x + max_x
, so the reflected point is at (min_x + max_x - x, y)
.
The verification process is straightforward: for each point in our set, check if its reflected counterpart exists. If even one point lacks its reflection, no valid line exists. We use a set data structure for O(1) lookup time when checking if reflected points exist.
This approach elegantly reduces the problem from finding a line to simply verifying if a specific line (the only candidate) works.
Solution Approach
The implementation follows a straightforward approach with three main steps:
-
Find the bounds and create a point set: We iterate through all points once to:
- Track the minimum x-coordinate (
min_x
) and maximum x-coordinate (max_x
) - Store all unique points in a set for O(1) lookup later
min_x, max_x = inf, -inf point_set = set() for x, y in points: min_x = min(min_x, x) max_x = max(max_x, x) point_set.add((x, y))
- Track the minimum x-coordinate (
-
Calculate the reflection line position: The sum
s = min_x + max_x
represents twice the x-coordinate of the reflection line. We don't need to divide by 2 because we'll use this sum directly in our reflection formula.s = min_x + max_x
-
Verify all points have their reflections: For each point
(x, y)
, we check if its reflection(s - x, y)
exists in the point set. The reflection formula comes from:- Reflection line is at
x = s/2
- Distance from point to line:
|x - s/2|
- Reflected x-coordinate:
s/2 - (x - s/2) = s - x
return all((s - x, y) in point_set for x, y in points)
- Reflection line is at
The all()
function returns True
only if every point has its corresponding reflection in the set. If any point lacks its reflection, it immediately returns False
.
Time Complexity: O(n) where n is the number of points - we iterate through the points twice (once to build the set and find bounds, once to verify reflections).
Space Complexity: O(n) for storing the point set.
The elegance of this solution lies in avoiding floating-point arithmetic by working with the sum s = min_x + max_x
directly instead of calculating the actual line position at s/2
.
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with the points: [(0,0), (1,0), (3,0), (4,0)]
Step 1: Find bounds and create point set
- Iterate through all points:
- Point (0,0): min_x = 0, max_x = 0
- Point (1,0): min_x = 0, max_x = 1
- Point (3,0): min_x = 0, max_x = 3
- Point (4,0): min_x = 0, max_x = 4
- Final bounds: min_x = 0, max_x = 4
- Point set: {(0,0), (1,0), (3,0), (4,0)}
Step 2: Calculate reflection line position
- s = min_x + max_x = 0 + 4 = 4
- This means the reflection line is at x = 4/2 = 2
Step 3: Verify all points have reflections
- Check (0,0): reflection at (4-0, 0) = (4,0) ✓ exists in set
- Check (1,0): reflection at (4-1, 0) = (3,0) ✓ exists in set
- Check (3,0): reflection at (4-3, 0) = (1,0) ✓ exists in set
- Check (4,0): reflection at (4-4, 0) = (0,0) ✓ exists in set
All points have their reflections in the original set, so return true
.
Visual representation:
Original points: 0 1 2 3 4 (x-axis) • • | • • ^ reflection line at x=2
When we reflect across x=2:
- (0,0) ↔ (4,0)
- (1,0) ↔ (3,0)
The reflected set {(4,0), (3,0), (1,0), (0,0)} is identical to the original set, confirming our answer.
Solution Implementation
1class Solution:
2 def isReflected(self, points: List[List[int]]) -> bool:
3 # Initialize variables to track the minimum and maximum x-coordinates
4 min_x, max_x = float('inf'), float('-inf')
5
6 # Create a set to store unique points for O(1) lookup
7 point_set = set()
8
9 # Iterate through all points to find min/max x values and populate the set
10 for x, y in points:
11 min_x = min(min_x, x)
12 max_x = max(max_x, x)
13 point_set.add((x, y))
14
15 # Calculate the sum of min and max x-coordinates
16 # This represents 2 times the x-coordinate of the reflection line
17 reflection_line_sum = min_x + max_x
18
19 # Check if every point has its reflection across the vertical line
20 # For a point (x, y), its reflection would be at (reflection_line_sum - x, y)
21 return all((reflection_line_sum - x, y) in point_set for x, y in points)
22
1class Solution {
2 public boolean isReflected(int[][] points) {
3 // Initialize constants for finding min/max x-coordinates
4 final int INFINITY = 1 << 30;
5 int minX = INFINITY;
6 int maxX = -INFINITY;
7
8 // Store all points in a HashSet for O(1) lookup
9 // Using List<Integer> to represent a point (x, y)
10 Set<List<Integer>> pointSet = new HashSet<>();
11
12 // First pass: find the minimum and maximum x-coordinates
13 // and add all points to the set
14 for (int[] point : points) {
15 minX = Math.min(minX, point[0]);
16 maxX = Math.max(maxX, point[0]);
17 pointSet.add(List.of(point[0], point[1]));
18 }
19
20 // Calculate the sum of min and max x-coordinates
21 // The reflection line is at x = (minX + maxX) / 2
22 // For a point (x, y), its reflection is (sum - x, y)
23 int sumOfBounds = minX + maxX;
24
25 // Second pass: check if every point has its reflection
26 for (int[] point : points) {
27 // Calculate the reflected x-coordinate
28 int reflectedX = sumOfBounds - point[0];
29
30 // Check if the reflected point exists in the set
31 if (!pointSet.contains(List.of(reflectedX, point[1]))) {
32 return false;
33 }
34 }
35
36 // All points have their reflections
37 return true;
38 }
39}
40
1class Solution {
2public:
3 bool isReflected(vector<vector<int>>& points) {
4 // Use a large constant to initialize min/max values
5 const int INF = 1 << 30;
6
7 // Track the minimum and maximum x-coordinates
8 int minX = INF;
9 int maxX = -INF;
10
11 // Store all unique points in a set for O(1) lookup
12 // Using pair<int, int> to represent (x, y) coordinates
13 set<pair<int, int>> pointSet;
14
15 // First pass: find x-coordinate boundaries and populate the point set
16 for (const auto& point : points) {
17 minX = min(minX, point[0]);
18 maxX = max(maxX, point[0]);
19 pointSet.insert({point[0], point[1]});
20 }
21
22 // Calculate the sum of min and max x-coordinates
23 // This represents 2 times the x-coordinate of the reflection line
24 // For a point (x, y) to reflect across line x = mid,
25 // its reflection would be at (2*mid - x, y)
26 // Since mid = (minX + maxX) / 2, we have 2*mid = minX + maxX
27 int sumX = minX + maxX;
28
29 // Second pass: verify each point has its reflection
30 for (const auto& point : points) {
31 // Calculate the reflected x-coordinate: sumX - point[0]
32 // Check if the reflected point exists in the set
33 if (!pointSet.count({sumX - point[0], point[1]})) {
34 return false;
35 }
36 }
37
38 // All points have their reflections
39 return true;
40 }
41};
42
1function isReflected(points: number[][]): boolean {
2 // Use a large constant to initialize min/max values
3 const INF = 1 << 30;
4
5 // Track the minimum and maximum x-coordinates
6 let minX = INF;
7 let maxX = -INF;
8
9 // Store all unique points in a set for O(1) lookup
10 // Using string representation "x,y" for point coordinates
11 const pointSet = new Set<string>();
12
13 // First pass: find x-coordinate boundaries and populate the point set
14 for (const point of points) {
15 minX = Math.min(minX, point[0]);
16 maxX = Math.max(maxX, point[0]);
17 pointSet.add(`${point[0]},${point[1]}`);
18 }
19
20 // Calculate the sum of min and max x-coordinates
21 // This represents 2 times the x-coordinate of the reflection line
22 // For a point (x, y) to reflect across line x = mid,
23 // its reflection would be at (2*mid - x, y)
24 // Since mid = (minX + maxX) / 2, we have 2*mid = minX + maxX
25 const sumX = minX + maxX;
26
27 // Second pass: verify each point has its reflection
28 for (const point of points) {
29 // Calculate the reflected x-coordinate: sumX - point[0]
30 // Check if the reflected point exists in the set
31 const reflectedX = sumX - point[0];
32 const reflectedPoint = `${reflectedX},${point[1]}`;
33
34 if (!pointSet.has(reflectedPoint)) {
35 return false;
36 }
37 }
38
39 // All points have their reflections
40 return true;
41}
42
Time and Space Complexity
Time Complexity: O(n)
, where n
is the number of points in the input list.
- The first loop iterates through all
n
points to findmin_x
andmax_x
, and to build thepoint_set
. Each operation inside the loop (min comparison, max comparison, and set insertion) takesO(1)
time on average. This results inO(n)
time. - The
all()
function with the generator expression iterates through alln
points once, and for each point, it performs a set lookup operation(s - x, y) in point_set
, which takesO(1)
time on average. This also results inO(n)
time. - Overall time complexity:
O(n) + O(n) = O(n)
Space Complexity: O(n)
, where n
is the number of points in the input list.
- The
point_set
stores all unique points from the input list. In the worst case, all points are unique, so the set will containn
elements, requiringO(n)
space. - Other variables (
min_x
,max_x
,s
) use constant spaceO(1)
. - Overall space complexity:
O(n)
Common Pitfalls
1. Handling Duplicate Points Incorrectly
A common mistake is not properly handling duplicate points in the input. Some might try to use a list instead of a set, leading to incorrect results when checking for reflections.
Problem Example:
points = [[1,1], [1,1], [3,1]] # Point (1,1) appears twice
Using a list would fail because you'd check for the reflection of (1,1) twice, but the reflected point (3,1) only appears once.
Solution: Always use a set to store unique points, which automatically handles duplicates and provides O(1) lookup time.
2. Integer Overflow or Precision Issues
When calculating min_x + max_x
, the sum might overflow in languages with fixed integer sizes, or cause precision issues if using floating-point division.
Problem Example:
# If min_x = -10^9 and max_x = 10^9 # Some might incorrectly calculate the line position as: line_x = (min_x + max_x) / 2 # Potential precision loss reflected_x = 2 * line_x - x # Compounds the precision error
Solution: Work with the sum directly (s = min_x + max_x
) and use the formula (s - x, y)
for reflection, avoiding division entirely. This maintains exact integer arithmetic.
3. Forgetting Edge Cases
Missing important edge cases can lead to incorrect results:
Empty Input:
points = [] # Should return True (empty set is symmetric)
Single Point:
points = [[0,0]] # Should return True (single point is symmetric)
Solution: Add edge case handling:
if not points: return True # Empty set is symmetric
4. Incorrect Reflection Formula
A common mathematical error is using the wrong reflection formula, especially when trying to work with the actual line position.
Incorrect approach:
# Wrong: Trying to reflect using distance calculation line_x = (min_x + max_x) / 2 reflected_x = x + 2 * (line_x - x) # This is incorrect!
Correct approach:
# Correct: Using the sum directly s = min_x + max_x reflected_x = s - x # Simple and correct
5. Not Considering Points ON the Reflection Line
Points that lie exactly on the reflection line reflect to themselves. Some implementations might incorrectly handle this case.
Problem Example:
points = [[2,1], [2,2], [2,3]] # All points on x=2 # The reflection line is at x=2, and all points reflect to themselves
Solution: The formula (s - x, y)
naturally handles this case correctly. When x = s/2
, then s - x = s/2
, so the point maps to itself, which should exist in the set.
What are the most two important steps in writing a depth first search function? (Select 2)
Recommended Readings
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Don’t Miss This!