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

题目

矩形以列表 [x1, y1, x2, y2] 的形式表示,其中 (x1, y1) 为左下角的坐标,(x2, y2) 是右上角的坐标。

矩形的上下边平行于 x 轴,左右边平行于 y 轴。

如果相交的面积为 正 ,则称两矩形重叠。

需要明确的是,只在角或边接触的两个矩形不构成重叠。

给出两个矩形 rec1 和 rec2。如果它们重叠,返回 true;否则,返回 false 。

示例 1:

输入:rec1 = [0,0,2,2], rec2 = [1,1,3,3]
输出:true

示例 2:

输入:rec1 = [0,0,1,1], rec2 = [1,0,2,1]
输出:false

示例 3:

输入:rec1 = [0,0,1,1], rec2 = [2,2,3,3]
输出:false

提示:

rect1.length == 4

rect2.length == 4

-10^9 <= rec1[i], rec2[i] <= 10^9

rec1 和 rec2 表示一个面积不为零的有效矩形

小结

感觉有一个顺序的问题。

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

v1-投影

思路

判断两个矩形是否重叠的通用条件是通过其投影区间是否有交集:

两矩形沿 x 轴投影有重叠,且两矩形沿 y 轴投影有重叠。

二维

矩形投影到坐标轴上,就变成了区间。稍加思考,我们发现:两个互相重叠的矩形,它们在 x 轴和 y 轴上投影出的区间也是互相重叠的。这样,我们就将矩形重叠问题转化成了区间重叠问题。

区间重叠是一维的问题,比二维问题简单很多。

我们可以穷举出两个区间所有可能的 6 种关系:

一维

可以看到,区间的 6 种关系中,不重叠只有两种情况,判断不重叠更简单。

假设两个区间分别是 [s1, e1] 和 [s2, e2] 的话,区间不重叠的两种情况就是 e1 <= s2 和 e2 <= s1。

重叠

公式化为:

x 轴投影相交:rec1[2] > rec2[0] && rec1[0] < rec2[2] y 轴投影相交:rec1[3] > rec2[1] && rec1[1] < rec2[3]

解法

class Solution {public boolean isRectangleOverlap(int[] rec1, int[] rec2) {// 判断 x 轴和 y 轴投影是否有交集boolean xOverlap = rec1[2] > rec2[0] && rec1[0] < rec2[2];boolean yOverlap = rec1[3] > rec2[1] && rec1[1] < rec2[3];// 两个投影都有交集才算重叠return xOverlap && yOverlap;}
}

小结

投影这种解法看起来很简单,实际上很巧妙,但是有时候我们不见得能想到。

v2-重叠面积

思路

如果两个矩形重叠,那么重叠的面积一定大于0.

于是问题变成如何计算重叠的矩形面积?

二维

如果有重叠,重叠的部分也一定是一个矩形

交集面积的计算方式是基于两个矩形的重叠区域的 左下角和右上角的坐标 来推算的。

具体来说,两个矩形的交集矩形(如果存在)也是一个矩形,它的边界由两个矩形的边界决定。

计算重叠面积

  • 第一个矩形 rec1 = [x1, y1, x2, y2],表示其左下角坐标为 (x1, y1),右上角坐标为 (x2, y2)

  • 第二个矩形 rec2 = [x3, y3, x4, y4],表示其左下角坐标为 (x3, y3),右上角坐标为 (x4, y4)

如果两个矩形有交集,那么交集的矩形的左下角和右上角的坐标可以通过取两者的最大和最小值来确定:

  • 交集矩形的左下角(x1', y1') = (max(x1, x3), max(y1, y3))

  • 交集矩形的右上角(x2', y2') = (min(x2, x4), min(y2, y4))

判断交集是否存在

交集矩形的面积只有在其宽度和高度都大于 0 时才存在。

如果交集矩形的宽度或高度小于等于 0,说明两个矩形没有交集。

因此,交集矩形的宽度和高度的计算方式如下:

  • 宽度:width = x2' - x1'
  • 高度:height = y2' - y1'

交集矩形的面积则为:

