LeetCode 391. Perfect Rectangle

方法一:Line Sweep

naive的想法是检查面积是否相等,但可以举出overlap的反例。顺着这种思路想,如果能判断是否重叠,那么本题就解决了。

暴力检查重叠太慢了。这里采用line sweep的方法。先根据x排序,维护一个对于y interval的active set。从左向右扫描,遇到左边界检查是否有重叠后insert进set,右边界则从set中erase。interval 重载了 < 符号。

注意如果x相等,右边界应该先处理,因为这种情况下不算overlap。如果左边界先处理,就会判断为overlap。

class Solution {
public:
    // [y1,y2] for rectangles
    struct interval {
        int start, end;
        interval(int s, int e):start(s),end(e){};
        bool operator < (const interval &other) const {
            return start < other.start;
        }
    };
    
    // left or right edge of rectangles
    struct edge {
        int x;
        interval i;
        int type; // left <- 1, right <- -1
    };
    
    bool isRectangleCover(vector<vector<int>>& rectangles) {
        vector<edge> vec;
        int minx = INT_MAX, miny = INT_MAX, maxx = INT_MIN, maxy = INT_MIN;
        int area=0;
        for (const auto &rect:rectangles){
            area += (rect[2]-rect[0])* (rect[3]-rect[1]);
            minx = min(rect[0], minx); miny = min(rect[1], miny);
            maxx = max(rect[2], maxx); maxy = max(rect[3], maxy); 
            vec.push_back({rect[0],{rect[1],rect[3]},1});
            vec.push_back({rect[2],{rect[1],rect[3]},-1});
        }
        sort(vec.begin(),vec.end(),[](edge e1, edge e2){
            if (e1.x==e2.x) return e1.type<e2.type;
            return e1.x<e2.x;
        });
        
        set<interval> active_intervals;
        for (edge tmp:vec){
            interval i=tmp.i; int type=tmp.type;
            if (type==1){ // left edge, insert interval and check
                auto it=active_intervals.lower_bound(i);
                if (it!=active_intervals.begin() && prev(it)->end > i.start) return false;
                if (it!=active_intervals.end() && i.end > it->start) return false;
                active_intervals.insert(it, i);
            }else{
                active_intervals.erase(i);
            }
        }
        
        return area == (maxx-minx) * (maxy - miny);
    }
};

 

时间复杂度 O(nlogn)

https://leetcode.com/problems/perfect-rectangle/discuss/87196/clean-C++-sweep-line-solution 

 

方法二:Corner Count

上述方法在check面积的同时,还检测了是否存在overlap。我们也可以检查每个corner出现的次数,如果在面积相等的情况下能组成矩形,那么奇数的corner有且仅能有四个:四个顶点。别的corner因为重合,必定是偶数个。

需要注意的是,pair没法直接hash,因此需要自定义hash函数。为了方便起见,这里用set,pair是先根据x,再根据y排序。

Why can't I use pair as key of unordered_set / unordered_map? 

class Solution {
public:    
    bool isRectangleCover(vector<vector<int>>& rectangles) {
        set<pair<int,int>> corners;
        int area=0;
        
        for (auto &rect:rectangles){
            vector<pair<int,int>> coords;
            coords.push_back({rect[0],rect[1]});
            coords.push_back({rect[2],rect[1]});
            coords.push_back({rect[0],rect[3]});
            coords.push_back({rect[2],rect[3]});

            for (auto coord:coords){
                if (corners.count(coord))
                    corners.erase(coord);
                else
                    corners.insert(coord);
            }
            area += (rect[2]-rect[0]) * (rect[3]-rect[1]);
        }
        
        if (corners.size()!=4) return false;
        auto bottomleft=corners.begin();
        auto topright=corners.rbegin();
        return area == (topright->first-bottomleft->first) * (topright->second-bottomleft->second);
    }
};

时间复杂度:set O(nlogn),如果自定义hash函数,用unordered_set,O(n)

转载于:https://www.cnblogs.com/hankunyan/p/11226494.html

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下 4载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下载 4使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、下载 4使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值