391. 完美矩形
给你一个数组 rectangles ,其中 rectangles[i] = [xi, yi, ai, bi] 表示一个坐标轴平行的矩形。这个矩形的左下顶点是 (xi, yi) ,右上顶点是 (ai, bi) 。
如果所有矩形一起精确覆盖了某个矩形区域,则返回 true ;否则,返回 false 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/perfect-rectangle
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
哈希表
import java.util.HashMap;
import java.util.Map;
class Solution {
public boolean isRectangleCover(int[][] rectangles) {
if (rectangles == null || rectangles.length == 0) {
return true;
}
long area = 0;
int minX = Integer.MAX_VALUE, minY = Integer.MAX_VALUE, maxX = Integer.MIN_VALUE, maxY = Integer.MIN_VALUE;
Map cnt = new HashMap<>();
for (int[] rect : rectangles) {
int x1 = rect[0], y1 = rect[1], 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);
Point point1 = new Point(x1, y1);
Point point2 = new Point(x1, y2);
Point point3 = new Point(x2, y1);
Point point4 = new Point(x2, y2);
cnt.put(point1, cnt.getOrDefault(point1, 0) + 1);
cnt.put(point2, cnt.getOrDefault(point2, 0) + 1);
cnt.put(point3, cnt.getOrDefault(point3, 0) + 1);
cnt.put(point4, cnt.getOrDefault(point4, 0) + 1);
}
Point pointMinMin = new Point(minX, minY);
Point pointMinMax = new Point(minX, maxY);
Point pointMaxMin = new Point(maxX, minY);
Point pointMaxMax = new Point(maxX, maxY);
if (area != (long) (maxX - minX) * (maxY - minY) ||
cnt.getOrDefault(pointMinMin, 0) != 1 ||
cnt.getOrDefault(pointMinMax, 0) != 1 ||
cnt.getOrDefault(pointMaxMin, 0) != 1 ||
cnt.getOrDefault(pointMaxMax, 0) != 1) {
return false;
}
cnt.remove(pointMinMin);
cnt.remove(pointMinMax);
cnt.remove(pointMaxMin);
cnt.remove(pointMaxMax);
for (Map.Entry entry : cnt.entrySet()) {
int value = entry.getValue();
if (value != 2 && value != 4) {
return false;
}
}
return true;
}
}
class Point {
int x;
int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public int hashCode() {
return x + y;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Point) {
Point point2 = (Point) obj;
return this.x == point2.x && this.y == point2.y;
}
return false;
}
}
扫描线
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
class Solution {
public boolean isRectangleCover(int[][] rectangles) {
int len = rectangles.length * 2, ids = 0;
int[][] re = new int[len][4];
//初始化re数组,组成[横坐标,纵坐标下顶点,纵坐标上顶点,矩形的左边or右边标志]
for (int[] i : rectangles) {
re[ids++] = new int[]{i[0], i[1], i[3], 1};
re[ids++] = new int[]{i[2], i[1], i[3], -1};
}
//排序,按照横坐标进行排序,横坐标相等就按纵坐标排序
Arrays.sort(re, (o1, o2) -> o1[0] != o2[0] ? o1[0] - o2[0] : o1[1] - o2[1]);
//操作每一个顶点,判断是否符合要求
for (int i = 0; i < len; ) {
//如果该边是矩形的左边界,就加入left
List left = new ArrayList<>();
//如果该边是矩形的左边界,就加入right
List right = new ArrayList<>();
//标志该边是不是 矩形的左边
boolean flag = i == 0;
//判断横坐标相同情况下的边
int x = i;
while (x < len && re[x][0] == re[i][0]) x++;
//判断该横坐标的 边是不是符合要求
while (i < x) {
//因为是引用数据类型,所以可以直接操作list,相当于操作left或者right
List list = re[i][3] == 1 ? left : right;
if (list.isEmpty()) {
list.add(re[i++]);
} else {
int[] pre = list.get(list.size() - 1);
int[] cur = re[i++];
//有重叠 直接放回false
if (cur[1] < pre[2]) return false;
if (cur[1] == pre[2]) pre[2] = cur[2];
else list.add(cur);
}
}
//判断边是中间边还是边界边
if (!flag && x < len) {
//如果是中间边 判断左右是不是相等
if (left.size() != right.size()) return false;
for (int j = 0; j < left.size(); ++j) {
if (left.get(j)[2] != right.get(j)[2] || left.get(j)[1] != right.get(j)[1]) return false;
}
} else {
//如果是边界边判断是不是一条
if (left.size() != 1 && right.size() == 0 || left.size() == 0 && right.size() != 1) return false;
}
}
return true;
}
}