Facebook Pixel

963. Minimum Area Rectangle II

MediumGeometryArrayHash TableMath
Leetcode Link

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.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

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:

  1. Starting with three points: If we have points P1, P2, and P3 that form three corners of a rectangle with P1 as the common corner (where two sides meet), then we can form two vectors: v21 = P2 - P1 and v31 = P3 - P1.

  2. Checking perpendicularity: For these three points to be part of a rectangle, the vectors v21 and v31 must be perpendicular. We can verify this by checking if their dot product equals zero: v21[0] * v31[0] + v21[1] * v31[1] == 0.

  3. 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 equivalently P4 = P1 + v21 + v31.

  4. 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.

  5. 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 vector v.

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 from j+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:

  1. Check if (x4, y4) exists in the point set s
  2. If it exists, create two vectors from the common corner:
    • v21 = (x2 - x1, y2 - y1)
    • v31 = (x3 - x1, y3 - y1)
  3. 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 Evaluator

Example 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 requires O(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))
Discover Your Strengths and Weaknesses: Take Our 3-Minute Quiz to Tailor Your Study Plan:

Which of the following problems can be solved with backtracking (select multiple)


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More