首页 > 其他分享 >leetcode 扫描线专题 06-leetcode.391 perfect-rectangle 力扣.391 完美矩形

leetcode 扫描线专题 06-leetcode.391 perfect-rectangle 力扣.391 完美矩形

时间:2024-11-18 11:41:14浏览次数:1  
标签:perfect 06 ints int 扫描线 矩形 rectangles leetcode

题目

给你一个数组 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 个矩形一起可以精确地覆盖一个矩形区域。

1

示例 2:

输入:rectangles = [[1,1,2,3],[1,3,2,4],[3,1,4,2],[3,2,4,4]]
输出:false
解释:两个矩形之间有间隔,无法覆盖成一个矩形。

2

示例 3:

输入:rectangles = [[1,1,3,3],[3,1,4,2],[1,3,2,4],[2,2,4,4]]
输出:false
解释:因为中间有相交区域,虽然形成了矩形,但不是精确覆盖。

3

提示:

1 <= rectangles.length <= 2 * 10^4

rectangles[i].length == 4

-10^5 <= xi < ai <= 10^5

-10^5 <= yi < bi <= 10^5

v1-基本思路 HashMap

思路

完美矩形其实需要符合 2 个条件:

  1. 所有的不重合的点应该只有最后完美大矩形的 4 个顶点

  2. 小矩形的面积之和等于最后的完美大矩形的面积

我们可以用 HashMap 记录点,出现偶数次的移除。同时累加每一个小矩形的面积。

最后的 4 个点,排序一下,计算出完美矩形的面积。

代码

class Solution {
    public boolean isRectangleCover(int[][] rectangles) {
        Map<String, Integer> pointMap = new HashMap<>();

        int area = 0;
        for(int[] ints : rectangles) {
            String one = ints[0]+","+ints[1];
            String two = ints[2]+","+ints[3];
            String three = ints[0]+","+ints[3];
            String four = ints[2]+","+ints[1];

            pointMap.put(one, (pointMap.getOrDefault(one, 0) + 1) % 2);
            pointMap.put(two, (pointMap.getOrDefault(two, 0) + 1) % 2);
            pointMap.put(three, (pointMap.getOrDefault(three, 0) + 1) % 2);
            pointMap.put(four, (pointMap.getOrDefault(four, 0) + 1) % 2);

            int currentArea = (ints[2]-ints[0]) * (ints[3] - ints[1]);
            area += currentArea;
        }

        List<Integer> xList = new ArrayList<>();
        List<Integer> yList = new ArrayList<>();

        for(Map.Entry<String,Integer> entry : pointMap.entrySet()) {
            String key = entry.getKey();
            Integer count = entry.getValue();
            if(count == 1) {
                String[] splits = key.split(",");
                int x = Integer.parseInt(splits[0]);
                int y = Integer.parseInt(splits[1]);

                xList.add(x);
                yList.add(y);
            }
        }

        // 应该有4个点
        if(xList.size() != 4 || yList.size() != 4) {
            return false;
        }

        // 面积计算
        Collections.sort(xList);
        Collections.sort(yList);
        int fourPointArea = (xList.get(3) - xList.get(0)) * (yList.get(3) - yList.get(0));

        if(fourPointArea == area) {
            return true;
        }
        return false;
    }
}

效果

57ms 击败36.84%

小结

这种解法其实要求对题目的理解比较深入,属于【特定解法】。

v2-Set 优化

思路

这种通过 Map 计算次数的,其实也可以通过 Set 优化一下。

1)如果点不存在,则加入

2)如果存在,则移除

整体思想类似。

还有一个改良点,使我们可以在遍历所有的点的时候,直接把 4 个顶点确认出来。

也就是 (min_x,min_y) 和 (max_x, max_y) 对应最后的完美节点的左下/右上,从而直接确定面积。

