我们有 N 个与坐标轴对齐的矩形, 其中 N > 0, 判断它们是否能精确地覆盖一个矩形区域。
每个矩形用左下角的点和右上角的点的坐标来表示。例如, 一个单位正方形可以表示为 [1,1,2,2]。 ( 左下角的点的坐标为 (1, 1) 以及右上角的点的坐标为 (2, 2) )。
示例 1:
rectangles = [
[1,1,3,3],
[3,1,4,2],
[3,2,4,4],
[1,3,2,4],
[2,3,3,4]
]
返回 true。5个矩形一起可以精确地覆盖一个矩形区域。
示例 2:
rectangles = [
[1,1,2,3],
[1,3,2,4],
[3,1,4,2],
[3,2,4,4]
]
返回 false。两个矩形之间有间隔,无法覆盖成一个矩形。
rectangles = [
[1,1,3,3],
[3,1,4,2],
[1,3,2,4],
[3,2,4,4]
]
返回 false。图形顶端留有间隔,无法覆盖成一个矩形。
rectangles = [
[1,1,3,3],
[3,1,4,2],
[1,3,2,4],
[2,2,4,4]
]
返回 false。因为中间有相交区域,虽然形成了矩形,但不是精确覆盖。
思路分析:如果所有小矩形能够拼凑成大矩形,那么所有小矩形的面积和必定和大矩形的面积相等,且大矩形被小矩形完全覆盖。
方法一:蛮力法。
class Solution {
public:
bool isRectangleCover(vector>& rectangles) {
long long area = 0;//所有小矩形的总面积
int leftDownRow = INT_MAX / 2, leftDownCol = INT_MAX / 2;//大矩形左下角
int rightUpRow = INT_MIN / 2, rightUpCol = INT_MIN / 2;//大矩形右上角
//遍历所有小矩形
for (auto &rectangle : rectangles){
area = area + (long long)(rectangle[2] - rectangle[0]) * (long long)(rectangle[3] - rectangle[1]);//小矩形面积
//寻找大矩形的可能最左下角的下标
if (leftDownRow + leftDownCol > rectangle[0] + rectangle[1]){
leftDownRow = rectangle[0];
leftDownCol = rectangle[1];
}
//寻找大矩形的可能最有上角的下标
if (rightUpRow + rightUpCol < rectangle[2] + rectangle[3]){
rightUpRow = rectangle[2];
rightUpCol = rectangle[3];
}
}
//如果所有小矩形的面积和和可能的最大矩形面积不相等,说明不能构成大矩形
if ((long long)(rightUpRow - leftDownRow) * (long long)(rightUpCol - leftDownCol) != area){
return false;
}
//将大矩形所有节点标记
map, bool> myMap;
for (int row = leftDownRow; row < rightUpRow; ++row){
for (int col = leftDownCol; col < rightUpCol; ++col){
myMap[make_pair(row, col)] = false;
}
}
//遍历所有小矩形
for (auto &rectangle : rectangles){
for (int row = rectangle[0]; row < rectangle[2]; ++row){
for (int col = rectangle[1]; col < rectangle[3]; ++col){
//如果这个点不在大矩形返回,或者之前就被标记了(重叠)
if (myMap.count(make_pair(row, col)) == 0 || myMap[make_pair(row, col)]){
return false;
}
else{
myMap[make_pair(row, col)] = true;//否则标记
}
}
}
}
return true;
}
};
方法二:并不将所有大矩形中的点进行标记,而是从放入的小矩形入手,将矩形两点表示修改为四点表示。每次访问一个小矩形都尝试将其四个顶点放入set,如果某个点之前set就存在,那么移除,否则放入集合。如果是完美矩形,那么最后set剩余的必定是大矩形的四个角。因为如果是完美矩形,其他点必定出现偶数次。
class Solution {
public:
bool isRectangleCover(vector>& rectangles) {
long long area = 0;//所有小矩形的总面积
int leftDownRow = INT_MAX / 2, leftDownCol = INT_MAX / 2;//大矩形左下角
int rightUpRow = INT_MIN / 2, rightUpCol = INT_MIN / 2;//大矩形右上角
set> mySet;//标记点
//遍历所有小矩形
for (auto &rectangle : rectangles){
area = area + (long long)(rectangle[2] - rectangle[0]) * (long long)(rectangle[3] - rectangle[1]);//小矩形面积
//寻找大矩形的可能最左下角的下标
leftDownRow = min(leftDownRow, rectangle[0]);
leftDownCol = min(leftDownCol, rectangle[1]);
//寻找大矩形的可能最有上角的下标
rightUpRow = max(rightUpRow, rectangle[2]);
rightUpCol = max(rightUpCol, rectangle[3]);
//将四个点进行确认
//左下角
if (mySet.find({rectangle[0], rectangle[1]}) == mySet.end()){
mySet.insert({rectangle[0], rectangle[1]});
}
else{
mySet.erase({rectangle[0], rectangle[1]});
}
//右上角
if (mySet.find({rectangle[2], rectangle[3]}) == mySet.end()){
mySet.insert({rectangle[2], rectangle[3]});
}
else{
mySet.erase({rectangle[2], rectangle[3]});
}
//左上角
if (mySet.find({rectangle[0], rectangle[3]}) == mySet.end()){
mySet.insert({rectangle[0], rectangle[3]});
}
else{
mySet.erase({rectangle[0], rectangle[3]});
}
//右下角
if (mySet.find({rectangle[2], rectangle[1]}) == mySet.end()){
mySet.insert({rectangle[2], rectangle[1]});
}
else{
mySet.erase({rectangle[2], rectangle[1]});
}
}
//如果是完美矩形,最后必定只剩四个点
if (mySet.size() == 4 && mySet.find({leftDownRow, leftDownCol}) != mySet.end() && mySet.find({rightUpRow, rightUpCol}) != mySet.end() && mySet.find({leftDownRow, rightUpCol}) != mySet.end() && mySet.find({rightUpRow, leftDownCol}) != mySet.end()){
//如果所有小矩形的面积和和可能的最大矩形面积相等,说明能构成大矩形
if ((long long)(rightUpRow - leftDownRow) * (long long)(rightUpCol - leftDownCol) == area){
return true;
}
}
return false;
}
};