  • 面积 = width * height,但是如果宽度或高度小于等于 0,面积就为 0。

因此,计算交集的面积时,我们需要确保 width > 0height > 0,否则交集的面积为 0。

代码示例

public class Solution {public boolean isRectangleOverlap(int[] rec1, int[] rec2) {// 计算交集矩形的左下角和右上角int x1 = Math.max(rec1[0], rec2[0]);int y1 = Math.max(rec1[1], rec2[1]);int x2 = Math.min(rec1[2], rec2[2]);int y2 = Math.min(rec1[3], rec2[3]);// 计算交集的宽度和高度int width = x2 - x1;int height = y2 - y1;// 如果交集的宽度和高度都大于 0,说明有重叠if (width > 0 && height > 0) {return true;}// 没有重叠return false;}
}

效果

0ms 100%

小结

这个感觉比方法 1 的投影应该更容易想到一些。

而且可以在后续的 T223 T3047 中拓展使用。

v3-扫描线

扫描线

使用扫描线(sweepline)方法解决这个问题也是一种非常常见且高效的方式。

扫描线的基本思路是将矩形视为一系列的 线段,并在 x 轴方向上依次“扫描”这些线段,检查是否有重叠。

思路

  1. 将矩形的边界转换为事件

    • 每个矩形有 两条边,一个是左边界(x1),一个是右边界(x2)。这两条边界构成了扫描线的“事件”。
    • 对于每个矩形,生成两个事件:
      • 左边界事件:表示矩形开始时,增加一个 y 区间(从 y1y2)。
      • 右边界事件:表示矩形结束时,移除一个 y 区间(从 y1y2)。
  2. 事件排序

    • 所有的事件按 x 坐标排序。如果 x 坐标相同,优先处理右边界事件(因为在同一位置时,应该先移除结束的矩形,再处理新的开始)。
  3. 扫描线处理

    • 扫描线从左到右扫描这些事件。当扫描到一个 左边界事件 时,添加相应的 y 区间;当扫描到一个 右边界事件 时,移除相应的 y 区间。
    • 在每次添加或移除事件时,检查当前的 y 区间是否存在重叠。如果存在重叠,那么矩形就重叠。
  4. 区间重叠检查

    • 在扫描线过程中,维护一个 活动的 y 区间集合,该集合记录了当前所有矩形在 y 轴上的区间。
    • 每次添加新的 y 区间时,检查当前 y 区间是否与已经存在的区间重叠。如果重叠,则说明存在矩形重叠。

详细步骤

  1. 定义事件

    • 每个矩形 rec = [x1, y1, x2, y2] 会生成两个事件:
      • 左边界事件 (x1, y1, y2, 1) 表示矩形开始(1 表示是左边界)。
      • 右边界事件 (x2, y1, y2, -1) 表示矩形结束(-1 表示是右边界)。
  2. 排序事件

    • 按照 x 坐标排序,如果两个事件的 x 坐标相同,右边界事件优先。

为什么要这样做?

因为在扫描线的过程中,当我们遇到同一个 x 坐标时,我们希望先处理右边界事件,再处理左边界事件。

这是为了避免在处理过程中出现误判的情况。

比如,当一个矩形的右边界和另一个矩形的左边界在同一个 x 坐标上时,我们应该先“移除”第一个矩形的 y 区间,然后再“添加”第二个矩形的 y 区间。

