LeetCode 391:完美矩形
LeetCode 391 完美矩形解法摘要 判断若干小矩形能否精确覆盖大矩形需满足: 面积守恒:小矩形总面积等于大矩形面积(避免间隙); 顶点规则:除大矩形的4个角点外,其他顶点必须出现偶数次(避免重叠)。 算法步骤: 计算边界与面积:确定大矩形范围(left/bottom/right/top),若小矩形面积总和不匹配则失败; 统计顶点:哈希表记录所有顶点出现次数,大矩形角点必须出现1次,其余顶点
·
LeetCode 391:完美矩形

问题本质:精确覆盖的两个核心条件
给定若干轴对齐的小矩形,判断它们是否能恰好覆盖一个大矩形(无重叠、无间隙)。需满足:
- 面积守恒:所有小矩形的面积和等于大矩形的面积。
- 顶点唯一:除大矩形的4个顶点外,其他顶点必须出现偶数次(重叠时顶点会被覆盖两次,间隙则会导致顶点缺失)。
核心思路:面积 + 顶点统计
1. 面积校验
- 遍历所有小矩形,计算 大矩形的边界(最小左边界
left、最小下边界bottom、最大右边界right、最大上边界top)。 - 计算 小矩形总面积 和 大矩形面积,若不相等,直接返回
false(存在间隙)。
2. 顶点校验
- 用哈希表统计所有小矩形的 4个顶点(左下、左上、右下、右上)的出现次数。
- 大矩形的4个顶点必须仅出现1次(唯一角),其余顶点必须出现偶数次(重叠抵消)。
算法步骤详解
步骤 1:计算大矩形边界与面积
int left = Integer.MAX_VALUE; // 初始为极大值,确保被更新
int bottom = Integer.MAX_VALUE;
int right = Integer.MIN_VALUE; // 初始为极小值,确保被更新
int top = Integer.MIN_VALUE;
long sumArea = 0; // 小矩形总面积
for (int[] rect : rectangles) {
int x1 = rect[0], y1 = rect[1], x2 = rect[2], y2 = rect[3];
// 更新大矩形边界
left = Math.min(left, x1);
bottom = Math.min(bottom, y1);
right = Math.max(right, x2);
top = Math.max(top, y2);
// 累加小矩形面积
sumArea += (long)(x2 - x1) * (y2 - y1);
}
// 大矩形面积
long totalArea = (long)(right - left) * (top - bottom);
if (sumArea != totalArea) {
return false; // 面积不等,直接失败
}
步骤 2:统计顶点出现次数
用哈希表记录每个顶点的出现次数(顶点用 (x, y) 唯一标识,通过位运算转换为 long 键):
Map<Long, Integer> pointCount = new HashMap<>();
for (int[] rect : rectangles) {
int x1 = rect[0], y1 = rect[1], x2 = rect[2], y2 = rect[3];
// 四个顶点:左下、左上、右下、右上
addPoint(pointCount, x1, y1);
addPoint(pointCount, x1, y2);
addPoint(pointCount, x2, y1);
addPoint(pointCount, x2, y2);
}
// 辅助方法:将(x,y)转换为唯一long键
private long getKey(int x, int y) {
return (long)x << 32 | (y & 0xFFFFFFFFL); // x左移32位,y存低32位
}
// 辅助方法:更新顶点计数
private void addPoint(Map<Long, Integer> map, int x, int y) {
long key = getKey(x, y);
map.put(key, map.getOrDefault(key, 0) + 1);
}
步骤 3:校验顶点规则
-
大矩形的4个顶点必须仅出现1次:
int[][] corners = { {left, bottom}, // 左下 {left, top}, // 左上 {right, bottom}, // 右下 {right, top} // 右上 }; for (int[] corner : corners) { int x = corner[0], y = corner[1]; long key = getKey(x, y); Integer cnt = pointCount.get(key); if (cnt == null || cnt != 1) { return false; // 顶点不存在或次数不对 } pointCount.put(key, cnt - 1); // 次数减为0(后续统一校验偶数) } -
所有顶点次数必须为偶数(包括大矩形顶点减为0的情况):
for (int count : pointCount.values()) { if (count % 2 != 0) { return false; // 存在奇数次顶点,说明重叠或缺失 } }
完整代码(Java)
import java.util.HashMap;
import java.util.Map;
class Solution {
public boolean isRectangleCover(int[][] rectangles) {
if (rectangles == null || rectangles.length == 0) {
return false;
}
// 步骤1:计算大矩形的边界和总面积
int left = Integer.MAX_VALUE;
int bottom = Integer.MAX_VALUE;
int right = Integer.MIN_VALUE;
int top = Integer.MIN_VALUE;
long sumArea = 0;
for (int[] rect : rectangles) {
int x1 = rect[0], y1 = rect[1], x2 = rect[2], y2 = rect[3];
left = Math.min(left, x1);
bottom = Math.min(bottom, y1);
right = Math.max(right, x2);
top = Math.max(top, y2);
sumArea += (long)(x2 - x1) * (y2 - y1);
}
// 校验面积是否相等
long totalArea = (long)(right - left) * (top - bottom);
if (sumArea != totalArea) {
return false;
}
// 步骤2:统计所有顶点的出现次数
Map<Long, Integer> pointCount = new HashMap<>();
for (int[] rect : rectangles) {
int x1 = rect[0], y1 = rect[1], x2 = rect[2], y2 = rect[3];
addPoint(pointCount, x1, y1);
addPoint(pointCount, x1, y2);
addPoint(pointCount, x2, y1);
addPoint(pointCount, x2, y2);
}
// 步骤3:校验大矩形的四个顶点(必须出现1次,然后次数减为0)
int[][] corners = {
{left, bottom},
{left, top},
{right, bottom},
{right, top}
};
for (int[] corner : corners) {
int x = corner[0], y = corner[1];
long key = getKey(x, y);
Integer cnt = pointCount.get(key);
if (cnt == null || cnt != 1) {
return false;
}
pointCount.put(key, cnt - 1); // 次数减为0
}
// 步骤4:校验所有顶点的次数是否为偶数
for (int count : pointCount.values()) {
if (count % 2 != 0) {
return false;
}
}
return true;
}
private long getKey(int x, int y) {
return (long)x << 32 | (y & 0xFFFFFFFFL);
}
private void addPoint(Map<Long, Integer> map, int x, int y) {
long key = getKey(x, y);
map.put(key, map.getOrDefault(key, 0) + 1);
}
}
复杂度分析
- 时间复杂度:
O(n),n是小矩形数量。遍历矩形(O(n))、统计顶点(O(n),每个矩形4个顶点)、校验顶点(O(n),顶点数最多为4n,但哈希表遍历是线性的)。 - 空间复杂度:
O(n),哈希表最多存储4n个顶点(实际远小于,因为大量顶点会重复)。
示例验证
- 示例1:面积相等,大矩形顶点各出现1次,其余顶点偶数次 → 返回
true。 - 示例2:存在间隙,面积虽相等,但顶点次数不满足 → 返回
false。 - 示例3:存在重叠,某顶点出现奇数次 → 返回
false。
该方法通过面积和顶点的双重约束,高效判断完美覆盖,是处理几何覆盖问题的经典思路。
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)