实现

    public boolean isRectangleCover(int[][] rectangles) {
        // 定义事件列表
        int totalArea = 0;
        int minX = Integer.MAX_VALUE, minY = Integer.MAX_VALUE, maxX = Integer.MIN_VALUE, maxY = Integer.MIN_VALUE;

        // 顶点集合
        Set<String> points = new HashSet<>();

        for (int[] rect : rectangles) {
            int x1 = rect[0], y1 = rect[1], x2 = rect[2], y2 = rect[3];

            // 更新边界
            minX = Math.min(minX, x1);
            minY = Math.min(minY, y1);
            maxX = Math.max(maxX, x2);
            maxY = Math.max(maxY, y2);

            // 累加面积
            totalArea += (x2 - x1) * (y2 - y1);

            // 更新顶点集合
            String[] corners = {
                    x1 + "," + y1, x1 + "," + y2, x2 + "," + y1, x2 + "," + y2
            };
            for (String corner : corners) {
                if (!points.add(corner)) {
                    points.remove(corner);
                }
            }
        }

        // 顶点检查:精确覆盖的矩形应该只有 4 个顶点
        if (points.size() != 4 ||
                !points.contains(minX + "," + minY) ||
                !points.contains(minX + "," + maxY) ||
                !points.contains(maxX + "," + minY) ||
                !points.contains(maxX + "," + maxY)) {
            return false;
        }

        // 检查总面积是否一致
        int expectedArea = (maxX - minX) * (maxY - minY);
        return expectedArea == totalArea;
    }

效果

39ms 击败 68.42%

效果好好一点。

v3-扫描线

思路

做算法,还是要看三叶!

【宫水三叶】常规扫描线题目

将每个矩形 rectangles[i] 看做两条竖直方向的边,使用 (x,y1,y2) 的形式进行存储(其中 y1 代表该竖边的下端点,y2 代表竖边的上端点),同时为了区分是矩形的左边还是右边,再引入一个标识位,即以四元组 (x,y1,y2,flag) 的形式进行存储。

一个完美矩形的充要条件为:对于完美矩形的每一条非边缘的竖边,都「成对」出现(存在两条完全相同的左边和右边重叠在一起);对于完美矩形的两条边缘竖边,均独立为一条连续的(不重叠)的竖边。

如图(红色框的为「完美矩形的边缘竖边」,绿框的为「完美矩形的非边缘竖边」):

扫描线

绿色:非边缘竖边必然有成对的左右两条完全相同的竖边重叠在一起;

红色:边缘竖边由于只有单边,必然不重叠,且连接成一条完成的竖边。

实现

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<int[]> left = new ArrayList<>();
            //如果该边是矩形的左边界,就加入right
            List<int[]> 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<int[]> 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]) continue;
                    return false;
                }
            } else {
                //如果是边界边判断是不是一条
                if (left.size()!=1&&right.size()==0||left.size()==0&&right.size()!=1) return false;
            }
        }
        return true;
    }
}

效果

25ms 击败 94.74%

小结

感觉有一个顺序的问题,这一题实际上是多矩形的重叠问题。

应该先学习一下 T836 + T223 + T850 可能再做这一题就会比较自然。

开源地址

为了便于大家学习,所有实现均已开源。欢迎 fork + star~

https://github.com/houbb/leetcode

扫描线专题

leetcode 扫描线专题 06-扫描线算法(Sweep Line Algorithm)

leetcode 扫描线专题 06-leetcode.218 the-skyline-problem 力扣.218 天际线问题

leetcode 扫描线专题 06-leetcode.252 meeting room 力扣.252 会议室

leetcode 扫描线专题 06-leetcode.253 meeting room ii 力扣.253 会议室 II

leetcode 扫描线专题 06-leetcode.1851 minimum-interval-to-include-each-query 力扣.1851 包含每个查询的最小区间

leetcode 扫描线专题 06-leetcode.223 rectangle-area 力扣.223 矩形面积

leetcode 扫描线专题 06-leetcode.3047 find-the-largest-area-of-square-inside-two-rectangles 力扣.3047 求交集区域的最大正方形面积

leetcode 扫描线专题 06-leetcode.391 perfect-rectangle 力扣.391 完美矩形

leetcode 扫描线专题 06-leetcode.836 rectangle-overlap 力扣.836 矩形重叠

leetcode 扫描线专题 06-leetcode.850 rectangle-area 力扣.850 矩形面积 II

标签:perfect,06,ints,int,扫描线,矩形,rectangles,leetcode
From: https://www.cnblogs.com/houbbBlogs/p/18552261

