这道题真是考验水平。
我第二遍做,还花了一个多小时。
我用上了Sweep Line, Interval, TreeSet 三种数据结构在一起解决了这道题。真的是对基本功的极大考验。
思路就是扫描线把矩形拆成左右两条线扔到一个数组里,
然后按x坐标排序, 然后每个x位置上的线段一起处理。
维持一个正在进行的线段的treeSet,在每个x点加进来一些线段,扔掉一些线段。
相当于开了很多个有overlap的session,每个x点关掉一些session, 新开一些session。 每个x位置上更新一下session。
在每个x位置上看一下那些已经开始的和在这个x位置上刚刚关闭的session贡献了多少面积。 由于存在overlap,所以就是一个merge Interval的问题。 看一下merge interval后能cover的最大长度是多少。
我里面出的bug,TreeSet和List Of line应该有两个不同的比较器,我用了同一个, 出了bug.
其实用Segment Tree也能做。我先不写了。
下面这个解法真是太赞了。
https://leetcode.com/problems/rectangle-area-ii/discuss/138028/Clean-Recursive-Solution-Java
class Solution {
public int rectangleArea(int[][] rectangles) {
List<Line> lineList = new ArrayList<>();
int i = 0;
for (int[] rect : rectangles) {
lineList.add(new Line(rect[0], rect, i));
lineList.add(new Line(rect[2], rect, i++));
}
Collections.sort(lineList, new Comparator<Line>(){
public int compare(Line o1, Line o2) {
return o1.x - o2.x;
}
});
TreeSet<Line> treeSet = new TreeSet<>();
Integer lastX = null;
int slow = 0, fast = 0;
long ans = 0;
while (fast < lineList.size()) {
int curX = lineList.get(fast).x;
treeSet.add(lineList.get(fast));
while (fast + 1 < lineList.size() && lineList.get(fast + 1).x == (curX)) {
treeSet.add(lineList.get(++fast));
}
if (lastX == null) {
lastX = curX;
} else {
ans += getArea(treeSet, curX, lastX);
ans %= 1000000007;
lastX = curX;
}
fast++;
}
return (int) ans;
}
private long getArea(TreeSet<Line> treeSet, int x2, int x1) {
List<Interval> intervals = new ArrayList<>();
Iterator<Line> it = treeSet.iterator();
while(it.hasNext()) {
Line line = it.next();
if (line.start == x2) continue;
intervals.add(new Interval(line.low, line.hi));
if (line.end == x2) it.remove();
}
return (long) (x2 - x1) * ((long) mergeIntervalAndCombine(intervals));
}
private int mergeIntervalAndCombine(List<Interval> list) {
int ans= 0;
Interval holder = null;
for (Interval itv : list) {
if (holder == null) {
holder = new Interval(itv.start, itv.end);
continue;
}
if (itv.start > holder.end) {
ans += holder.end - holder.start;
holder.start = itv.start;
holder.end = itv.end;
} else {
holder.end = Math.max(holder.end, itv.end);
}
}
if (holder != null) ans += holder.end - holder.start;
return ans;
}
}
class Interval {
int start, end;
public Interval(int start, int end) {
this.start = start;
this.end = end;
}
}
class Line implements Comparable<Line> {
int x;
int low, hi;
int start, end;
int id;
public Line(int x, int[] rec, int id) {
this.x = x;
this.low = rec[1];
this.hi = rec[3];
this.start = rec[0];
this.end = rec[2];
this.id = id;
}
@Override
public int compareTo(Line that) {
if (this.low != that.low) return this.low < that.low ? -1 : 1;
return this.id - that.id;
//如果我不用id的话,treeSet会把compare为0的两个entry只留一个!!
}
}