资讯动态

矩形面积覆盖问题:容斥原理与重叠边界处理全解析(含OD面试手撕思路)

发布时间:2026/10/17 23:40:43 来源:尧图企业网站定制
这道“矩形面积”在OD手撕题里出场率高得离谱我前前后后见过不下十次也是不少候选人在白板上栽跟头最多的一道“简单题”。题目本身不绕核心就是给你两个矩形让你算出它们覆盖的总面积但正因为看起来太基础反而把很多人的思维漏洞暴露得干干净净要么坐标抽歪了要么重叠边界处理漏掉要么交完代码连一组自测用例都想不出来。这篇就按我实际复盘OD面试手撕环节的思路把这道题从公式推导、代码实现到面试官追问完整拆一遍。1. 题目考察的本质与出题逻辑1.1 原题描述与输入约定这道题的标准描述一般长这样给定两个矩形的左下角坐标和右上角坐标分别是(ax1, ay1)与(ax2, ay2)以及(bx1, by1)与(bx2, by2)坐标均为整数两个矩形可能重叠也可能完全不重叠要求返回它们覆盖的总面积。这个描述里有一个信息容易被忽略但非常关键矩形的边分别平行于x轴和y轴也就是说这是个“轴对齐矩形”。面试中默认都是这种情况如果面试官没说“矩形可能旋转”你就别自己吓自己。坐标系也遵循数学惯例x轴向右为正y轴向上为正左下角坐标一定小于右上角坐标所以ax1 ax2、ay1 ay2这类不等关系天然成立不用额外校验。输入形式在不同公司里略有差异有人用两个数组比如rec1 [ax1, ay1, ax2, ay2]rec2 [bx1, by1, bx2, by2]也有人用六个参数比如computeArea(ax1, ay1, ax2, ay2, bx1, by1, bx2, by2)。甚至有些题会把矩形描述成“左上角坐标宽高”这种变体我在后文单独讲。但不管外壳怎么改内部计算的数学内核完全一样。1.2 表面是数学题实际是边界处理题很多候选人第一反应是“这不就是两个面积相加再减掉重叠面积嘛”思路没错公式也就一行的事。但手撕环节的真正难点从来不是这个公式多么深奥而是你能不能把“重叠面积”算得滴水不漏。举例说明假设第一个矩形的右上角x坐标是5第二个矩形的左下角x坐标是6那它们在x轴方向上压根没有交集重叠宽度应该视为0。如果你直接从min(ax2, bx2) - max(ax1, bx1)去算得到的是负数拿这个负数去乘高度重叠面积就变成了一个负数最终总面积会被错误地减小。这就是整道题最核心的坑位必须把负的差值截断为0。用代码表达就是Math.max(0, min(ax2, bx2) - max(ax1, bx1))。这个max(0, ...)的操作本质上是在处理“投影不相交”的情况。两个矩形的重叠区域可以拆成x轴方向上的重叠长度与y轴方向上的重叠长度的乘积。两个方向都必须严格大于0才存在真正的面积重叠只要有一个方向上的重叠值为0总面积就是两个矩形各自面积之和不用做任何减操作。很多人在嘴里能把这个逻辑讲流畅一落到代码里就忘记包那层max这是最典型的手脑不一致。1.3 面试官出这道题的真实意图当作热身题时面试官想确认的事情有三层。第一层是数学抽象能力你能不能把一个几何问题转化为代数表达式而不是在脑海里画一堆示意图第二层是边界条件意识你知不知道x方向不重叠、y方向不重叠、点接触、边重合这些情况要怎么处理第三层是代码风格你写出来的代码是不是能让别人一眼看懂变量命名、注释、格式化是否职业。这道题还有一层隐性作用面试官可以通过它对候选人进行“压力分级”。如果你写得很顺追问环节就会立刻升级到多矩形并集面积、不规则多边形这类进阶问题如果你写得很挣扎面试官在剩余时间里会降低难度用更基础的题目来判断你的下限。换句话说这道题不仅是能力检测也是面试节奏调节器。所以别因为它简单就掉以轻心你在这个题上的表现直接决定了整轮面试后半场的难度曲线。2. 把推导细节彻底吃透的解题框架2.1 容斥原理与总面积公式计算两个矩形的覆盖总面积本质上是一个容斥问题。容斥原理说两个集合的并集大小等于两个集合分别的大小之和减去交集的大小。对应到这道题总面积 矩形A的面积 矩形B的面积 - 重叠区域的面积。矩形A的面积就是用右上角x坐标减左下角x坐标再乘上右上角y坐标减左下角y坐标也就是(ax2 - ax1) * (ay2 - ay1)。矩形B同理。这两部分几乎送分只要注意别把坐标写反就行。真正需要多花心思的是“重叠区域的面积”这一项。这里有一个隐藏前提重叠区域本身必然是一个矩形或者一个退化矩形。为什么因为两个轴对齐矩形的交集在x轴上是一个区间在y轴上也是一个区间两个区间的笛卡尔积自然还是一个轴对齐矩形。即便两个矩形完全不相交交集区间为空也可以理解成面积为0的退化矩形。这个性质是整道题的核心也是后面推导重叠面积公式的基础。2.2 重叠面积的投影数学内核重叠面积的计算拆开来看就是两个字投影。把矩形A和矩形B分别投影到x轴上得到两个区间[ax1, ax2]与[bx1, bx2]它们的重叠区间为[max(ax1, bx1), min(ax2, bx2)]区间长度是min(ax2, bx2) - max(ax1, bx1)。但请注意这个长度可能是负数说明两个区间在x轴上完全没有重叠。把同样的逻辑套到y轴上得到重叠高度min(ay2, by2) - max(ay1, by1)同样可能是负数。两个方向的重叠长度都是非负的时候乘起来才是真正的重叠面积。所以正确的重叠面积公式应该写作 overlapWidth Math.max(0, Math.min(ax2, bx2) - Math.max(ax1, bx1)) overlapHeight Math.max(0, Math.min(ay2, by2) - Math.max(ay1, by1)) overlap overlapWidth * overlapHeight这个公式美就美在它把“判断是否重叠”和“计算重叠大小”合并成了一个表达式。宽度为0时高度那一项即使算出来是正的乘积也是0反过来也是这个道理。正因如此你可以完全不写if分支用纯数学方式一步到位代码简洁且不易遗漏分支。2.3 一行代码与分支判断的取舍关于实现方式候选人之间经常分成两派。一派喜欢先判断两个矩形是否相交不相交就直接返回areaA areaB相交再算重叠另一派喜欢统一用max(0, ...)公式不做任何提前判断直接返回。这两种写法各有场景我个人更建议在面试中采用后者原因有三个第一提前判断相交本身就是额外的工作量你得多写一组min/max的比较条件而且容易在判断逻辑中出错比如漏掉两个矩形边完全重合但不相交的退化场景。第二统一公式的可读性并不差只要变量命名清晰面试官能一眼看出你用了投影重叠的思路。第三统一公式本质上已经内含了“不相交则重叠面积为0”的处理不会出现分支遗漏。但这不代表分支判断一无是处。如果你的面试官额外追问“这两个矩形到底有没有重叠重叠面积是多少”那就走分支判断的路线分别返回结果这样反而更契合题意。面试时的原则是听清问题再动手不要抱着一个模板写遍所有变体。3. 手写实现从思路到提交的全过程3.1 动笔前的三分钟沟通术手撕题最容易犯的错误不是代码写不出来而是题目还没看完就开始写。我的习惯是拿到题目后先不碰笔用一到三分钟跟面试官对齐三件事输入坐标是左下角和右上角还是左上角和右下角两个矩形是否一定轴对齐坐标范围是什么是否存在溢出风险。别小看这三分钟。现实面试中很多候选人因为没确认坐标系把左上角坐标当成左下角用写出一个计算结果是负数还很自洽的答案。对齐之后我会口头把思路讲一遍“我打算先算两个矩形的面积再按容斥原理减去重叠面积重叠面积我用投影区间来算x方向和y方向各自取max(0, 重叠长度)。”这段话不超过三十秒但能让面试官立刻知道你走对了方向同时万一理解有偏差面试官也会在这个时间点出手纠正而不是等你写完几十行代码才发现。3.2 可读性优先的Java实现在面试场景中Java永远是最稳妥的手撕语言之一因为它的类型声明天然要求你想清楚每个变量的含义。下面给出我常用的实现版本class Solution { public int computeArea(int ax1, int ay1, int ax2, int ay2, int bx1, int by1, int bx2, int by2) { long areaA (long)(ax2 - ax1) * (ay2 - ay1); long areaB (long)(bx2 - bx1) * (by2 - by1); long overlapWidth Math.max(0L, Math.min(ax2, bx2) - Math.max(ax1, bx1)); long overlapHeight Math.max(0L, Math.min(ay2, by2) - Math.max(ay1, by1)); long overlapArea overlapWidth * overlapHeight; return (int)(areaA areaB - overlapArea); } }这里我做了两个刻意设计。一个是把中间变量全部用long声明防止相乘过程溢出另一个是max(0L, ...)传入长整型字面量保证整个表达式不发生类型收缩。虽然这道题的官方案例用int通常不会爆但手撕环节展示出溢出意识在面试官心中的加分效果立竿见影。变量命名上我没有偷懒用a1、a2这种极简命名而是保留了原题坐标语义。手撕代码不是提交OJ面试官要现场读你的代码清晰的命名比代码短小精悍重要得多。注释不需要写太多一两行点明“重叠区域的宽高先截断为0”就足够注释的价值在于表达你的思考过程而不是解释代码在做什么。3.3 追求极简的Python实现如果面试允许你选Python那可以写得更紧凑一些。Python的写法在思路上与Java完全一致只是语法更简洁def compute_area(ax1: int, ay1: int, ax2: int, ay2: int, bx1: int, by1: int, bx2: int, by2: int) - int: area_a (ax2 - ax1) * (ay2 - ay1) area_b (bx2 - bx1) * (by2 - by1) width max(0, min(ax2, bx2) - max(ax1, bx1)) height max(0, min(ay2, by2) - max(ay1, by1)) return area_a area_b - width * height注意一个Python细节这段代码里的坐标如果来自力扣标准约束即绝对值不超过10^4那么即使相乘也不会溢出因为Python的整数是任意精度的。但你在面试中最好口头提一句“如果坐标范围非常大Python不担心溢出但其他语言需要转long”既展示思考深度又说明你熟悉不同语言的差异。3.4 边界用例的自测清单写完代码之后面试官通常会让你“自己测一下”。这时候如果你只丢一个常规用例等于放弃了这个展示机会。我每次都会在现场快速过一遍这样的用例组合完全不相交例如第一个矩形在(-2, -2, -1, -1)第二个矩形在(1, 1, 2, 2)。此时重叠宽高均为0结果是两个面积相加。边恰好重合但无面积重叠例如(0, 0, 1, 1)和(1, 0, 2, 1)。x方向投影重叠长度为min(1, 2) - max(0, 1) 0重叠面积为0。一个矩形完全包含另一个例如(0, 0, 5, 5)包含(1, 1, 2, 2)。重叠面积等于小矩形的面积总面积等于大矩形面积。负坐标参与的重叠例如(-3, -3, 0, 0)与(-2, -2, 1, 1)。负坐标最容易暴露出坐标轴方向搞反的问题。这些用例的价值不在于覆盖所有可能而在于覆盖了“不相交、边界接触、完全包含、负坐标”四个最容易出问题的维度。你能主动列出这组用例面试官就会认定你的边界意识在职级线上是合格的。4. 候选人最常见的翻车点实录4.1 min/max写反导致面积为负这是我在评估候选人代码时看到最多的一类错误。重叠宽度的公式里一定是min(ax2, bx2)减max(ax1, bx1)即“较小的右边界减去较大的左边界”。一旦写成max(ax2, bx2) - min(ax1, bx1)那算出来的就不是重叠区间而是两个矩形x跨度合并后的总长度重叠面积彻底失去意义。如何避免我常用的一个心法是“左边界取大右边界取小”。两个区间要重叠必定是从比较大的左端点开始到比较小的右端点结束。这个心法不仅适用于矩形重叠也适用于区间合并、滑动窗口碰撞检测是一劳永逸的思维习惯。4.2 忽略max(0, ...)导致负面积另一类高频错误是公式里漏掉max(0, ...)直接拿min(ax2, bx2) - max(ax1, bx1)去乘高度。这样一来当两个矩形在x方向完全错开时重叠宽度为负值负数乘以正数的高度得到负数重叠面积最终结果比真实总面积小。这种错误很隐蔽因为只要测试数据选的是相交矩形答案依然正确只有碰到不相交用例才暴雷。防这种问题没有捷径就是形成肌肉记忆。只要写到“重叠”两个字马上条件反射般补上max(0, ...)。如果你对自己不放心还可以把两个矩形改成负数坐标重新推导一遍亲手算一次负数重叠到底怎么回事之后就再也不会忘了。4.3 零面积与负坐标的隐藏陷阱有些变体题目会给出“左下角与右上角坐标相同”的矩形也就是宽或高为0的退化矩形。遇到这类输入面积公式依然成立重叠面积为0结果不会被污染。但如果你提前写了if (!isOverlap) return areaA areaB这样的分支又没有考虑宽或高为0时应当视为不重叠就可能判断失误。负坐标陷阱则更偏向于坐标系理解问题。有些候选人潜意识里认为“负坐标区域的矩形一定不会和正坐标区域重叠”直接跳过了相交计算导致答案出错。矩形重叠与否只取决于投影区间的位置关系与坐标值的正负无关。拿到负坐标用例时最稳妥的做法是把坐标画在草稿纸上先直观确认重叠区域长什么样再落到公式。4.4 溢出意识不足原题坐标范围通常限制在[-10^4, 10^4]之间矩形面积最大约为4 * 10^8int完全装得下。但实际面试中面试官可能会临时改口“如果我放宽坐标范围到10^9呢”这时候两个面积都可能超过int上限直接相乘或相加就会溢出返回负数。处理办法很简单就像我前面给出的代码那样统一提升为long。如果你所在的语言没有long类型则要考虑是否使用BigInteger或先做数学变形避免溢出。这里顺便说一句哪怕不放大坐标范围我也建议在面试中主动把这个考虑带出来。一个候选人如果连“会不会溢出”这种问题都主动想清楚了说明他平时写代码就养成了防御性编程习惯这一点的权重远高于题目本身的AC状态。5. 面试官追问环节的加分回答5.1 追问1两个矩形变成N个怎么办这道题最常见的追问方向是从两个矩形扩展到N个矩形。如果你只有20秒思考时间可以这样回答两矩形的容斥公式在N矩形场景下会指数爆炸因为交集项的数量急剧增加所以必须换思路用扫描线算法。扫描线算法的核心是选择一个轴做扫描方向比如在x方向上从最左到最右扫遇到矩形的左边界就在当前覆盖集合中加入该矩形的y区间遇到右边界就移除。在任意两个相邻的事件点之间当前活动矩形的x跨度是固定的我们只需要维护这组y区间在数轴上的合并总长度两者相乘就是这段区间对总面积的贡献累加所有区间即可。如果面试官追问复杂度你还要能说出活动区间维护用线段树或有序集合一般能将单次插入删除的复杂度控制在O(logN)整体复杂度O(NlogN)。这是力扣850题的完整解法能在现场把这个思路说清楚已经超过绝大多数同场候选人。如果面试时间充足面试官可能还会让你手写一个简化版本那就按“离散化所有矩形的y坐标构建线段树覆盖计数”的思路来写。5.2 追问2矩形由中心点和半宽表示怎么处理变体题目有时候不给你左下角和右上角而是给中心点(cx, cy)、半宽w和半高h。处理方式是在这一层做一个坐标转换将其先转化为左下角与右上角left cx - wright cx wbottom cy - htop cy h后续计算无缝复用原公式。注意这里有另一个易错点如果题目给的是“中心点和宽高”那宽高是完整宽度和高度半宽是宽的一半如果题目给的是“中心点和半宽”那已经是除以2之后的值不要再除以一次。面试时说清楚这一步转换逻辑能让面试官觉得你不仅会套公式还能做输入适配。其实面试中的这类变体考的就是“给你一个不完全兼容的输入你能不能快速适配到已有的解题框架里”这跟工作中接手一个老模块做扩展是同一类能力。5.3 追问3坐标维度变大怎么做把矩形放到三维空间比如两个长方体求它们覆盖的总体积公式依然成立总体积 长方体A体积 长方体B体积 - 重叠体积。重叠体积的计算就是把x、y、z三个方向的重叠长度各自用max(0, ...)钳制再相乘。这个追问的妙处在于它根本不需要你重新学任何算法只要你能把二维思考平滑地推广到三维面试官就会认定你对几何模型有抽象迁移能力。但我也提醒一句别只顾着高兴。面试官在这个追问里往往还潜伏着一个数字陷阱三维情况下如果坐标范围很大体积可能一下膨胀到极大的量级类型选择上必须更加谨慎。6. 从这道题反推OD面试的手撕评价标准6.1 代码之外的五项隐性考察在多次复盘这道题之后我梳理出手撕环节真正打分的关键点它们不完全体现在代码正确性上。第一个是思路表达能力你能不能在被要求动手前把解题路径在口头上讲清楚第二个是边界敏感性你愿不愿意主动构造异常用例而不是等面试官来问第三个是代码组织能力命名、缩进、函数拆分是否专业第四个是防御性思维对溢出、极端输入是否有自己的预判第五个是沟通意识遇到不确定的输入约定时是选择猜测还是选择快速确认。这五项能力在矩形面积这道题里都能有对应的观察点也是面试官评分表的常见维度。很多人AC完题目自我感觉良好结果却收到拒信问题往往不是代码本身而是上面某几个软性维度掉了链子。比如题意没确认就猛写虽然方向碰巧正确但面试官没有看到你验证输入的过程就会对你处理模糊需求的方式存疑。6.2 我整理的手撕题复习路径刷题刷到最后真正见效的不是题量而是归类。以矩形面积这道题作为出发点我建议你把相关题放进同一个“几何容斥”文件夹包括矩形面积、矩形重叠、多个矩形面积并集再延伸到网格中的图形面积计算。这个类别练熟之后你会发现它们共用的都是“投影区间 容斥”的思维模型。另一个重要建议是不要只在编译器里敲题尽可能模拟一次白板手写。因为面试现场没有代码补全、没有运行提示、没有lint报错所有错误都要靠眼睛和脑子发现。我自己的练习方式是拿一张A4纸把矩形面积的三个方向变体各写一遍写完后对着纸检查变量名、类型、边界条件看看能不能在完全不运行的情况下发现逻辑漏洞。这个能力练起来枯燥但在实战场上最为保命。最后分享一个我复盘无数候选人后得出的结论这道题的最优解并不是代码最短的那个版本而是代码最容易让人看懂、同时每一步都有明确意图的版本。手撕环节真正的对手不是题而是你在有限时间内能不能让一个陌生工程师高效地相信你的工程素养。把这个原则想明白矩形面积只会是你整套面试流程里的开胃菜绝不会成为绊脚石。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