Maximum Area Rectangle With Point Constraints II
HardPrompt
There are n points on an infinite plane. You are given two integer arrays xCoord and yCoord where (xCoord[i], yCoord[i]) represents the coordinates of the ith point.
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: xCoord = [1,1,3,3], yCoord = [1,3,1,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: xCoord = [1,1,3,3,2], yCoord = [1,3,1,3,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: xCoord = [1,1,3,3,1,3], yCoord = [1,3,1,3,2,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 <= xCoord.length == yCoord.length <= 2 * 1050 <= xCoord[i], yCoord[i] <= 8 * 107- All the given points are unique.
Approaches
3 approaches with complexity analysis and trade-offs.
This approach improves upon the brute-force method by using a sweep-line technique. It processes the points sorted by one coordinate (e.g., y-coordinate) and uses a hash map to keep track of potential rectangle edges seen so far. This avoids the O(N^3) complexity by intelligently constructing and verifying only the rectangles that have a chance of being empty.
Algorithm
-
- Establish the necessary and sufficient conditions for an empty rectangle: its four edges must be empty of other points. This implies that its corners are formed by points that are mutually adjacent in the point-defined grid.
-
- Pre-process the points into two maps:
xMap(mapping each x-coordinate to a sorted list of its y-coordinates) andyMap(mapping each y-coordinate to a sorted list of its x-coordinates).
- Pre-process the points into two maps:
-
- Initialize
maxArea = -1and a hash maplastYSeen. This map will store, for a pair of x-coordinates(x1, x2), the y-coordinate where they last appeared as an adjacent horizontal segment.
- Initialize
-
- Perform a horizontal sweep by iterating through a sorted list of unique y-coordinates.
-
- For each
y, get its sorted list of x-coordinatesxCoordsfromyMap.
- For each
-
- Iterate through adjacent pairs
(x1, x2)inxCoords. This pair forms an empty horizontal segment.
- Iterate through adjacent pairs
-
- Check if the pair
(x1, x2)exists as a key inlastYSeen. If it does, with a valueprevY, we have a candidate rectangle with empty top and bottom edges.
- Check if the pair
-
- Verify that the vertical edges are also empty. This is done by checking if
yis the immediate successor ofprevYin the sorted y-lists for bothx1andx2(fromxMap).
- Verify that the vertical edges are also empty. This is done by checking if
-
- If all adjacency conditions hold, calculate the area and update
maxArea.
- If all adjacency conditions hold, calculate the area and update
-
- Update
lastYSeenwith the current(x1, x2)pair and its y-coordinatey.
- Update
Walkthrough
The core idea is based on the insight that an empty rectangle must be bounded by adjacent points. For a rectangle with corners (x1, y1), (x2, y1), (x1, y2), (x2, y2) to be empty, its horizontal and vertical edges must not contain any other points.
We can implement this with a horizontal sweep-line algorithm. We first pre-process all points into two maps: one mapping x-coordinates to their sorted y-coordinates (xMap), and another mapping y-coordinates to their sorted x-coordinates (yMap).
We then sweep a line from bottom to top by iterating through the unique y-coordinates in sorted order. At each y level, we look at the points on that line. We consider every adjacent pair of points (x1, y) and (x2, y). This forms an empty horizontal segment. We use a hash map, lastYSeen, to remember the y-coordinate where we last saw the horizontal segment defined by (x1, x2).
If we find the pair (x1, x2) in our map, it means we have found a previous empty horizontal segment at prevY with the same x-coordinates. This gives us a rectangle with empty top and bottom edges. The final step is to verify that the vertical edges are also empty. We do this by using our xMap to check if y is the immediate successor of prevY in the sorted y-lists for both x1 and x2. If this holds, the rectangle is empty, and we update our maximum area.
import java.util.*; class Solution { public long maxAreaRectangle(int[] xCoord, int[] yCoord) { int n = xCoord.length; Map<Integer, List<Integer>> xMap = new HashMap<>(); Map<Integer, List<Integer>> yMap = new HashMap<>(); for (int i = 0; i < n; i++) { xMap.computeIfAbsent(xCoord[i], k -> new ArrayList<>()).add(yCoord[i]); yMap.computeIfAbsent(yCoord[i], k -> new ArrayList<>()).add(xCoord[i]); } for (List<Integer> list : xMap.values()) { Collections.sort(list); } for (List<Integer> list : yMap.values()) { Collections.sort(list); } List<Integer> sortedY = new ArrayList<>(yMap.keySet()); Collections.sort(sortedY); long maxArea = -1; Map<Long, Integer> lastYSeen = new HashMap<>(); for (int y : sortedY) { List<Integer> xCoords = yMap.get(y); for (int i = 0; i < xCoords.size() - 1; i++) { int x1 = xCoords.get(i); int x2 = xCoords.get(i + 1); long pairKey = pack(x1, x2); if (lastYSeen.containsKey(pairKey)) { int prevY = lastYSeen.get(pairKey); // Check vertical adjacency if (isVerticallyAdjacent(xMap, x1, prevY, y) && isVerticallyAdjacent(xMap, x2, prevY, y)) { long area = (long)(x2 - x1) * (y - prevY); if (maxArea == -1 || area > maxArea) { maxArea = area; } } } lastYSeen.put(pairKey, y); } } return maxArea; } private boolean isVerticallyAdjacent(Map<Integer, List<Integer>> xMap, int x, int y1, int y2) { List<Integer> yList = xMap.get(x); int idx = Collections.binarySearch(yList, y1); return idx >= 0 && idx + 1 < yList.size() && yList.get(idx + 1) == y2; } private long pack(int x1, int x2) { return ((long)x1 << 32) | x2; }}Complexity
Time
O(N log N), where N is the number of points. The preprocessing step of creating and sorting the lists in the maps takes `O(N log N)`. The sweep-line itself involves iterating through `O(N)` adjacent pairs in total, with each check involving binary searches (`O(log N)`), leading to a total time complexity of `O(N log N)`.
Space
O(N), where N is the number of points. This space is used for the `xMap`, `yMap`, and the `lastYSeen` map, all of which can store up to `O(N)` elements or pairs in total.
Trade-offs
Pros
Efficient
O(N log N)time complexity, which is suitable for the given constraints.Systematically finds all valid empty rectangles.
Cons
The implementation is more complex than the brute-force approach.
Requires careful management of multiple data structures and understanding of the geometric properties.
Video 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.