963. Minimum Area Rectangle II
Problem Description
You are given an array of points in the X-Y plane where each point is represented as [x, y]
coordinates. Your task is to find the minimum area of a rectangle that can be formed using these points as vertices.
The key challenge is that the rectangle's sides do not need to be parallel to the X and Y axes - the rectangle can be rotated at any angle in the plane. This means you need to consider all possible orientations of rectangles that can be formed from the given points.
If it's not possible to form any rectangle from the given points, return 0
.
The answer should be accurate within 10^-5
of the actual value, meaning small floating-point differences are acceptable.
For example:
- If you have points that form a square with side length 2, the area would be 4
- If you have points that form a rectangle tilted at 45 degrees with dimensions 3×4, the area would be 12
- If you only have 3 points or points that don't form any rectangle, return 0
The solution approach checks all possible combinations of three points to determine if they can form three vertices of a rectangle, then verifies if the fourth vertex exists in the point set. It validates rectangles by checking if two adjacent sides are perpendicular (their dot product equals zero) and calculates the area as the product of the lengths of these two sides.
Intuition
To find rectangles in a set of points, we need to think about what defines a rectangle geometrically. A rectangle has four vertices where opposite sides are equal and parallel, and adjacent sides are perpendicular to each other.
The key insight is that if we have three vertices of a rectangle, the fourth vertex is completely determined. If we pick any three points that could potentially form three corners of a rectangle, we can calculate where the fourth corner must be using vector addition.
Here's how we arrive at this approach:
-
Starting with three points: If we have points
P1
,P2
, andP3
that form three corners of a rectangle withP1
as the common corner (where two sides meet), then we can form two vectors:v21 = P2 - P1
andv31 = P3 - P1
. -
Checking perpendicularity: For these three points to be part of a rectangle, the vectors
v21
andv31
must be perpendicular. We can verify this by checking if their dot product equals zero:v21[0] * v31[0] + v21[1] * v31[1] == 0
. -
Finding the fourth point: If the perpendicularity condition is met, the fourth point
P4
can be calculated using the parallelogram rule. Since opposite sides of a rectangle are equal and parallel, we have:P4 = P2 + P3 - P1
, or equivalentlyP4 = P1 + v21 + v31
. -
Verification: We then check if this calculated fourth point actually exists in our original set of points. If it does, we've found a valid rectangle.
-
Calculating area: The area of the rectangle is simply the product of the lengths of the two adjacent sides:
|v21| * |v31|
, where|v|
represents the length of vectorv
.
By iterating through all possible combinations of three points and checking these conditions, we can find all rectangles in the point set and track the one with minimum area. This exhaustive search ensures we don't miss any potential rectangles, regardless of their orientation in the plane.
Learn more about Math patterns.
Solution Approach
The implementation uses a brute-force approach with geometric validation to find all possible rectangles and track the minimum area.
Data Structure Setup:
- Convert the points list into a set
s
for O(1) lookup time when checking if the fourth vertex exists - Store points as tuples
(x, y)
in the set for hashability
Triple Nested Loop Structure: The algorithm iterates through all possible combinations of three points:
- Outer loop (index
i
): Selects the first point(x1, y1)
as the corner vertex - Middle loop (index
j
): Selects the second point(x2, y2)
- Inner loop (index
k
): Selects the third point(x3, y3)
, starting fromj+1
to avoid duplicates
Fourth Vertex Calculation: For each triplet of points, calculate where the fourth vertex should be:
x4 = x2 - x1 + x3 y4 = y2 - y1 + y3
This formula comes from the vector addition: P4 = P1 + (P2 - P1) + (P3 - P1)
Rectangle Validation:
- Check if
(x4, y4)
exists in the point sets
- If it exists, create two vectors from the common corner:
v21 = (x2 - x1, y2 - y1)
v31 = (x3 - x1, y3 - y1)
- Verify perpendicularity by checking if the dot product equals zero:
v21[0] * v31[0] + v21[1] * v31[1] == 0
Area Calculation: If a valid rectangle is found:
- Calculate the length of the first side:
w = sqrt(v21[0]^2 + v21[1]^2)
- Calculate the length of the second side:
h = sqrt(v31[0]^2 + v31[1]^2)
- Compute area as
w * h
- Update the minimum area if this rectangle is smaller
Final Result:
- Initialize
ans
to infinity to track the minimum area - After checking all combinations, return
0
if no rectangle was found (ans still equals infinity) - Otherwise, return the minimum area found
The time complexity is O(n³) where n is the number of points, as we examine all triplets. The space complexity is O(n) for storing the point set.
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 finding the minimum area rectangle with points: [[1,2], [2,1], [1,0], [0,1]]
Step 1: Convert to Set
Create set s = {(1,2), (2,1), (1,0), (0,1)}
for O(1) lookups.
Step 2: Check All Triplets We'll examine combinations of three points. Let's trace through when we select:
- P1 = (1, 2) [index 0]
- P2 = (2, 1) [index 1]
- P3 = (0, 1) [index 3]
Step 3: Calculate Fourth Vertex
Using the formula P4 = P2 + P3 - P1
:
- x4 = 2 + 0 - 1 = 1
- y4 = 1 + 1 - 2 = 0
- So P4 = (1, 0)
Step 4: Validate Rectangle Check if (1, 0) exists in our set - it does! ✓
Now verify perpendicularity with vectors from P1:
- v21 = P2 - P1 = (2-1, 1-2) = (1, -1)
- v31 = P3 - P1 = (0-1, 1-2) = (-1, -1)
- Dot product = (1)×(-1) + (-1)×(-1) = -1 + 1 = 0 ✓
The vectors are perpendicular, confirming a valid rectangle!
Step 5: Calculate Area
- Length of first side: |v21| = √(1² + (-1)²) = √2
- Length of second side: |v31| = √((-1)² + (-1)²) = √2
- Area = √2 × √2 = 2
Step 6: Continue Checking The algorithm continues checking other triplets. For instance:
- Triplet (1,2), (1,0), (0,1) would calculate P4 = (0,-1), which doesn't exist in our set
- Triplet (2,1), (1,0), (0,1) would calculate P4 = (-1,0), which doesn't exist either
After checking all possible triplets, the minimum area found is 2.
Visual Representation:
(1,2)-----(0,1) | | | | (2,1)-----(1,0)
This forms a square rotated 45 degrees with area 2.
Solution Implementation
1class Solution:
2 def minAreaFreeRect(self, points: List[List[int]]) -> float:
3 # Convert points list to a set for O(1) lookup
4 point_set = {(x, y) for x, y in points}
5 num_points = len(points)
6 min_area = float('inf')
7
8 # Try each point as a potential corner of the rectangle
9 for i in range(num_points):
10 x1, y1 = points[i]
11
12 # Try second point to form one side of rectangle
13 for j in range(num_points):
14 if j == i:
15 continue
16
17 x2, y2 = points[j]
18
19 # Try third point to form another side of rectangle
20 for k in range(j + 1, num_points):
21 if k == i:
22 continue
23
24 x3, y3 = points[k]
25
26 # Calculate where the fourth point should be if these form a rectangle
27 # Using vector addition: point4 = point2 - point1 + point3
28 x4 = x2 - x1 + x3
29 y4 = y2 - y1 + y3
30
31 # Check if the fourth point exists in our point set
32 if (x4, y4) in point_set:
33 # Create vectors from point1 to point2 and point1 to point3
34 vector_1_to_2 = (x2 - x1, y2 - y1)
35 vector_1_to_3 = (x3 - x1, y3 - y1)
36
37 # Check if vectors are perpendicular (dot product equals 0)
38 dot_product = vector_1_to_2[0] * vector_1_to_3[0] + vector_1_to_2[1] * vector_1_to_3[1]
39
40 if dot_product == 0:
41 # Calculate the lengths of the two sides
42 width = (vector_1_to_2[0] ** 2 + vector_1_to_2[1] ** 2) ** 0.5
43 height = (vector_1_to_3[0] ** 2 + vector_1_to_3[1] ** 2) ** 0.5
44
45 # Update minimum area
46 area = width * height
47 min_area = min(min_area, area)
48
49 # Return 0 if no rectangle was found, otherwise return the minimum area
50 return 0.0 if min_area == float('inf') else min_area
51
1class Solution {
2 public double minAreaFreeRect(int[][] points) {
3 int n = points.length;
4
5 // Create a set to store all points for O(1) lookup
6 // Using a hash function to convert 2D coordinates to unique integers
7 Set<Integer> pointSet = new HashSet<>(n);
8 for (int[] point : points) {
9 pointSet.add(encodePoint(point[0], point[1]));
10 }
11
12 double minArea = Double.MAX_VALUE;
13
14 // Try each point as the first vertex of a rectangle
15 for (int i = 0; i < n; ++i) {
16 int x1 = points[i][0];
17 int y1 = points[i][1];
18
19 // Try each other point as the second vertex
20 for (int j = 0; j < n; ++j) {
21 if (j == i) continue;
22
23 int x2 = points[j][0];
24 int y2 = points[j][1];
25
26 // Try each point after j as the third vertex
27 for (int k = j + 1; k < n; ++k) {
28 if (k == i) continue;
29
30 int x3 = points[k][0];
31 int y3 = points[k][1];
32
33 // Calculate the fourth vertex using vector addition
34 // If we have vertices P1, P2, P3, then P4 = P2 + P3 - P1
35 // This forms a parallelogram with P1 as opposite corner to P4
36 int x4 = x2 - x1 + x3;
37 int y4 = y2 - y1 + y3;
38
39 // Check if the fourth vertex exists in our point set
40 if (pointSet.contains(encodePoint(x4, y4))) {
41 // Check if the angle at P1 is 90 degrees using dot product
42 // Vector P1->P2 dot Vector P1->P3 should be 0 for perpendicular vectors
43 int dotProduct = (x2 - x1) * (x3 - x1) + (y2 - y1) * (y3 - y1);
44
45 if (dotProduct == 0) {
46 // Calculate the area of the rectangle
47 // Area = width * height
48 int widthSquared = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);
49 int heightSquared = (x3 - x1) * (x3 - x1) + (y3 - y1) * (y3 - y1);
50 double area = Math.sqrt(1L * widthSquared * heightSquared);
51
52 minArea = Math.min(minArea, area);
53 }
54 }
55 }
56 }
57 }
58
59 // Return 0 if no rectangle was found, otherwise return the minimum area
60 return minArea == Double.MAX_VALUE ? 0 : minArea;
61 }
62
63 /**
64 * Encodes a 2D point into a unique integer
65 * Uses 40001 as multiplier since coordinates are in range [-20000, 20000]
66 * This ensures no collision between different points
67 */
68 private int encodePoint(int x, int y) {
69 return x * 40001 + y;
70 }
71}
72
1class Solution {
2public:
3 double minAreaFreeRect(vector<vector<int>>& points) {
4 // Hash function to convert 2D coordinates to a unique integer
5 // Using 40001 as multiplier since coordinates are in range [0, 40000]
6 auto hashPoint = [](int x, int y) {
7 return x * 40001 + y;
8 };
9
10 int numPoints = points.size();
11
12 // Store all points in a hash set for O(1) lookup
13 unordered_set<int> pointSet;
14 for (auto& point : points) {
15 pointSet.insert(hashPoint(point[0], point[1]));
16 }
17
18 double minArea = 1e20; // Initialize with a large value
19
20 // Try each point as the first vertex of a rectangle
21 for (int i = 0; i < numPoints; ++i) {
22 int x1 = points[i][0], y1 = points[i][1];
23
24 // Try each other point as the second vertex
25 for (int j = 0; j < numPoints; ++j) {
26 if (j == i) continue;
27
28 int x2 = points[j][0], y2 = points[j][1];
29
30 // Try each point after j as the third vertex
31 for (int k = j + 1; k < numPoints; ++k) {
32 if (k == i) continue;
33
34 int x3 = points[k][0], y3 = points[k][1];
35
36 // Calculate the fourth vertex using vector addition
37 // If points form a rectangle: P4 = P2 + P3 - P1
38 int x4 = x2 - x1 + x3;
39 int y4 = y2 - y1 + y3;
40
41 // Check if the fourth vertex is within valid bounds and exists in our point set
42 if (x4 >= 0 && x4 < 40000 && y4 >= 0 && y4 <= 40000 &&
43 pointSet.count(hashPoint(x4, y4))) {
44
45 // Check if vectors (P2-P1) and (P3-P1) are perpendicular
46 // Using dot product: if dot product is 0, vectors are perpendicular
47 if ((x2 - x1) * (x3 - x1) + (y2 - y1) * (y3 - y1) == 0) {
48 // Calculate the squared lengths of the two sides
49 int widthSquared = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);
50 int heightSquared = (x3 - x1) * (x3 - x1) + (y3 - y1) * (y3 - y1);
51
52 // Calculate area and update minimum
53 double area = sqrt(1LL * widthSquared * heightSquared);
54 minArea = min(minArea, area);
55 }
56 }
57 }
58 }
59 }
60
61 // Return 0 if no rectangle was found, otherwise return the minimum area
62 return minArea == 1e20 ? 0 : minArea;
63 }
64};
65
1/**
2 * Finds the minimum area of a rectangle formed by any 4 points from the given array.
3 * The rectangle can be at any angle (not necessarily axis-aligned).
4 *
5 * @param points - Array of 2D points represented as [x, y] coordinates
6 * @returns The minimum area of a rectangle, or 0 if no rectangle can be formed
7 */
8function minAreaFreeRect(points: number[][]): number {
9 const pointCount = points.length;
10
11 /**
12 * Hash function to convert 2D coordinates into a unique number.
13 * Uses 40001 as multiplier since coordinates are in range [0, 40000].
14 */
15 const hashPoint = (x: number, y: number): number => x * 40001 + y;
16
17 // Store all points in a set for O(1) lookup
18 const pointSet: Set<number> = new Set();
19 for (const [x, y] of points) {
20 pointSet.add(hashPoint(x, y));
21 }
22
23 let minimumArea = Number.MAX_VALUE;
24
25 // Try each point as the first corner of the rectangle
26 for (let i = 0; i < pointCount; ++i) {
27 const [x1, y1] = points[i];
28
29 // Try each other point as the second corner
30 for (let j = 0; j < pointCount; ++j) {
31 if (j !== i) {
32 const [x2, y2] = points[j];
33
34 // Try each remaining point as the third corner
35 for (let k = j + 1; k < pointCount; ++k) {
36 if (k !== i) {
37 const [x3, y3] = points[k];
38
39 // Calculate where the fourth corner should be using vector addition
40 // If points form a rectangle: p4 = p2 + p3 - p1
41 const x4 = x2 - x1 + x3;
42 const y4 = y2 - y1 + y3;
43
44 // Check if the fourth corner exists in our point set
45 if (pointSet.has(hashPoint(x4, y4))) {
46 // Verify that the angle at p1 is 90 degrees using dot product
47 // Vectors (p1->p2) and (p1->p3) should be perpendicular
48 const dotProduct = (x2 - x1) * (x3 - x1) + (y2 - y1) * (y3 - y1);
49
50 if (dotProduct === 0) {
51 // Calculate the squared lengths of the two sides from p1
52 const side1Squared = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);
53 const side2Squared = (x3 - x1) * (x3 - x1) + (y3 - y1) * (y3 - y1);
54
55 // Calculate area as product of the two perpendicular sides
56 const area = Math.sqrt(side1Squared * side2Squared);
57 minimumArea = Math.min(minimumArea, area);
58 }
59 }
60 }
61 }
62 }
63 }
64 }
65
66 // Return 0 if no valid rectangle was found
67 return minimumArea === Number.MAX_VALUE ? 0 : minimumArea;
68}
69
Time and Space Complexity
Time Complexity: O(n³)
The algorithm uses three nested loops to iterate through the points:
- The outer loop runs
n
times (iterating through all points as the first vertex) - The second loop runs up to
n
times for each iteration of the outer loop (selecting the second vertex) - The third loop runs up to
n
times for each iteration of the second loop (selecting the third vertex)
For each triple of points (i, j, k)
, the algorithm performs:
- Constant time operations to calculate the fourth point coordinates:
O(1)
- Set lookup to check if the fourth point exists:
O(1)
on average - Dot product calculation to verify perpendicularity:
O(1)
- Distance calculations and area computation:
O(1)
Therefore, the overall time complexity is O(n) × O(n) × O(n) × O(1) = O(n³)
Space Complexity: O(n)
The algorithm uses:
- A set
s
to store all points as tuples, which requiresO(n)
space - A few variables to store coordinates, vectors, and calculated values:
O(1)
- No recursive calls or additional data structures that scale with input size
The dominant space usage comes from the set storing all points, resulting in O(n)
space complexity.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Duplicate Rectangle Counting
The most significant pitfall in this solution is that each rectangle is counted multiple times. When we iterate through all triplets of points, the same rectangle can be discovered from different starting corners and with different point orderings.
Why it happens:
- A rectangle has 4 corners, and we can start from any of them
- For each corner, we can choose the adjacent points in different orders
- This leads to the same rectangle being found up to 8 times
Solution: While the duplicate counting doesn't affect correctness (since we're finding the minimum area), it impacts performance. To optimize:
# Instead of starting k from j+1, we should ensure we only check each unique triplet once
for i in range(num_points):
for j in range(i + 1, num_points):
for k in range(j + 1, num_points):
# Check all three possible rectangles formed by these three points
# as potential corners (not just one configuration)
2. Floating Point Precision Issues
The dot product check dot_product == 0
uses exact equality for floating-point numbers, which can fail due to precision errors when coordinates involve calculations.
Solution: Use an epsilon tolerance for the perpendicularity check:
EPSILON = 1e-9
if abs(dot_product) < EPSILON: # Instead of dot_product == 0
# Rectangle is valid
3. Missing Rectangle Configurations
The current approach assumes point i
is always the corner vertex connecting to both j
and k
. However, in a triplet of three points, any of them could be the corner vertex.
Solution: For each triplet, check all three possible configurations:
def check_rectangle(p1, p2, p3, point_set):
# Configuration 1: p1 is the corner
x4 = p2[0] - p1[0] + p3[0]
y4 = p2[1] - p1[1] + p3[1]
if (x4, y4) in point_set:
# Validate and calculate area
# Configuration 2: p2 is the corner
x4 = p1[0] - p2[0] + p3[0]
y4 = p1[1] - p2[1] + p3[1]
if (x4, y4) in point_set:
# Validate and calculate area
# Configuration 3: p3 is the corner
x4 = p1[0] - p3[0] + p2[0]
y4 = p1[1] - p3[1] + p2[1]
if (x4, y4) in point_set:
# Validate and calculate area
4. Inefficient Point Set Creation
Creating the set with tuple comprehension is fine, but for very large inputs, consider using frozenset for slightly better performance and immutability guarantees.
Better approach:
point_set = frozenset(map(tuple, points))
Which of the following problems can be solved with backtracking (select multiple)
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!