391. 完美矩形 扫描线

391. 完美矩形

难度困难234

给你一个数组 rectangles ,其中 rectangles[i] = [xi, yi, ai, bi] 表示一个坐标轴平行的矩形。这个矩形的左下顶点是 (xi, yi) ,右上顶点是 (ai, bi) 。

如果所有矩形一起精确覆盖了某个矩形区域,则返回 true ;否则,返回 false 。

示例 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 * 1e4
  • rectangles[i].length == 4
  • -105 <= xi, yi, ai, bi <= 1e5

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/perfect-rectangle
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

做题结果

成功,写出扫描线方式,但是不太熟练 

方法:扫描线

1. 按行扫描,按y排序,同行的先处理结束行,再处理开始行

2. 结束行:删掉头尾:如果有任何线以当前开头结尾则产生新的结尾,加到b,否则和当前已产生的结尾抵消;如果任何线以当前结尾开头则产生新的开头,添加到a,否则和当前产生的开头抵消。当前开头从去重哈希中移除

3. 开始行:添加开头不能产生重复。当前的开头结尾不断链接,最终会产生唯一的开头和唯一的结尾。如果第一次拿到开头结尾,则记录,否则判断是否相同开头结尾,是否唯一

4. 非法条件:开头重复/产生多个开头结尾/开头结尾和前面已出现行的开头结尾不一致

class Solution {
        final int OPEN = 1;
        final int CLOSE = 0;
        public boolean isRectangleCover(int[][] rectangles) {
            int n = rectangles.length;
            int[][] sortLines = new int[n*2][4];
            for(int i = 0; i < n; i++){
                int[] rectangle=rectangles[i];
                int x1 = rectangle[0];
                int y1 = rectangle[1];
                int x2 = rectangle[2];
                int y2 = rectangle[3];
                sortLines[i*2] = new int[]{OPEN,y1,x1,x2};
                sortLines[i*2+1] = new int[]{CLOSE,y2,x1,x2};
            }

            Arrays.sort(sortLines,(a,b)->{
                if(a[1]!=b[1]) return a[1]-b[1];
                if(a[0]!=b[0]) return a[0]-b[0];
                return a[2]-b[2];
            });
            int startX = Integer.MIN_VALUE;
            int endX = Integer.MIN_VALUE;
            Set<Integer> a = new HashSet<>();
            Set<Integer> b = new HashSet<>();
            Map<Integer,Integer> map = new HashMap<>();
            for(int i = 0; i < n*2; ){
                int y = sortLines[i][1];
                while (i<n*2&&y==sortLines[i][1]){
                    if(sortLines[i][0]==OPEN && map.containsKey(sortLines[i][2])) return false;
                    int start = sortLines[i][2];
                    int end = sortLines[i][3];
                    if(sortLines[i][0]==OPEN){
                        map.put(start,end);
                        if(b.contains(start)) b.remove(start);
                        else a.add(start);
                        if(a.contains(end)) a.remove(end);
                        else b.add(end);
                    }else{
                        map.remove(start);
                        if(a.contains(start)) a.remove(start);
                        else b.add(start);

                        if(b.contains(end)) b.remove(end);
                        else a.add(end);
                    }
                  
                    ++i;
                }
                //检查x
                if(i<n*2&&map.isEmpty()) return false;
                if(!map.isEmpty()){
                    int min = Integer.MAX_VALUE;
                    int max = Integer.MIN_VALUE;
                    for(int key:a) min = key;
                    for(int value:b) max = value;

                    if(startX == Integer.MIN_VALUE){
                        startX = min;
                        endX = max;
                    }

                    if(startX != min || endX != max) return false;
                    if(a.size()!=1||!a.contains(min)) return false;
                    if(b.size()!=1||!b.contains(max)) return false;
                }
            }
            return true;
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值