391. 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.

算法分析

刚开始想到的一个方法是先遍历所有的矩形,找出最小的(leftMost,bottomMost)和最大的(rightMost,topMost),这是所有矩形所可能覆盖的最大的区域。然后定义一个二维数组:

int[][] area = new int[topMost-bottomMost][rightMost-leftMost],

再遍历一次所有的矩形,对矩形 rect,做如下判断:

int totalArea=0;
for(int[] rect:rectangles){
for(int i=rect[1]-bottomMost;i<rect[3]-bottomMost;i++){
for(int j=rect[0]-leftMost;j<rect[2]-leftMost;j++){
totalArea++;
if(area[i][j]>=1){//说明出现了重叠覆盖区域
return false;
}
else{
area[i][j]++;
}
}
}

当遍历完所有矩形后,首先判断

if(totalArea!=(rightMost-leftMost)*(topMost-bottomMost)){
return false;
}

因为如果要实现完全覆盖,必须有 totalArea=(rightMost-leftMost)*(topMost-bottomMost).

满足了相等条件后,再判断是否area[][]数组中所有的数据均为1----是,则说明最大覆盖区域中的每个小单元均被覆盖了一次,满足条件,返回 true;否,则说明有的区域没有覆盖到,返回 false。

上述算法的思想是正确的,但是当输入数据量覆盖面积较大时,会出现 Memory Exceeded 的错误。考虑使用一个 bit 来表示一个单元面积,结果出现了 Time Limit Exceeded 的错误。

最终考虑使用如下算法思想:

任意一个矩形均有4个顶点,当出现Perfect Rectangle时,在最大覆盖矩形内部,所有其它矩形的任意一个顶点均会出现偶数次(因为一个矩形旁边应当有一个或三个矩形和它紧密相连,那么这个相接的顶点就出现了偶数次)。所以,可以构建一个HashSet<String> set,以一个矩形的四个顶点的(x,y)坐标构造字符串 (x+","+y),以该字符串做键值,当set中不存在该键值时,则存入该键值;当set中存在该键值时,则删除该键值;最终set中应该只剩下四个键,这四个键即是最大覆盖矩形的四个顶点。


Java 算法实现如下(并不正确):

public class Solution {
public boolean isRectangleCover(int[][] rectangles) {
if(rectangles.length==0||rectangles[0].length==0){
return false;
}
else{
HashSet<String>set=new HashSet<>();
int leftMost=Integer.MAX_VALUE;
int bottomMost=Integer.MAX_VALUE;
int rightMost=Integer.MIN_VALUE;
int topMost=Integer.MIN_VALUE;
int x1,y1,x2,y2;
for(int[] rect:rectangles){
x1=rect[0];
y1=rect[1];
x2=rect[2];
y2=rect[3];
//记录最靠边界的点的坐标
if(x1<leftMost){
leftMost=x1;
}
if(y1<bottomMost){
bottomMost=y1;
}
if(x2>rightMost){
rightMost=x2;
}
if(y2>topMost){
topMost=y2;
}
//由当前考察的矩形的四个顶点的坐标构成的键值
String key1=x1+","+y1;
String key2=x1+","+y2;
String key3=x2+","+y1;
String key4=x2+","+y2;
//删除那些出现了偶数次的键值
if(set.contains(key1)){
set.remove(key1);
}
else{
set.add(key1);
} if(set.contains(key2)){
set.remove(key2);
}
else{
set.add(key2);
} if(set.contains(key3)){
set.remove(key3);
}
else{
set.add(key3);
} if(set.contains(key4)){
set.remove(key4);
}
else{
set.add(key4);
}
}
String key1=leftMost+","+bottomMost;
String key2=leftMost+","+topMost;
String key3=rightMost+","+bottomMost;
String key4=rightMost+","+topMost;
if(set.size()!=4||!set.contains(key1)||
!set.contains(key2)||!set.contains(key3)||
!set.contains(key4)){
return false;
}
else{
return true;
}
}
}
}

结果出现如下错误:



如上数据所示,[0,0,3,3] 为最大覆盖矩形,两个[1,1,2,2]又都在其内部,且互相抵消掉了,所以该输入数据成功地避开了所有的检测,返回了不正确的答案 true。 改正方法是添加一个 long area 数据用以记录所有矩形的总面积,检测 area 是否和 (rightMost-leftMost)*(topMost-bottomMost)相等,若不等,则说明没有完全覆盖或者出现了重叠覆盖,返回 false;若相等,则做进一步判断。新代码如下:

Java算法实现:

public class Solution {
public boolean isRectangleCover(int[][] rectangles) {
if(rectangles.length==0||rectangles[0].length==0){
return false;
}
else{
HashSet<String>set=new HashSet<>();
int leftMost=Integer.MAX_VALUE;
int bottomMost=Integer.MAX_VALUE;
int rightMost=Integer.MIN_VALUE;
int topMost=Integer.MIN_VALUE;
int x1,y1,x2,y2;
long area=0;
for(int[] rect:rectangles){
x1=rect[0];
y1=rect[1];
x2=rect[2];
y2=rect[3];
area+=(x2-x1)*(y2-y1);//累积记录已遍历的矩形的面积
//记录最靠边界的点的坐标
if(x1<leftMost){
leftMost=x1;
}
if(y1<bottomMost){
bottomMost=y1;
}
if(x2>rightMost){
rightMost=x2;
}
if(y2>topMost){
topMost=y2;
}
if(area>(rightMost-leftMost)*(topMost-bottomMost)){
//目前遍历的矩形的面积已经大于了所能覆盖的面积,则一定存在了重叠
return false;
}
//由当前考察的矩形的四个顶点的坐标构成的键值
String key1=x1+","+y1;
String key2=x1+","+y2;
String key3=x2+","+y1;
String key4=x2+","+y2;
//totalCouverCount用以记录是否出现了某个矩形完全覆盖了之前的某个矩形
//删除那些出现了偶数次的键值
if(set.contains(key1)){
set.remove(key1);
}
else{
set.add(key1);
} if(set.contains(key2)){
set.remove(key2);
}
else{
set.add(key2);
} if(set.contains(key3)){
set.remove(key3);
}
else{
set.add(key3);
} if(set.contains(key4)){
set.remove(key4);
}
else{
set.add(key4);
}
} if(area!=(rightMost-leftMost)*(topMost-bottomMost)){//说明没有完全覆盖或出现了重叠覆盖
return false;
} String key1=leftMost+","+bottomMost;
String key2=leftMost+","+topMost;
String key3=rightMost+","+bottomMost;
String key4=rightMost+","+topMost;
if(set.size()!=4||!set.contains(key1)||
!set.contains(key2)||!set.contains(key3)||
!set.contains(key4)){
return false;
}
else{
return true;
}
}
}
}

这次就成功了。

LeetCode赛题391----Perfect Rectangle的更多相关文章

  1. 花式求解 LeetCode 279题-Perfect Squares

    原文地址 https://www.jianshu.com/p/2925f4d7511b 迫于就业的压力,不得不先放下 iOS 开发的学习,开始走上漫漫刷题路. 今天我想聊聊 LeetCode 上的第2 ...

  2. LeetCode算法题-Construct the Rectangle(Java实现)

    这是悦乐书的第243次更新,第256篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第110题(顺位题号是492).对于Web开发人员,了解如何设计网页的大小非常重要.因此 ...

  3. LeetCode算法题-Valid Perfect Square(Java实现-四种解法)

    这是悦乐书的第209次更新,第221篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第77题(顺位题号是367).给定正整数num,写一个函数,如果num是一个完美的正方形 ...

  4. 391. Perfect Rectangle

    最后更新 一刷 16-Jan-2017 这个题我甚至不知道该怎么总结. 难就难在从这个题抽象出一种解法,看了别人的答案和思路= =然而没有归类总结到某种类型,这题相当于背了个题... 简单的说,除了最 ...

  5. 391 Perfect Rectangle 完美矩形

    有 N 个与坐标轴对齐的矩形, 其中 N > 0, 判断它们是否能精确地覆盖一个矩形区域.每个矩形用左下角的点和右上角的点的坐标来表示.例如, 一个单位正方形可以表示为 [1,1,2,2]. ( ...

  6. LeetCode赛题515----Find Largest Element in Each Row

    问题描述 You need to find the largest element in each row of a Binary Tree. Example: Input: 1 / \ 2 3 / ...

  7. LeetCode赛题----Find Left Most Element

    问题描述 Given a binary tree, find the left most element in the last row of the tree. Example 1: Input: ...

  8. LeetCode赛题395----Longest Substring with At Least K Repeating Characters

    395. Longest Substring with At least K Repeating Characters Find the length of the longest substring ...

  9. LeetCode赛题394----Decode String

    394. Decode String Given an encoded string, return it's decoded string. The encoding rule is: k[enco ...

随机推荐

  1. PKUWC2019退役记

    PKUWC2019 退役记 \(day1\): 进场看T1,发现是个对于所有边的子集求权值和的计数题,以为是个主旋律那样的神仙容斥,完全不会做(退役flag*1).T2是个和虚树有关的计数题,第一个s ...

  2. 获得自己电脑的SSH公匙

    关于什么是SSH请点击此"www.Baidu.com”网站了解 我这里只说怎么获取属于自己电脑的SSH公匙 本人是Win10电脑 所以相对来说简单一点  点击win ->选择设置-&g ...

  3. mono for android 第三课--页面布局(转)

    对于C#程序员来说布局不是什么难事,可是对于我这个新手在mono for android 中布局还是有点小纠结的,不会没关系.慢慢学习.好吧我们开始简单的布局.在之前我们拖拽的控件都是自动的去布局,也 ...

  4. Jmeter之测试报告

    当我们完成测试后,需要通过报告来查看测试结果 一.聚合报告 Label:每个JMeter的element的Name值.例如HTTP Request的Name #Samples:发出请求数量.例如:如第 ...

  5. Tomcat *的下载(绿色版和安装版都适用)

    不多说,直接干货! 1.先下载tomcat,到http://tomcat.apache.org/ 2.注意:下载可以下载zip格式或exe格式的,其中zip格式的只要解压缩再配置下环境变量就可以使用了 ...

  6. 阅读The Java® Language Specification需要知道的术语

    Null Pointer Exception,简称NPE 在java中,static final修饰的是常量.根据编译器的不同行为,常量又可分为编译时常量和运行时常量. 举例说明吧 public st ...

  7. rspec中的let和let!区别

    文档 https://relishapp.com/rspec/rspec-core/v/2-5/docs/helper-methods/let-and-let 从上面文档中得出 let 1 只会在一个 ...

  8. PHP代码实现强制换行

    1. 简单的,只能分2行: //$str:输入字符串: //$num:超过多少个字符后进行换行(换行后每行的最大字符数) function forceBlackString($str, $num){ ...

  9. 话说C语言的关键字volatile

    最近搞NVMe驱动需求分析,对volatile这个单词实在是再熟悉不过了. 而在C语言中,有一个关键字就叫做volatile, 其字面意思是"挥发性的, 不稳定的,可改变的". 那 ...

  10. 使用Java发送Http请求的内容

    公司要将自己的产品封装一个WebService平台,所以最近开始学习使用Java发送Http请求的内容.这一块之前用PHP的时候写的也比较多,从用最基本的Socket和使用第三方插件都用过. 学习了J ...