[LeetCode] Perfect Rectangle 完美矩形
Given N axis-aligned rectangles where N > 0, determine if they all together form an exact cover of a rectangular region.
Each rectangle is represented as a bottom-left point and a top-right point. For example, a unit square is represented as [1,1,2,2]. (coordinate of bottom-left point is (1, 1) and top-right point is (2, 2)).

Example 1:
rectangles = [
[1,1,3,3],
[3,1,4,2],
[3,2,4,4],
[1,3,2,4],
[2,3,3,4]
] Return true. All 5 rectangles together form an exact cover of a rectangular region.

Example 2:
rectangles = [
[1,1,2,3],
[1,3,2,4],
[3,1,4,2],
[3,2,4,4]
] Return false. Because there is a gap between the two rectangular regions.

Example 3:
rectangles = [
[1,1,3,3],
[3,1,4,2],
[1,3,2,4],
[3,2,4,4]
] Return false. Because there is a gap in the top center.

Example 4:
rectangles = [
[1,1,3,3],
[3,1,4,2],
[1,3,2,4],
[2,2,4,4]
] Return false. Because two of the rectangles overlap with each other.
这道题是LeetCode第二周编程比赛的压轴题目,然而我并没有做出来,我想了两种方法都无法通过OJ的大数据集合,第一种方法是对于每一个矩形,我将其拆分为多个面积为1的单位矩形,然后以其左下方的点为标记,用一个哈希表建立每一个单位矩形和遍历到的矩形的映射,因为每个单位矩形只能属于一个矩形,否则就会有重叠,我感觉这种思路应该没错,但是由于把每一个遍历到的矩形拆分为单位矩形再建立映射很费时间,尤其是当矩形很大的时候,TLE就很正常了,后来我试的第二种方法是对于遍历到的每个矩形都和其他所有矩形检测一遍是否重叠,这种方法也是毫无悬念的TLE。
博主能力有限,只能去论坛中找各位大神的解法,发现下面两种方法比较fancy,也比较好理解。首先来看第一种方法,这种方法的设计思路很巧妙,利用了mask,也就是位操作Bit Manipulation的一些技巧,下面这张图来自这个帖子:

