最近在整理算法面经时发现一道出现频率很高的“手撕开场题”矩形面积。题面几句话就能讲完代码也不到十行但我在模拟面试里见过太多人把它做砸。原因不是题目难而是大多数人一上来就分“相交、相离、包含、共边”四种情况去写 if分支越写越多边界越写越乱最后把自己绕晕。这道题在很多大厂的 OD 技术面中经常被拿来试水属于典型的“看着简单其实考基本功”的题目。它表面上只要求算两个矩形的覆盖总面积背后却涉及容斥原理、区间投影、边界处理和数据溢出几个层面。这篇就顺着我自己的解题习惯把这类题从读题、思路、实现到被追问的应对方式完整拆一遍。不管你是准备面试还是单纯想把计算几何的基础题吃透都能有点收获。1. 题面理解与大厂 OD 面试的考察逻辑1.1 这道题到底在问什么先还原一下面试现场你会发现的标准题面给定两个矩形每个矩形用自己的左下角坐标和右上角坐标来表示也就是矩形 A左下角 (ax1, ay1)右上角 (ax2, ay2)矩形 B左下角 (bx1, by1)右上角 (bx2, by2)要求返回这两个矩形覆盖的总面积。注意这里说的是“覆盖总面积”不是“重叠面积”。如果两个矩形有交叉那么重叠部分只能算一次所以答案是A 的面积加上 B 的面积再减去重叠部分的面积。很多人在这一步就理解偏了以为要返回公共面积。一旦目标搞错后面整个过程都会跑偏。我建议拿到题第一件事先用自己的话复述一遍题面“矩形 A 面积 矩形 B 面积 - 二者相交区域面积”。这句话就是整道题的骨架。这种输入格式也很有代表性用左下角和右上角来定义矩形而不是中心点加宽高。后者在做旋转或物理模拟时更常见前者在做轴对齐矩形相交判断时最方便因为所有边都平行于坐标轴判断关系只需要比较坐标值。1.2 为什么面试官青睐这道题大厂 OD 面试手撕环节选这道题有几个明显的好处。第一代码量小但思维密度不低。它要求你在一两分钟内想清楚“容斥”这个核心思路而不是靠背模板。第二它天然带着边界条件相离、包含、共边、坐标有负值、计算结果溢出这些都是面试官可以顺着往下追问的切入点。第三它能够区分“背过题的人”和“真的理解的人”。背过题的人可能会写但往往说不清为什么减去的重叠面积要取非负理解的人不仅能写对还能把投影法的直觉讲清楚。所以这道题表面上是一道算法题实际考的是三件事数学抽象能力、边界敏感性、代码表达是否干净。这三点恰恰是日常工程里最常用的能力面试官用它来判断一个候选人愿不愿意在动手前先想清楚。2. 核心思路拆解从“容斥原理”到“一维投影”2.1 先算各自面积再去重叠两个矩形的坐标都是轴对齐的所以各自面积可以直接用长乘宽算出来A 的面积 (ax2 - ax1) * (ay2 - ay1)B 的面积 (bx2 - bx1) * (by2 - by1)为什么要先算各自面积这其实是容斥原理最朴素的应用。两个集合的并集大小 集合 A 大小 集合 B 大小 - 交集大小。放在矩形上就是覆盖面积 面积A 面积B - 重叠面积。这个式子本身很简单但很多面试者死记硬背只记得“相加减去重叠”却不知道它成立的前提是重叠部分被加了两次。一旦面对三个矩形这种朴素的两两相加就会出现问题这也是面试官喜欢追着问“三个矩形怎么办”的原因。关于这个变形我会在后面专门展开。2.2 重叠区间的判定技巧投影法重点来了怎么算两个矩形的重叠面积我的习惯是把二维问题拆成两个一维问题。矩形 A 在 x 轴上的范围是 [ax1, ax2]矩形 B 在 x 轴上的范围是 [bx1, bx2]。这两个区间在 x 轴上的交集长度就是重叠部分的宽度。同理它们在 y 轴上的交集长度就是重叠部分的高度。重叠面积 重叠宽度 * 重叠高度。这个“投影法”是解决轴对齐矩形问题的核心直觉了解它之后很多类似题都能直接套。两个区间求交集长度有一个固定的公式重叠宽度 min(ax2, bx2) - max(ax1, bx1)不要把这个公式和直觉搞反了。区间交集的新左边界应该取两个左端点中更靠右的那个也就是 max(ax1, bx1)新右边界应该取两个右端点中更靠左的那个也就是 min(ax2, bx2)。所以是“左边界取大右边界取小”。很多人在这里会把 max 和 min 用反写成了max(ax2, bx2) - min(ax1, bx1)算出来的东西很离谱有时候甚至是负数还觉得自己“算出负的宽度代表方向相反”。这个坑我见的太多了解决办法就是记住一句话求交集永远是“右边界的最小值减去左边界的最大值”。2.3 重叠面积公式与边界情况的数学统一有了重叠宽度和重叠高度之后还不能直接相乘。如果两个矩形在 x 方向上根本没有交集比如 A 完全在 B 的左边那么min(ax2, bx2) - max(ax1, bx1)会得到一个负数。这时候重叠宽度没有意义把它当成 0 才是正确处理。所以在工程实现上有两种写法用 if 判断if overlap_width 0 and overlap_height 0才计算重叠面积用 max 截断overlap_width max(0, min(ax2, bx2) - max(ax1, bx1))这两种写法等价但第二种更干净因为它把“负数归零”这个操作内聚到变量定义里后续代码不用再思考分支。我实际编码时更喜欢第二种面试时也更容易让代码保持线性结构。这样做还能顺带覆盖所有边界情况两个矩形完全相离重叠宽或高为 0重叠面积为 0总面积就是两面积之和。一个矩形包含另一个重叠面积等于较小的那个矩形面积总面积是大矩形面积。两个矩形只共一条边重叠宽或高为 0不重复计算。两个矩形完全重合重叠面积等于矩形本身面积总面积等于单个矩形面积。关键启发是你不需要为每一种几何关系单独写一个分支一个统一的公式加一个“负数归零”的处理就能全部覆盖。这也是面试官最希望看到的——用数学表达消灭 if-else 风暴。3. 手写实现与代码详解3.1 直接可跑的 Python 版本思路理清楚以后代码就水到渠成了。我最常用的 Python 版本是这样的def compute_area(ax1, ay1, ax2, ay2, bx1, by1, bx2, by2): area_a (ax2 - ax1) * (ay2 - ay1) area_b (bx2 - bx1) * (by2 - by1) overlap_width max(0, min(ax2, bx2) - max(ax1, bx1)) overlap_height max(0, min(ay2, by2) - max(ay1, by1)) overlap_area overlap_width * overlap_height return area_a area_b - overlap_area这里最漂亮的在于max(0, ...)这个操作。它把重叠宽度和重叠高度都限制在非负区间从根本上避免了负数宽度带来的逻辑错误。整个函数没有显式分支读起来非常顺。你也可以改成 if 的写法但不是不能而是完全没有必要。如果面试官问“为什么这里用 max(0, x) 而不是 if”你可以回答这相当于把“区间不相交时重叠长度为 0”这个业务规则直接表达在类型约束里用数学函数替代分支减少心智负担。3.2 C 风格实现与溢出坑位Python 写起来爽但很多 OD 技术面是允许用 C 或者 Java 的。一旦切到 C就要额外考一个很现实的问题溢出。假设坐标的范围是 [-10^9, 10^9]两个边长相减之后是 2 * 10^9乘起来面积是 4 * 10^18这已经超过 int 的表示范围了。如果你用 int 存面积算到一半可能溢出成负数最后返回一个莫名其妙的结果。这在面试里是特别常见的“追加考察点”。所以 C 实现最好直接上long longlong long computeArea(int ax1, int ay1, int ax2, int ay2, int bx1, int by1, int bx2, int by2) { long long areaA (long long)(ax2 - ax1) * (ay2 - ay1); long long areaB (long long)(bx2 - bx1) * (by2 - by1); long long overlapW max(0, min(ax2, bx2) - max(ax1, bx1)); long long overlapH max(0, min(ay2, by2) - max(ay1, by1)); long long overlap overlapW * overlapH; return areaA areaB - overlap; }注意min(ax2, bx2) - max(ax1, bx1)这一步本身可能还是 int 范围内的差但为了安全我直接把它赋值给long long后续乘法就不会溢出。Java 版本同理用long而不是int。如果你在面试中主动写出long long并且解释一句“坐标可能很大面积相乘可能超过 int 范围”这是一个非常典型的加分细节因为这体现了工程意识而算法模板里通常不会强调这一点。3.3 测试用例设计与边界清单写完代码之后不要急着说“做完了”。面试手撕环节主动设计测试用例会让你显得非常专业。我通常会在草稿纸上列一组典型用例然后快速验算场景矩形A矩形B期望结果说明正常重叠(0,0,2,2)(1,1,3,3)7A面积4 B面积4 - 重叠1完全相离(0,0,1,1)(2,2,3,3)2无重叠简单相加完全包含(0,0,5,5)(1,1,2,2)25重叠面积等于小矩形共边(0,0,2,2)(2,0,4,2)8重叠宽度为0坐标含负(-2,-2,0,0)(-1,-1,1,1)6负坐标参与运算正常用这些用例在心里跑一遍代码有没有问题基本就清楚了。尤其是“完全包含”这个用例极容易把重叠面积算错因为你可能会拿小矩形的宽高直接相乘但正确的重叠宽度应该通过公式算结果是一样的这说明公式能退化成包含情况的正确答案。4. 面试时的沟通方式与解题框架4.1 拿到题先问清什么很多候选人拿到题就埋头写这是手撕环节的大忌。面试官给你题不只是要一个答案还要看你遇到模糊需求时的反应。矩形面积这道题至少有这几个问题值得确认输入坐标一定是左下角和右上角吗有没有可能给的是中心点坐标范围是多少会不会大到超过 int矩形是否一定面积非零有没有可能退化成线段返回值类型有没有要求比如 C 是否需要 long long这些问题看起来琐碎但每一个都直接影响实现。比如如果矩形可能退化成线段那么面积可能是 0你的代码要能处理。如果坐标范围很大你的类型就要选对。面试官问你这些问题时通常不会不耐烦反而会把你视为“谨慎的工程师”。反之什么都不问就开始写写得再快也可能被判定为“只会背题”。4.2 先讲思路再动手怎么写我的建议是遵循一个固定套路先给结论再给推导最后写代码。你可以这样说“我的思路是分三步。第一步算两个矩形的面积并求和。第二步算重叠面积做法是把 x 轴和 y 轴分别投影成一维区间用右端点最小值减去左端点最大值得到重叠宽度和高度小于 0 就归零。第三步用面积和减去重叠面积得到最终结果。”这段话控制在 30 秒以内面试官能立刻知道你有思路。之后你写代码他不需要一直盯着猜你要干嘛压力会小很多你的发挥也会更稳。写代码的时候我建议先写核心计算公式再写类型定义最后再回头处理边界。尤其是这种十行以内的小题千万别先在 if 分支里纠结半天把公式先落在代码里逻辑就立住了。4.3 额外加分项时间与空间复杂度分析代码写完以后主动报复杂度是一个好习惯。这道题的时间复杂度是 O(1)因为只做了固定次数的加减乘除和比较空间复杂度也是 O(1)只用了几个临时变量。这句话一定要说因为它标志着你具备算法性能意识。不过别只报“O(1)”就完了。可以补一句“无论坐标多大计算量都不会随规模增长因为输入只有固定的 8 个整数。”这种解释能体现你真的理解复杂度含义而不是背公式。如果面试官追一句“那如果有 N 个矩形怎么办”你就可以顺势过渡到后面的变形题讨论这是展示深度的好时机。5. 变形题与延伸矩形面积家族5.1 常见变形多个矩形覆盖总面积面试官很可能在矩形面积之后追问如果有 N 个矩形怎么求它们覆盖的总面积这时候刚才的两两容斥就不够用了因为三个矩形两两相交时三者共同覆盖的区域会被重复扣除。正确的做法有两个方向。第一个是扫描线法。按 x 坐标从左到右扫描每遇到一个矩形的左边界或右边界就更新当前在 y 轴上的活动区间集合然后算当前 x 段的覆盖高度再乘以 x 方向的宽度累加面积。复杂度在排序后是 O(N^2) 或优化到 O(N log N)取决于区间维护的数据结构。第二个是离散化 二维前缀覆盖。把所有矩形的 x 坐标和 y 坐标分别收集起来排序去重后形成网格然后逐格判断是否被至少一个矩形覆盖。这种做法简单但空间复杂度高适合矩形数量少的场景。我在面试中遇到这类追问一般先提扫描线因为它才是工程上通用的解法。但我会坦白说“如果只是两个矩形不需要这么重型的工具直接容斥就够了”。这种回答方式会让人觉得你的知识是分层的有简朴解法也知道通用解法能按场景选型。5.2 其他变体矩形相交判断、重叠面积、合并区间矩形面积这个考点还能延伸出好几个兄弟题目。判断两个矩形是否相交。这其实只需要看重叠宽度和高度是否都大于 0比面积还简单。求两个矩形的重叠面积。这就是本题的中间步骤。给一组区间求合并后的总长度。这就是把二维问题退化到一维很多人会先做这道过渡题再上矩形。求 N 个矩形的边界轮廓。这要用到扫描线加区间维护更复杂的操作一般出现在更高阶的面试轮次。这些变形都围绕同一个核心能力把几何对象拆成坐标轴上的区间再进行交集、并集、差集运算。所以如果你把矩形面积吃透等于掌握了这一整类问题的敲门砖。5.3 面试过程中被追问怎么办追问是面试里很常见的压力测试你答不上来不代表前面的代码白写了关键是别慌。比如面试官可能会问“如果两个矩形根本不相交你算出来的 overlap_width 是负数为什么最后结果还是对的”你回答因为我用 max(0, ...) 把负数截断成 0 了所以重叠面积是 0不是负数总面积就等于两个面积之和。再比如“如果矩形的坐标很大比如 10^9 量级用 int 会怎样”你回答乘法会溢出结果不确定。所以我在 C 里用了 long longPython 的 int 则没有这个问题。这些追问都没有超出这道题本身只要思路清晰基本都是送分题。最怕的是那种没有真正理解代码、只是背模板的人一旦参数变了就完全不知道怎么调。6. 踩坑实录与经验复盘6.1 我见过的三个典型错误这些年帮人 Mock 面试矩形面积这道题的经典错误我基本都看全了这里分享三个频率最高的。第一个是 max 和 min 用反。很多人把重叠宽度写成max(ax2, bx2) - min(ax1, bx1)。这会导致计算出的“重叠宽度”大得离谱因为右端点取了大的左端点取了小的相当于把两个区间并集宽度算出来了。更迷惑的是它也可能是正数所以结果看起来“好像没问题”但一对比真实答案就露馅了。第二个是只判断了宽度没判断高度。两个矩形在 x 方向上重叠但 y 方向完全分开此时 overlap_width 是正数overlap_height 是负数直接相乘会得到一个负数。有人看到负数就开始怀疑人生有人干脆用 abs 取绝对值那就错得没边了。正确做法是宽和高都必须大于 0 才算有实际重叠区域。第三个是过度分类。我见过有候选人把情况分成左上、右上、左下、右下四种重叠写了四段几乎重复的代码中间还漏了一种“完全包含”的情况。这种写法不仅冗长而且在现场高压下极易漏判。用投影法统一公式就可以把四种情况合而为一。6.2 调试小技巧把中间量打出来如果你写完之后不确定对不对最快的验证方式是在心里或者草稿纸上打印中间量。比如算完 overlap_width、overlap_height、overlap_area分别检查它们是否在合理区间。这个过程其实是在验证“网格线切出来的那种直觉”两个矩形互怼之后公共部分仍然是一个矩形它的宽高不可能比两个原矩形都宽。如果发现重叠宽度算出来比任何一个矩形的宽度还大那一定是 max/min 用反了。这个反直觉的检查特别有效因为重叠区间的长度有天然上界它不可能超过两个区间中较短的那个的长度。一旦突破这个上界代码一定有问题。我在现场写代码时也习惯把关键变量名取得有语义感比如overlap_width、overlap_height而不是w、h。表面上只是名字长一点但它能逼着你在写乘法之前先确认自己在乘什么。面试官也会觉得你的代码可读性更好。6.3 复盘这道题真正考察的是什么把矩形面积这道题做对靠的不是记住公式而是建立一种思考习惯拿到几何问题先想能不能拆到坐标轴上拿到集合问题先想容斥拿到边界条件先想数学公式能不能统一处理。这种习惯在实际工程里同样重要。做图形渲染时你要判断碰撞箱是否相交做布局引擎时要算两个组件是否重叠做地图服务时要合并多个地理围栏区域。它们背后的计算模型跟这道手撕题几乎是同一套。所以我经常对准备面试的人说不要小看这种“简单题”它恰恰是区分“背题”和“懂题”的分水岭。你能不能在两分钟内把投影法和容斥原理讲清楚比你写出漂亮代码更能反映真实水平。如果下次你在面试里碰到它记得先稳住说清思路再落代码最后用边界用例自测。这套流程跑下来你的答案质量一定不会差。