Maximum Area Rectangle With Point Constraints I
MedPrompt
You are given an array points where points[i] = [xi, yi] represents the coordinates of a point on an infinite plane.
Your task is to find the maximum area of a rectangle that:
- Can be formed using four of these points as its corners.
- Does not contain any other point inside or on its border.
- Has its edges parallel to the axes.
Return the maximum area that you can obtain or -1 if no such rectangle is possible.
Example 1:
Input: points = [[1,1],[1,3],[3,1],[3,3]]
Output: 4
Explanation:

We can make a rectangle with these 4 points as corners and there is no other point that lies inside or on the border. Hence, the maximum possible area would be 4.
Example 2:
Input: points = [[1,1],[1,3],[3,1],[3,3],[2,2]]
Output: -1
Explanation:

There is only one rectangle possible is with points [1,1], [1,3], [3,1] and [3,3] but [2,2] will always lie inside it. Hence, returning -1.
Example 3:
Input: points = [[1,1],[1,3],[3,1],[3,3],[1,2],[3,2]]
Output: 2
Explanation:

The maximum area rectangle is formed by the points [1,3], [1,2], [3,2], [3,3], which has an area of 2. Additionally, the points [1,1], [1,2], [3,1], [3,2] also form a valid rectangle with the same area.
Constraints:
1 <= points.length <= 10points[i].length == 20 <= xi, yi <= 100- All the given points are unique.
Approaches
2 approaches with complexity analysis and trade-offs.
This approach exhaustively checks every possible combination of four points from the input array to see if they can form a valid, empty, axis-aligned rectangle. Given the small constraint on the number of points (N <= 10), this method is feasible despite its high time complexity.
Algorithm
- Initialize a variable
maxAreato -1 to store the maximum valid area found. - Use four nested loops to iterate through all unique combinations of four points from the input array
points. Let the chosen points bep1,p2,p3, andp4. - For each quartet of points, verify if they can form an axis-aligned rectangle. This is true if the set of their x-coordinates and the set of their y-coordinates each contain exactly two unique values.
- If they form a rectangle, determine its boundaries by finding the minimum and maximum x and y coordinates (
x_min,x_max,y_min,y_max). - Check the emptiness condition: Iterate through all points in the original
pointsarray. If any point that is not one of the four corners lies within or on the boundary of the rectangle (i.e., its coordinates(px, py)satisfyx_min <= px <= x_maxandy_min <= py <= y_max), the rectangle is considered not empty and is invalid. - If the rectangle is confirmed to be empty, calculate its area as
(x_max - x_min) * (y_max - y_min). - Update
maxAreaby taking the maximum of the currentmaxAreaand the newly calculated area. - After checking all possible combinations, return the final
maxArea.
Walkthrough
The core idea is to use brute force. Since a rectangle requires four corners, we can generate all possible sets of four points from the input list. The number of combinations is given by N C 4, where N is the total number of points. For each combination, we perform two checks:
-
Rectangle Formation Check: We verify if the four points can form an axis-aligned rectangle. This is done by checking their coordinates. If there are exactly two distinct x-values and two distinct y-values among the four points, they form a rectangle.
-
Emptiness Check: If the points form a rectangle, we then check if it's 'empty'. An empty rectangle is one that does not contain any other input points on its boundary or in its interior. We iterate through all the points in the input array that are not part of the current quartet. If any of these points fall within the rectangle's bounding box, the rectangle is invalid.
If a rectangle passes both checks, we calculate its area and update our maximum area found so far. If no such rectangle is found after checking all combinations, the initial value of -1 is returned.
class Solution { public int maxAreaRectangle(int[][] points) { int n = points.length; if (n < 4) { return -1; } long maxArea = -1; for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { for (int k = j + 1; k < n; k++) { for (int l = k + 1; l < n; l++) { int[] p1 = points[i]; int[] p2 = points[j]; int[] p3 = points[k]; int[] p4 = points[l]; java.util.Set<Integer> xCoords = new java.util.HashSet<>(); java.util.Set<Integer> yCoords = new java.util.HashSet<>(); xCoords.add(p1[0]); xCoords.add(p2[0]); xCoords.add(p3[0]); xCoords.add(p4[0]); yCoords.add(p1[1]); yCoords.add(p2[1]); yCoords.add(p3[1]); yCoords.add(p4[1]); if (xCoords.size() == 2 && yCoords.size() == 2) { int x_min = java.util.Collections.min(xCoords); int x_max = java.util.Collections.max(xCoords); int y_min = java.util.Collections.min(yCoords); int y_max = java.util.Collections.max(yCoords); boolean isEmpty = true; for (int m = 0; m < n; m++) { if (m == i || m == j || m == k || m == l) { continue; } int[] otherPoint = points[m]; if (otherPoint[0] >= x_min && otherPoint[0] <= x_max && otherPoint[1] >= y_min && otherPoint[1] <= y_max) { isEmpty = false; break; } } if (isEmpty) { long area = (long)(x_max - x_min) * (y_max - y_min); maxArea = Math.max(maxArea, area); } } } } } } return (int)maxArea; }}Complexity
Time
O(N^5), where N is the number of points. There are O(N^4) combinations of four points. For each combination, we check the emptiness condition by iterating through the other O(N) points.
Space
O(1), as we only use a few variables to store coordinates and the max area, not dependent on the input size.
Trade-offs
Pros
Simple to understand and implement.
Requires no extra space.
Cons
The time complexity is very high, making it impractical for larger datasets.
A more efficient method involves iterating through all pairs of points and treating them as potential diagonal corners of a rectangle. By using a hash set for quick lookups of the other two corners, we can find candidate rectangles much faster than the four-point combination approach.
Algorithm
- First, store all input points in a
HashSetto allow for constant-time average lookups. A common way to do this is to convert each point[x, y]into a string like"x,y"to use as the key. - Initialize a variable
maxAreato -1. - Iterate through all unique pairs of points from the input array, let's say
p1 = (x1, y1)andp2 = (x2, y2). - For each pair, check if they can form a diagonal of an axis-aligned rectangle. This is possible only if
x1 != x2andy1 != y2. - If they can form a diagonal, the other two corners of the rectangle would be
p3 = (x1, y2)andp4 = (x2, y1). Check if bothp3andp4exist in theHashSet. - If all four corners exist, we have found a candidate rectangle. Now, check if it's empty.
- To check for emptiness, iterate through all
Ninput points. If any point (that is not one of the four corners) lies inside or on the boundary of the rectangle, the rectangle is invalid. - If the rectangle is empty, calculate its area:
abs(x1 - x2) * abs(y1 - y2). - Update
maxAreawith the current area if it's larger. - After checking all pairs, return the final
maxArea.
Walkthrough
This optimized approach reduces the complexity of finding rectangles. Instead of picking four points, we pick two points, p1(x1, y1) and p2(x2, y2), and assume they are diagonally opposite corners. For this to be possible, their x and y coordinates must be different.
The other two corners required to complete the rectangle would be at (x1, y2) and (x2, y1). We can check for the existence of these two points very quickly if we pre-process all input points into a HashSet.
Once a four-corner rectangle is identified, we perform the same emptiness check as in the brute-force approach: we iterate through all input points to ensure no other point lies within the rectangle's boundaries. If the rectangle is empty, we calculate its area and update the maximum area found.
This method reduces the complexity of finding candidate rectangles from O(N^4) to O(N^2), leading to a significant overall performance improvement.
class Solution { public int maxAreaRectangle(int[][] points) { int n = points.length; if (n < 4) { return -1; } java.util.Set<String> pointSet = new java.util.HashSet<>(); for (int[] p : points) { pointSet.add(p[0] + "," + p[1]); } long maxArea = -1; for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { int[] p1 = points[i]; int[] p2 = points[j]; int x1 = p1[0], y1 = p1[1]; int x2 = p2[0], y2 = p2[1]; if (x1 == x2 || y1 == y2) { continue; } // Check if the other two corners exist if (pointSet.contains(x1 + "," + y2) && pointSet.contains(x2 + "," + y1)) { int x_min = Math.min(x1, x2); int x_max = Math.max(x1, x2); int y_min = Math.min(y1, y2); int y_max = Math.max(y1, y2); boolean isEmpty = true; for (int[] p_check : points) { boolean isCorner = (p_check[0] == x1 && p_check[1] == y1) || (p_check[0] == x2 && p_check[1] == y2) || (p_check[0] == x1 && p_check[1] == y2) || (p_check[0] == x2 && p_check[1] == y1); if (isCorner) { continue; } if (p_check[0] >= x_min && p_check[0] <= x_max && p_check[1] >= y_min && p_check[1] <= y_max) { isEmpty = false; break; } } if (isEmpty) { long area = (long)(x_max - x_min) * (y_max - y_min); maxArea = Math.max(maxArea, area); } } } } return (int)maxArea; }}Complexity
Time
O(N^3), where N is the number of points. We iterate through O(N^2) pairs of points. For each pair, we perform an O(1) lookup for the other corners and then an O(N) scan for the emptiness check.
Space
O(N) to store the N points in a `HashSet` for efficient lookups.
Trade-offs
Pros
Significantly faster than the brute-force approach.
Still conceptually straightforward.
Cons
Requires extra space to store the points in a hash set.
Solutions
Solution
class Solution {public int maxRectangleArea(int[][] points) { int ans = -1; for (int i = 0; i < points.length; ++i) { int x1 = points[i][0], y1 = points[i][1]; for (int j = 0; j < i; ++j) { int x2 = points[j][0], y2 = points[j][1]; int x3 = Math.min(x1, x2), y3 = Math.min(y1, y2); int x4 = Math.max(x1, x2), y4 = Math.max(y1, y2); if (check(points, x3, y3, x4, y4)) { ans = Math.max(ans, (x4 - x3) * (y4 - y3)); } } } return ans; }private boolean check(int[][] points, int x1, int y1, int x2, int y2) { int cnt = 0; for (var p : points) { int x = p[0]; int y = p[1]; if (x < x1 || x > x2 || y < y1 || y > y2) { continue; } if ((x == x1 || x == x2) && (y == y1 || y == y2)) { cnt++; continue; } return false; } return cnt == 4; }}class Solution {public: int maxRectangleArea(vector<vector<int>> &points) { auto check = [&](int x1, int y1, int x2, int y2) -> bool { int cnt = 0; for (const auto &point : points) { int x = point[0]; int y = point[1]; if (x < x1 || x > x2 || y < y1 || y > y2) { continue; } if ((x == x1 || x == x2) && (y == y1 || y == y2)) { cnt++; continue; } return false; } return cnt == 4; }; int ans = -1; for (int i = 0; i < points.size(); i++) { int x1 = points[i][0], y1 = points[i][1]; for (int j = 0; j < i; j++) { int x2 = points[j][0], y2 = points[j][1]; int x3 = min(x1, x2), y3 = min(y1, y2); int x4 = max(x1, x2), y4 = max(y1, y2); if (check(x3, y3, x4, y4)) { ans = max(ans, (x4 - x3) * (y4 - y3)); } } } return ans; }};class Solution: def maxRectangleArea(self, points: List[List[int]]) -> int: def check(x1: int, y1: int, x2: int, y2: int) -> bool: cnt = 0 for x, y in points: if x < x1 or x > x2 or y < y1 or y > y2: continue if (x == x1 or x == x2) and (y == y1 or y == y2): cnt += 1 continue return False return cnt == 4 ans = - 1 for i, (x1, y1) in enumerate(points): for x2, y2 in points[: i]: x3, y3 = min(x1, x2), min(y1, y2) x4, y4 = max(x1, x2), max(y1, y2) if check(x3, y3, x4, y4): ans = max(ans, (x4 - x3) * (y4 - y3)) return ansVideo walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.