相关文章

  • 2024-2025-1 20241406 刘书含《计算机基础与程序设计》第8周学习总结
    2024-2025-120241406《计算机基础与程序设计》第8周学习总结这个作业属于哪个课程 2024-2025-1-计算机基础与程序设计这个作业要求在哪里 如2024-2025-1计算机基础与程序设计第八周作业这个作业的目标 功能设计与面向对象设计>面向对象设计过程面向对象语言三要素汇编、编......
  • 学期2024-2025-1 学号20241306 《计算机基础与程序设计》第8周学习总结
    学期2024-2025-1学号20241306《计算机基础与程序设计》第8周学习总结作业信息这个作业属于哪个课程<班级的链接>(如2024-2025-1-计算机基础与程序设计)这个作业要求在哪里<作业要求的链接>(如2024-2025-1计算机基础与程序设计第8周作业)这个作业的目标功能设计与面......
  • 20222306 2024-2025-1《网络与系统攻防技术》实验六实验报告
    1.实验内容1.1内容回顾总结这周都重点在于Metasploit工具的使用,我深入了解了对其功能和使用流程。Metasploit是一个功能强大的渗透测试框架,广泛应用于网络安全领域。它为安全专家、渗透测试人员和红队提供了一个全面的工具集,支持漏洞利用、攻击模拟和安全评估。Metasploit提......
  • 20222406 2024-2025-1 《网络与系统攻防技术》实验六实验报告
    202224062024-2025-1《网络与系统攻防技术》实验六实验报告1.实验内容前期渗透:在root权限下进行主机发现、端口扫描、扫系统版本和漏洞操作。多种漏洞利用:包括Vsftpd源码包后门漏洞(21端口)、SambaMS-RPCShell命令注入漏洞(139端口)、JavaRMISERVER命令执行漏洞(109......
  • 20222406 2024-2025-1 《网络与系统攻防技术》实验五实验报告
    202224062024-2025-1《网络与系统攻防技术》实验五实验报告1.实验内容对网站进行DNS域名查询,包括注册人、IP地址等信息,还通过相关命令查询IP地址注册人及地理位置。尝试获取QQ好友IP地址并查询其地理位置。使用nmap对靶机环境扫描,获取靶机IP活跃状态、开......
  • 20222306 2024-2025-1 《网络与系统攻防技术》实验五实验报告
    1.实验内容(1)从www.besti.edu.cn、baidu.com、sina.com.cn中选择一个DNS域名进行查询,获取如下信息:DNS注册人及联系方式该域名对应IP地址IP地址注册人及联系方式IP地址所在国家、城市和具体地理位置PS:使用whois、dig、nslookup、traceroute、以及各类在线和离线工具进行搜集......
  • (免费源码)计算机毕业设计必看必学 原创程序 java、PHP、python、文案全套、毕设成品等
    摘要由于数据库和数据仓库技术的快速发展,停车场管理系统建设越来越向模块化、智能化、自我服务和管理科学化的方向发展。停车场管理系统对处理对象和服务对象,自身的系统结构,处理能力,都将适应技术发展的要求发生重大的变化。停车场管理系统除了具有共享系统的全部功能以外,能......
  • 报错:ORA-00603、ORA-01092、ORA-00704, ORA-00604, ORA-00904
    基本情况在做备份还原的时候,可能是第三方备份软件的配置的原因,使得我在测试服务器做恢复测试时,使用的备份集不是我的预期的备份集。我想恢复的是19c的数据库,而我实际恢复的是一个11g的数据库。我在恢复控制文件、数据文件和归档日志文件的时候都很顺利,recoverdatabase也成功,但......
  • leetcode 扫描线专题 06-leetcode.252 meeting room 力扣.252 会议室
    扫描线专题leetcode扫描线专题06-扫描线算法(SweepLineAlgorithm)leetcode扫描线专题06-leetcode.218the-skyline-problem力扣.218天际线问题leetcode扫描线专题06-leetcode.252meetingroom力扣.252会议室leetcode扫描线专题06-leetcode.253meetingroomii......
  • 1.11--06:月度开销
    月度开销题目传送门思路给定连续N天的开销,需要将这些天分成M个财政周期,使得开销最多的财政周期的开销尽可能少。首先,我们可以确定一个财政周期的长度l,即将N天平均分成M个财政周期。这样每个财政周期的长度就是N/M。然后,我们需要计算每个财政周期中的开销总和。假设当前财政......