所有的矩形的四个顶点只会有下面蓝,绿,红三种情况,其中蓝表示该顶点周围没有其他矩形,T型的绿点表示两个矩形并排相邻,红点表示四个矩形相邻,那么在一个完美矩形中,蓝色的点只能有四个,这是个很重要的判断条件。我们再来看矩形的四个顶点,我们按照左下,左上,右上,右下的顺序来给顶点标号为1,2,4,8,为啥不是1,2,3,4呢,我们注意它们的二进制1(0001),2(0010),4(0100),8(1000),这样便于我们与和或的操作,我们还需要知道的一个判定条件是,当一个点是某一个矩形的左下顶点时,这个点就不能是其他矩形的左下顶点了,这个条件对于这四种顶点都要成立,那么对于每一个点,如果它是某个矩形的四个顶点之一,我们记录下来,如果在别的矩形中它又是相同的顶点,那么直接返回false即可,这样就体现了我们标记为1,2,4,8的好处,我们可以按位检查1。如果每个点的属性没有冲突,那么我们来验证每个点的mask是否合理,通过上面的分析,我们知道每个点只能是蓝,绿,红三种情况的一种,其中蓝的情况是mask的四位中只有一个1,分别就是1(0001),2(0010),4(0100),8(1000),而且蓝点只能有四个;那么对于T型的绿点,mask的四位中有两个1,那么就有六种情况,分别是12(1100), 10(1010), 9(1001), 6(0110), 5(0101), 3(0011);而对于红点,mask的四位都是1,只有一种情况15(1111),那么我们可以通过直接找mask是1,2,4,8的个数,也可以间接通过找不是绿点和红点的个数,看是否是四个。最后一个判定条件是每个矩形面积累加和要等于最后的大矩形的面积,那么大矩形的面积我们通过计算最小左下点和最大右上点来计算出来即可, 参见代码如下:
解法一:
class Solution {
public:
bool isRectangleCover(vector<vector<int>>& rectangles) {
unordered_map<string, int> m;
int min_x = INT_MAX, min_y = INT_MAX, max_x = INT_MIN, max_y = INT_MIN, area = , cnt = ;
for (auto rect : rectangles) {
min_x = min(min_x, rect[]);
min_y = min(min_y, rect[]);
max_x = max(max_x, rect[]);
max_y = max(max_y, rect[]);
area += (rect[] - rect[]) * (rect[] - rect[]);
if (!isValid(m, to_string(rect[]) + "_" + to_string(rect[]), )) return false; // bottom-left
if (!isValid(m, to_string(rect[]) + "_" + to_string(rect[]), )) return false; // top-left
if (!isValid(m, to_string(rect[]) + "_" + to_string(rect[]), )) return false; // top-right
if (!isValid(m, to_string(rect[]) + "_" + to_string(rect[]), )) return false; // bottom-right
}
for (auto it = m.begin(); it != m.end(); ++it) {
int t = it->second;
if (t != && t != && t != && t != && t != && t != && t!= ) {
++cnt;
}
}
return cnt == && area == (max_x - min_x) * (max_y - min_y);
}
bool isValid(unordered_map<string, int>& m, string corner, int type) {
int& val = m[corner];
if (val & type) return false;
val |= type;
return true;
}
};
下面这种方法也相当的巧妙, 提出这种算法的大神细心的发现了每种点的规律,每个绿点其实都是两个顶点的重合,每个红点都是四个顶点的重合,而每个蓝点只有一个顶点,有了这条神奇的性质就不用再去判断“每个点最多只能是一个矩形的左下,左上,右上,或右下顶点”这条性质了,我们直接用一个set,对于遍历到的任意一个顶点,如果set中已经存在了,则删去这个点,如果没有就加上,这样最后会把绿点和红点都滤去,剩下的都是蓝点,我们只要看蓝点的个数是否为四个,再加上检测每个矩形面积累加和要等于最后的大矩形的面积即可,参见代码如下:
解法二:
class Solution {
public:
bool isRectangleCover(vector<vector<int>>& rectangles) {
unordered_set<string> st;
int min_x = INT_MAX, min_y = INT_MAX, max_x = INT_MIN, max_y = INT_MIN, area = ;
for (auto rect : rectangles) {
min_x = min(min_x, rect[]);
min_y = min(min_y, rect[]);
max_x = max(max_x, rect[]);
max_y = max(max_y, rect[]);
area += (rect[] - rect[]) * (rect[] - rect[]);
string s1 = to_string(rect[]) + "_" + to_string(rect[]); // bottom-left
string s2 = to_string(rect[]) + "_" + to_string(rect[]); // top-left
string s3 = to_string(rect[]) + "_" + to_string(rect[]); // top-right
string s4 = to_string(rect[]) + "_" + to_string(rect[]); // bottom-right
if (st.count(s1)) st.erase(s1);
else st.insert(s1);
if (st.count(s2)) st.erase(s2);
else st.insert(s2);
if (st.count(s3)) st.erase(s3);
else st.insert(s3);
if (st.count(s4)) st.erase(s4);
else st.insert(s4);
}
string t1 = to_string(min_x) + "_" + to_string(min_y);
string t2 = to_string(min_x) + "_" + to_string(max_y);
string t3 = to_string(max_x) + "_" + to_string(max_y);
string t4 = to_string(max_x) + "_" + to_string(min_y);
if (!st.count(t1) || !st.count(t2) || !st.count(t3) || !st.count(t4) || st.size() != ) return false;
return area == (max_x - min_x) * (max_y - min_y);
}
};
参考资料:
https://discuss.leetcode.com/topic/56052/really-easy-understanding-solution-o-n-java
https://discuss.leetcode.com/topic/55997/short-java-solution-with-explanation-updated/2
https://discuss.leetcode.com/topic/55923/o-n-solution-by-counting-corners-with-detailed-explaination
LeetCode All in One 题目讲解汇总(持续更新中...)
[LeetCode] Perfect Rectangle 完美矩形的更多相关文章
- 391 Perfect Rectangle 完美矩形
有 N 个与坐标轴对齐的矩形, 其中 N > 0, 判断它们是否能精确地覆盖一个矩形区域.每个矩形用左下角的点和右上角的点的坐标来表示.例如, 一个单位正方形可以表示为 [1,1,2,2]. ( ...
- Perfect Rectangle(完美矩形)
我们有 N 个与坐标轴对齐的矩形, 其中 N > 0, 判断它们是否能精确地覆盖一个矩形区域. 每个矩形用左下角的点和右上角的点的坐标来表示.例如, 一个单位正方形可以表示为 [1,1,2,2] ...
- [LeetCode] Maximal Rectangle 最大矩形
Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing all ones and ...
- Leetcode: Perfect Rectangle
Given N axis-aligned rectangles where N > 0, determine if they all together form an exact cover o ...
- [LeetCode] Perfect Number 完美数字
We define the Perfect Number is a positive integer that is equal to the sum of all its positive divi ...
- [LeetCode] 223. Rectangle Area 矩形面积
Find the total area covered by two rectilinearrectangles in a 2D plane. Each rectangle is defined by ...
- [LeetCode]223. Rectangle Area矩形面积
/* 像是一道数据分析题 思路就是两个矩形面积之和减去叠加面积之和 */ public int computeArea(int A, int B, int C, int D, int E, int F ...
- Leetcode 391.完美矩形
完美矩形 我们有 N 个与坐标轴对齐的矩形, 其中 N > 0, 判断它们是否能精确地覆盖一个矩形区域. 每个矩形用左下角的点和右上角的点的坐标来表示.例如, 一个单位正方形可以表示为 [1,1 ...
- Java实现 LeetCode 391 完美矩形
391. 完美矩形 我们有 N 个与坐标轴对齐的矩形, 其中 N > 0, 判断它们是否能精确地覆盖一个矩形区域. 每个矩形用左下角的点和右上角的点的坐标来表示.例如, 一个单位正方形可以表示为 ...
随机推荐
- 【Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之缓存融合技术和主要后台进程(四)
缓存融合技术和主要后台进程(四) 概述:写下本文档的初衷和动力,来源于上篇的<oracle基本操作手册>.oracle基本操作手册是作者研一假期对oracle基础知识学习的汇总.然后形成体 ...
- linux网络设备驱动程序
4.linux网络设备驱动程序体系结构 -------------------------------------- | 数据包发送 | 数据包接收 | ----->网络协议接口层 | dev_ ...
- ASP.NET Core 中文文档 第三章 原理(13)管理应用程序状态
原文:Managing Application State 作者:Steve Smith 翻译:姚阿勇(Dr.Yao) 校对:高嵩 在 ASP.NET Core 中,有多种途径可以对应用程序的状态进行 ...
- [原创]django+ldap实现单点登录(装饰器和缓存)
前言 参考本系列之前的文章,我们已经搭建了ldap并且可以通过django来操作ldap了,剩下的就是下游系统的接入了,现在的应用场景,我是分了2个层次,第一层次是统一认证,保证各个系统通过ldap来 ...
- C# 条件编译
本文导读: C#的预处理器指令从来不会转化为可执行代码的命令,但是会影响编译过程的各个方面,常用的预处理器指令有#define.#undef.#if,#elif,#else和#endif等等,下面介绍 ...
- c#面向对象基础技能——学习笔记(三)基于OOP思想研究对象的【方法】
实例方法:(解决问题的步骤)完成某功能的各种语句的组合 编写方法要考虑的内容: 1.通过项目需求,确定各方法的任务.功能: 2.方法的可访问性(默认是private):(字段private 属性int ...
- StackExchange.Redis客户端读写主从配置,以及哨兵配置。
今天简单分享一下StackExchange.Redis客户端中配置主从分离以及哨兵的配置. 关于哨兵如果有不了解的朋友,可以看我之前的一篇分享,当然主从复制文章也可以找到.http://www.cnb ...
- css水平居中的各种方法
说到水平居中,大家可能觉得很简单啊,text-align:center 就OK了. 但是,有时候会发现这样写了也没出效果.原因是什么呢? 请往下看. 水平居中:分为块级元素居中和行元素居中 行内元素 ...
- Xcode7.1环境下上架iOS App到AppStore 流程② (Part 二)
前言部分 part二部分主要讲解 iOS App IDs 的创建.概要文件的配置.以及概要文件安装的过程. 一.iOS App IDs 的创建 1)进入如图1所示界面点击右上角箭头所指的加号 进入iO ...
- flhs笔试题-回家上机实践
这是最近参加的一个公司的笔试题,回家上机写了下代码,希望对有需要的小伙伴有用,简单实现字符串和数组在指定位置的插入: package org.flhs; import com.google.commo ...