  1. 扫描并更新活动区间
    • 用一个数据结构(比如 TreeSet)维护当前的活动区间。每次扫描到一个事件时,更新该区间,检查是否存在重叠。

如何判断是否重叠:

private boolean hasOverlap(TreeSet<int[]> activeIntervals) {int prevEnd = Integer.MIN_VALUE;  // 初始化 prevEnd 为一个极小值for (int[] interval : activeIntervals) {// 如果当前区间的起始点小于前一个区间的终点,说明有重叠if (interval[0] < prevEnd) {return true;  // 有重叠,返回 true}prevEnd = interval[1];  // 更新 prevEnd 为当前区间的终点}return false;  // 如果没有任何重叠,返回 false
}

实现

import java.util.*;public class Solution {public boolean isRectangleOverlap(int[] rec1, int[] rec2) {// 如果 rec1 和 rec2 的 x 范围没有交集,直接返回 falseif (rec1[2] <= rec2[0] || rec1[0] >= rec2[2]) {return false;}// 生成事件列表List<int[]> events = new ArrayList<>();// 对 rec1 和 rec2 的边界生成事件// 左边界事件 [x, y1, y2, type],type = 1 表示左边界,-1 表示右边界events.add(new int[]{rec1[0], rec1[1], rec1[3], 1});  // rec1 左边界events.add(new int[]{rec1[2], rec1[1], rec1[3], -1}); // rec1 右边界events.add(new int[]{rec2[0], rec2[1], rec2[3], 1});  // rec2 左边界events.add(new int[]{rec2[2], rec2[1], rec2[3], -1}); // rec2 右边界// 按 x 坐标排序,x 相同的话,优先处理右边界事件events.sort((a, b) -> a[0] == b[0] ? b[3] - a[3] : a[0] - b[0]);// 活动区间维护TreeSet<int[]> activeIntervals = new TreeSet<>((a, b) -> a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]);for (int[] event : events) {int x = event[0];int y1 = event[1];int y2 = event[2];int type = event[3];if (type == 1) { // 左边界事件,加入活动区间activeIntervals.add(new int[]{y1, y2});} else { // 右边界事件,移除活动区间activeIntervals.remove(new int[]{y1, y2});}// 检查活动区间是否有重叠if (hasOverlap(activeIntervals)) {return true;}}return false;}// 检查活动区间是否有重叠private boolean hasOverlap(TreeSet<int[]> activeIntervals) {int prevEnd = Integer.MIN_VALUE;for (int[] interval : activeIntervals) {if (interval[0] < prevEnd) {return true;  // 有重叠}prevEnd = interval[1]; // 更新 prevEnd}return false;  // 没有重叠}
}

效果

1ms 击败2.08%

小结

整体上而言,我比较喜欢重叠面积的方式,这种比较好想到,而且可以扩展。

当然扫描线也是一种很通用的解法。

这一题的巧思属于维度投影的解法,很巧妙。

开源地址

为了便于大家学习,所有实现均已开源。欢迎 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

参考资料

https://leetcode.cn/problems/4sum/

https://leetcode.cn/problems/rectangle-overlap/solutions/155825/tu-jie-jiang-ju-xing-zhong-die-wen-ti-zhuan-hua-we/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/474498.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ASP.NET MVC宠物商城系统

该系统采用B/S架构&#xff0c;使用C#编程语言进行开发&#xff0c;以ASP.NET MVC框架为基础&#xff0c;以Visual Studio 2019为开发工具&#xff0c;数据库采用SQL Server进行保存数据。系统主要功能包括登录注册、宠物展示、个人中心、我的订单、购物车、用户管理、宠物类别…

最优化方法_罚函数法例题

1 外点罚函数 算法1 外点罚函数法 给定初点&#xff0c;初始罚因子,放大系数&#xff0c;允许误差&#xff0c;置k1。以为初始点&#xff0c;求解无约束问题得最优解。如果,则停止计算&#xff0c;为约束问题的近似最优解&#xff1b;否 则&#xff0c;增大罚因子&#xff0c;令…

python调用MySql保姆级教程(包会的)

目录 一、下载MySql 二、安装MySql 三、验证MySql是否OK 1、MySQL控制台验证 2、命令提示符cmd窗口验证 四、Python调用MySql 4.1 安装pysql 4.2 使用pysql 4.2.1、连接数据库服务器并且创建数据库和表 4.2.2 、将人脸识别考勤系统识别到的数据自动填入到数据库的表单中…

【鸿蒙生态崛起,开发者有哪些机遇与挑战?】HarmonyOS NEXT 引领数字化未来

文章目录 前言一、HarmonyOS NEXT 特点与升级二、全面突破操作系统核心技术三、鸿蒙生态全面守护用户隐私四、鸿蒙生态的崛起与开发者机遇五、全新鸿蒙生态引领数字化未来小结 前言 鸿蒙系统不断发展&#xff0c;有与安卓、iOS 形成三足鼎立之势&#xff0c;且其在智能手机、智…

ssh无法连接Ubuntu

试了多次ssh都无法连接&#xff0c;明明可以上网 网卡、防火墙、端口都没有问题&#xff0c;就是连接不上 结果是这个版本Ubuntu镜像默认没有安装ssh服务 安装SSH服务&#xff1a;apt-get install openssh-server 开启SSH服务&#xff1a;/etc/init.d/ssh start 就可以连接…

基于Java Springboot外卖平台系统

一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue、Element-ui 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 数…

vue2动态导出多级表头表格

需求&#xff1a;导出多级表格&#xff0c;如下&#xff0c;每个人名对应的是不同的城市金钱和年龄&#xff0c;日期占俩行&#xff0c;需要根据数据进行动态展示 1.效果 2.关键代码讲解 2.1数据源 2.2所需插件 npm install xlsx 2.3关键代码 创建name组和date组&#xff0c…

散户持股增厚工具:智能T0算法交易

最近市场很多都说牛市&#xff0c;但是大多数朋友怎么来的又怎么吐出去了。这会儿我们用T0的智能算法交易又可以增厚我们的持仓收益。简单来说&#xff0c;就是基于用户原有的股票持仓&#xff0c;针对同一标的&#xff0c;配合智能T0算法&#xff0c;每天全自动操作&#xff0…

独立开发:一人公司模式下副业产品的全流程

在数字经济的浪潮下&#xff0c;越来越多的开发者选择成为自由职业者或创立一人公司&#xff0c;通过副业产品开发实现个人价值与经济收益的双重提升。本文将围绕一人公司模式下副业产品的设计、开发、运营及变现落地全流程&#xff0c;提供一套实战指南&#xff0c;帮助有志于…

SD模型微调之Textual Inversion和Embedding fine-tuning

​ &#x1f33a;系列文章推荐&#x1f33a; 扩散模型系列文章正在持续的更新&#xff0c;更新节奏如下&#xff0c;先更新SD模型讲解&#xff0c;再更新相关的微调方法文章&#xff0c;敬请期待&#xff01;&#xff01;&#xff01;&#xff08;本文及其之前的文章均已更新&a…

【Vue笔记】基于vue3 + element-plus + el-dialog封装一个自定义的dialog弹出窗口组件

这篇文章,介绍一下如何使用vue3+element-plus中的el-dialog组件,自己封装一个通用的弹出窗口组件。运行效果如下所示: 目录 1.1、父子组件通信 1.2、自定义VDialog组件(【v-model】模式) 1.2.1、编写VDialog组件代码 1.2.2、使用VDialog组件 1.2.3、运行效果 1.3、自…

Spring Cloud Alibaba [Gateway]网关。

1 简介 网关作为流量的入口&#xff0c;常用功能包括路由转发、权限校验、限流控制等。而springcloudgateway 作为SpringCloud 官方推出的第二代网关框架&#xff0c;取代了Zuul网关。 1.1 SpringCloudGateway特点: &#xff08;1&#xff09;基于Spring5&#xff0c;支持响应…

不完全微分PID控制算法

不完全微分PID控制算法是一种改进的PID控制方法&#xff0c;主要针对PID控制中的微分环节对高频噪声敏感的问题。通过对微分项进行优化和改造&#xff0c;减少其对噪声的放大作用&#xff0c;同时保留对系统动态变化的响应能力。 不完全微分PID控制原理 不完全微分的核心思想是…

DataOps for LLM 的数据工程技术架构实践

导读 在 LLM 蓬勃发展的今天&#xff0c;数据工程已成为支持大规模 AI 模型训练的基石。DataOps 作为数据工程的重要方法论&#xff0c;通过优化数据集成、转换和自动化运维&#xff0c;加速数据到模型的闭环流程。本文聚焦新一代数据 & AI 集成工具- Apache SeaTunnel 在…

go-zero(七) RPC服务和ETCD

go-zero 实现 RPC 服务 在实际的开发中&#xff0c;我们是通过RPC来传递数据的&#xff0c;下面我将通过一个简单的示例&#xff0c;说明如何使用go-zero框架和 Protocol Buffers 定义 RPC 服务。 一、生成 RPC项目 在这个教程中&#xff0c;我们根据user.api文件&#xff0…

【c++丨STL】list模拟实现(附源码)

&#x1f31f;&#x1f31f;作者主页&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所属专栏&#xff1a;C、STL 目录 前言 一、节点、迭代器以及函数声明 二、list功能实现 1. 节点 2. 迭代器 迭代器的默认构造 operator* operator-> 前置和-- 后置和--…

SpringBoot:不支持发行版本17超详细解决办法

一开始linux中就已经下好了JDK21&#xff0c;但是后来创建项目的时候选用了JDK23&#xff0c;导致环境错乱&#xff0c;估计大部分都是因为这个原因&#xff0c;接下来我会一步步带大家解决。 检查系统环境&#xff08;以Ubuntu为例&#xff09; 没有下载JDK的可以在官网下载…

计算机网络中的数据包传输机制详解

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 计算机网络中的数据包传输机制详解 计算机网络中的数据包传输机制详解 计算机网络中的数据包传输机制详解 引言 数据包的基本概念…

Springboot3.3.5 启动流程之 tomcat启动流程介绍

在文章 Springboot3.3.5 启动流程&#xff08;源码分析&#xff09; 中讲到 应用上下文&#xff08;applicationContext&#xff09;刷新(refresh)时使用模板方法 onRefresh 创建了 Web Server. 本文将详细介绍 ServletWebServer — Embedded tomcat 的启动流程。 首先&…

HarmonyOs鸿蒙开发实战(9)=>解析json数据,自动生成实体Bean插件-jsonFormat使用教程(铁粉福利)

1.条件:基于HarmonyOs5.0.0版本. 2.老规矩先看效果> 3.第一步 >下载jsonFormat.jar文件,使用版本1.0.5-deveco https://plugins.jetbrains.com/plugin/24930-jsonformat/versions/stable 4.第二步 > 在DevEco Stuio中安装插件 5.第三步 > 新建bean文件&#xff…