在问 · 算法题解

836. 矩形重叠

简单数学投影区间求交力扣原题 ↗

题目描述

每个矩形用数组 [x1, y1, x2, y2] 表示,(x1, y1) 是左下角坐标,(x2, y2) 是右上角坐标。矩形的边都与坐标轴平行。

两个矩形的公共部分面积大于 0 时才算重叠。只有边或顶点接触时,公共面积为 0,不算重叠。

输入两个矩形 rec1 和 rec2,重叠返回 true,否则返回 false。

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

解释:两者共有边长为 1 的正方形区域 [1,1] 到 [2,2]。

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

解释:两个矩形只共用 x = 1 这条边,面积为 0。

示例 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 都是面积大于 0 的合法矩形。

解题思路:投影区间求交

把二维问题拆成两个一维问题:两个矩形重叠,当且仅当它们在 x 轴上的投影区间重叠,且在 y 轴上的投影区间也重叠。区间 [a1, a2] 和 [b1, b2] 的交集长度为正,当且仅当 min(a2, b2) > max(a1, b1)。

为什么正确

交集矩形的左边界是两个左边界的较大者,右边界是两个右边界的较小者;宽为正等价于右 > 左,y 方向同理。

复杂度分析

时间 O(1),空间 O(1)。

易错点

比较必须用严格大于 >:用 >= 会把只共边或共角的情况误判为重叠。另外不要试图枚举“谁的角落在谁里面”,十字形交叉时没有任何角在对方内部。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def isRectangleOverlap(self, rec1: List[int], rec2: List[int]) -> bool:
        x_overlap = min(rec1[2], rec2[2]) > max(rec1[0], rec2[0])
        y_overlap = min(rec1[3], rec2[3]) > max(rec1[1], rec2[1])
        return x_overlap and y_overlap

载入编辑器,自己跑一遍 →

其他解法

投影法把二维问题拆成两个一维区间求交,边界自然正确;位置法从反面列举四种分离情况,直观但要额外注意退化矩形。

解法 2:反向判断不重叠的位置 时间 O(1),空间 O(1)

两个正面积矩形不重叠,当且仅当一个完全在另一个的左边、右边、下边或上边(贴边也算不重叠)。先排除宽或高为 0 的退化矩形,再把这四种情况取或后取反。

从“什么时候肯定不重叠”反过来想,条件很直观。但必须单独处理面积为 0 的矩形,否则一条线段穿过另一个矩形时会误判为重叠;投影法用严格不等号自动处理了这种情况。

class Solution:
    def isRectangleOverlap(self, rec1: List[int], rec2: List[int]) -> bool:
        if rec1[0] == rec1[2] or rec1[1] == rec1[3] or rec2[0] == rec2[2] or rec2[1] == rec2[3]:
            return False
        return not (rec1[2] <= rec2[0] or rec2[2] <= rec1[0] or rec1[3] <= rec2[1] or rec2[3] <= rec1[1])

数学 专题的其他题目

查看 数学 全部题目 →