Hard
题目描述
给定一个数组 rectangles,其中 rectangles[i] = [xi, yi, ai, bi] 表示一个轴对齐的矩形。矩形的左下角点为 (xi, yi),右上角点为 (ai, bi)。
如果所有矩形一起恰好覆盖了某个矩形区域,返回 true。
示例 1:
输入:rectangles = [[1,1,3,3],[3,1,4,2],[3,2,4,4],[1,3,2,4],[2,3,3,4]]
输出:true
解释:5 个矩形一起可以精确地覆盖一个矩形区域。
示例 2:
输入:rectangles = [[1,1,2,3],[1,3,2,4],[3,1,4,2],[3,2,4,4]]
输出:false
解释:两个矩形之间有间隔,无法覆盖成一个矩形。
示例 3:
输入:rectangles = [[1,1,3,3],[3,1,4,2],[1,3,2,4],[2,2,4,4]]
输出:false
解释:因为中间有相互重叠的矩形。
提示:
1 <= rectangles.length <= 2 * 10^4rectangles[i].length == 4-10^5 <= xi < ai <= 10^5-10^5 <= yi < bi <= 10^5
解题思路
这是一个几何问题,需要判断给定的矩形是否能完美拼接成一个大矩形。
核心思路:
完美矩形需要满足两个条件:
- 面积匹配:所有小矩形的面积之和等于最终大矩形的面积
- 顶点唯一性:除了大矩形的四个顶点外,其他所有顶点都应该出现偶数次
算法步骤:
- 遍历所有矩形,计算总面积和边界范围
- 使用哈希集合记录所有顶点,如果顶点重复出现则移除(利用异或性质)
- 最终集合中应该只剩下4个顶点,且这4个顶点恰好是大矩形的四个角
关键观察:
- 在完美拼接中,内部顶点会被相邻矩形共享,出现偶数次
- 只有最外层的4个角点会出现奇数次(实际上是1次)
- 使用集合的添加/删除操作可以自动过滤出现偶数次的点
这种方法的时间复杂度为O(n),空间复杂度也是O(n),是最优解法。
代码实现
class Solution {
public:
bool isRectangleCover(vector<vector<int>>& rectangles) {
long long area = 0;
int minX = INT_MAX, minY = INT_MAX;
int maxX = INT_MIN, maxY = INT_MIN;
set<pair<int, int>> points;
for (auto& rect : rectangles) {
int x1 = rect[0], y1 = rect[1];
int x2 = rect[2], y2 = rect[3];
area += (long long)(x2 - x1) * (y2 - y1);
minX = min(minX, x1);
minY = min(minY, y1);
maxX = max(maxX, x2);
maxY = max(maxY, y2);
vector<pair<int, int>> corners = {{x1, y1}, {x1, y2}, {x2, y1}, {x2, y2}};
for (auto& corner : corners) {
if (points.count(corner)) {
points.erase(corner);
} else {
points.insert(corner);
}
}
}
return area == (long long)(maxX - minX) * (maxY - minY) &&
points.size() == 4 &&
points.count({minX, minY}) &&
points.count({minX, maxY}) &&
points.count({maxX, minY}) &&
points.count({maxX, maxY});
}
};
class Solution:
def isRectangleCover(self, rectangles: List[List[int]]) -> bool:
area = 0
minX = minY = float('inf')
maxX = maxY = float('-inf')
points = set()
for x1, y1, x2, y2 in rectangles:
area += (x2 - x1) * (y2 - y1)
minX = min(minX, x1)
minY = min(minY, y1)
maxX = max(maxX, x2)
maxY = max(maxY, y2)
corners = [(x1, y1), (x1, y2), (x2, y1), (x2, y2)]
for corner in corners:
if corner in points:
points.remove(corner)
else:
points.add(corner)
return (area == (maxX - minX) * (maxY - minY) and
len(points) == 4 and
{(minX, minY), (minX, maxY), (maxX, minY), (maxX, maxY)} == points)
public class Solution {
public bool IsRectangleCover(int[][] rectangles) {
long area = 0;
int minX = int.MaxValue, minY = int.MaxValue;
int maxX = int.MinValue, maxY = int.MinValue;
var points = new HashSet<(int, int)>();
foreach (var rect in rectangles) {
int x1 = rect[0], y1 = rect[1];
int x2 = rect[2], y2 = rect[3];
area += (long)(x2 - x1) * (y2 - y1);
minX = Math.Min(minX, x1);
minY = Math.Min(minY, y1);
maxX = Math.Max(maxX, x2);
maxY = Math.Max(maxY, y2);
var corners = new (int, int)[] {(x1, y1), (x1, y2), (x2, y1), (x2, y2)};
foreach (var corner in corners) {
if (points.Contains(corner)) {
points.Remove(corner);
} else {
points.Add(corner);
}
}
}
return area == (long)(maxX - minX) * (maxY - minY) &&
points.Count == 4 &&
points.Contains((minX, minY)) &&
points.Contains((minX, maxY)) &&
points.Contains((maxX, minY)) &&
points.Contains((maxX, maxY));
}
}
var isRectangleCover = function(rectangles) {
if (rectangles.length === 0) return false;
let minX = Infinity, minY = Infinity;
let maxX = -Infinity, maxY = -Infinity;
let totalArea = 0;
let corners = new Set();
for (let [x1, y1, x2, y2] of rectangles) {
minX = Math.min(minX, x1);
minY = Math.min(minY, y1);
maxX = Math.max(maxX, x2);
maxY = Math.max(maxY, y2);
totalArea += (x2 - x1) * (y2 - y1);
let rectCorners = [
x1 + ',' + y1,
x1 + ',' + y2,
x2 + ',' + y1,
x2 + ',' + y2
];
for (let corner of rectCorners) {
if (corners.has(corner)) {
corners.delete(corner);
} else {
corners.add(corner);
}
}
}
let expectedArea = (maxX - minX) * (maxY - minY);
if (totalArea !== expectedArea) return false;
if (corners.size !== 4) return false;
let expectedCorners = new Set([
minX + ',' + minY,
minX + ',' + maxY,
maxX + ',' + minY,
maxX + ',' + maxY
]);
for (let corner of corners) {
if (!expectedCorners.has(corner)) return false;
}
return true;
};
复杂度分析
| 复杂度类型 | 分析 |
|---|---|
| 时间复杂度 | O(n),其中 n 是矩形的数量。需要遍历所有矩形,每个矩形处理4个顶点 |
| 空间复杂度 | O(n),最坏情况下集合中可能存储 4n 个顶点 |