精进Leetcode每日一题-1116

这是我参与11月更文挑战的第14天,活动详情查看:2021最后一次更文挑战

目标:拼搏30天,拿到11月的Leetcode 月度勋章。今天是第 16 天。

题目:完美矩阵

给你一个数组 rectangles ,其中 rectangles[i] = [xi, yi, ai, bi] 表示一个坐标轴平行的矩形。这个矩形的左下顶点是 (xi, yi) ,右上顶点是 (ai, bi) 。 如果所有矩形一起精确覆盖了某个矩形区域,则返回 true ;否则,返回 false 。

分析:

这道题目是一道hard题,但是最重要的不是解题思路,而是这道题目要处理的步骤太多了,稍有不慎就导致无法正常AC。我也是提交了4遍左右才成功通过所有的测试用例。

题目要求:所有矩形一起 精确 覆盖了某个矩形区域,可以得出以下几个结论:

  • 不能出现空缺;
  • 不能出现重叠;
  • 所有小矩形合在一起是大矩形;

通过以上结论,我们可知,所有小矩形的面积之和等于大矩形的面积,所以,我们可以先找出大矩形的左下角和右上角,然后求出所有小矩形的面积之和与大矩形的面积比较,如果不相等,可以直接返回 false。

我们考虑拼出完美矩形的情况:

  • 左下角、左上角、右下角、右上角的顶点一定是所有矩阵的最外圈
  • 它们的面积和一定和完美矩阵的面积相等

任意不是这四个顶点的小矩阵的点,一定会出现两次或四次(如果出现四次以上,一定有超过四个矩阵以这个点为顶点,那么必然有重叠;如果出现奇数次,那么必然没有被完整覆盖)【这个的判断可以去掉面积相等,但是是内部重叠的情况】

解答:

class Solution {
    public boolean isRectangleCover(int[][] rectangles) {
        // 计算每个小矩形面积是否等于大矩形面积
        // 看每个顶点出现的次数,如果最后出现一次的顶点不是四个,则说明不符合完美矩形
        int area = 0;
        Set<Integer> set = new HashSet<>();
        // 记录大矩形的左下角和右上角
        int a1 = Integer.MAX_VALUE, b1 = Integer.MAX_VALUE;
        int a2 = Integer.MIN_VALUE, b2 = Integer.MIN_VALUE;
        for (int[] rec : rectangles) {
            // 小矩形的坐标
            int x1 = rec[0];
            int y1 = rec[1];
            int x2 = rec[2];
            int y2 = rec[3];
            // 计算左下角
            if (x1 < a1 || y1 < b1) {
                a1 = x1;
                b1 = y1;
            }
            // 计算右上角
            if (x2 > a2 || y2 > b2) {
                a2 = x2;
                b2 = y2;
            }
            // 计算面积
            area += (x2 - x1) * (y2 - y1);
            // 记录每个顶点出现的次数
            record(set, x1, y1);
            record(set, x1, y2);
            record(set, x2, y1);
            record(set, x2, y2);
        }
        // 通过左下角和右上角坐标可以算出总面积
        int totalArea = (a2 - a1) * (b2 - b1);
        // 如果两个面积不相等,直接返回false
        if (area != totalArea) return false;
        // 四个为1的顶点正好是大矩形的四个顶点
        return set.size() == 4 && set.contains(key(a1, b1)) && set.contains(key(a1, b2)) && set.contains(key(a2, b1)) && set.contains(key(a2, b2));
    }’
    private void record(Set<Integer> set, int x, int y) {
        // 记录顶点出现的次数,如果一个顶点出现偶数次,则移除
        int key = key(x, y);
        if (set.contains(key)) {
            set.remove(key);
        } else {
            set.add(key);
        }
    }
    private int key(int x, int y) {
        // 二维坐标转一维,方便比较
        // 100000007是随便取的一个大质数
        // 这里即使溢出了也没什么问题
        return x * 100000007 + y;
    }
}

复制代码

复杂度分析:

  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

提交排名

image.png

おすすめ

転載: juejin.im/post/7031192797621256223