850. Rectangle Area II

这道题真是考验水平。
我第二遍做,还花了一个多小时。
我用上了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 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(){
            public int compare(Line o1, Line o2) {
                return o1.x - o2.x;
            }
        });
        
        
        TreeSet 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 treeSet, int x2, int x1) {
        List intervals = new ArrayList<>();
        Iterator 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 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 {
    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只留一个!!
    }
}

你可能感兴趣的:(850. Rectangle Area II)