[LeetCode] 850. Rectangle Area II 矩形面积之二
We are given a list of (axis-aligned) `rectangles`. Each `rectangle[i] = [x1, y1, x2, y2] `, where (x1, y1) are the coordinates of the bottom-left corner, and (x2, y2) are the coordinates of the top-right corner of the `i`th rectangle.
Find the total area covered by all rectangles in the plane. Since the answer may be too large, return it modulo 10^9 + 7.

Example 1:
Input: [[0,0,2,2],[1,0,2,3],[1,0,3,1]]
Output: 6
Explanation: As illustrated in the picture.
Example 2:
Input: [[0,0,1000000000,1000000000]]
Output: 49
Explanation: The answer is 10^18 modulo (10^9 + 7), which is (10^9)^2 = (-7)^2 = 49.
Note:
1 <= rectangles.length <= 200rectanges[i].length = 40 <= rectangles[i][j] <= 10^9- The total area covered by all rectangles will never exceed
2^63 - 1and thus will fit in a 64-bit signed integer.
这道题是之前那道 [Rectangle Area](http://www.cnblogs.com/grandyang/p/4563153.html) 的拓展,那道题只有两个矩形重叠,而这道题有多个矩形可能同时重叠,整体难度一下就上来了,那么通过将所有矩形面积加起来再减去重叠区域的方法这里就不太适用了,因为多个矩形在同一区域重叠的话,都减去重叠面积是会错的,还得把多减的补回来,相当的麻烦。这里我们需要换一种解题的思路,不能一股脑儿的把所有的矩形都加起来,而是应该利用微积分的思想,将重叠在一起的区域拆分成一个个的小矩形,分别累加面积,因为这里的矩形是不会旋转的,所以是可以正常拆分的。思路有了,新建一个二维数组 all 来保存所有的矩形,然后遍历给定的矩形数组,对于每个遍历到的数组,调用一个子函数,将当前的矩形加入 all 中。下面主要来看一下这个子函数 helper 该如何实现?首先要明白这个函数的作用是将当前矩形加入 all 数组中,而且用的是递归的思路,所以要传入一个 start 变量,表示当前和 all 数组中正在比较的矩形的 index,这样在开始的时候,检查一下若 start 大于等于 all 数组长度,表示已经检测完 all 中所有的矩形了,将当前矩形加入 all 数组,并返回即可。否则的话则取出 start 位置上的矩形 rec,此时就要判断当前要加入的矩形和这个 rec 矩形是否有重叠,这在 LeetCode 中有专门一道题是考察这个的 [Rectangle Overlap](https://www.cnblogs.com/grandyang/p/10367583.html),这里用的就是那道题的判断方法,假如判断出当前矩形 cur 和矩形 rec 没有交集,就直接对 all 数组中下一个矩形调用递归函数,并返回即可。假如有重叠的话,就稍微麻烦一点,由于重叠的部位不同,所以需要分情况讨论一下,参见下图所示:

对于一个矩形 Rectangle,若有另外一个矩形跟它有重叠的话,可以将重叠区域分为四个部分,如上图的 Case1,Case2,Case3,Case4 所示,非重叠部分一定会落在一个或多个区域中,则可以把这些拆开的小矩形全部加入到矩形数组 all 中。仔细观察上图可以发现,对于将矩形 cur 拆分的情况可以分为下面四种:
- 落入区间1,条件为 cur[0] < rec[0],产生的新矩形的两个顶点为 {cur[0], cur[1], rec[0], cur[3]}。
- 落入区间2,条件为 cur[2] > rec[2],产生的新矩形的两个顶点为 {rec[2], cur[1], cur[2], cur[3]}。
- 落入区间3,条件为 cur[1] < rec[1],产生的新矩形的两个顶点为 {max(rec[0], cur[0]), cur[1], min(rec[2], cur[2]), rec[1]}。
- 落入区间4,条件为 cur[3] > rec[3],产生的新矩形的两个顶点为 {max(rec[0], cur[0]), rec[3], min(rec[2], cur[2]), cur[3]}。
这样操作下来的话,整个所有的区域都被拆分成了很多个小矩形,每个矩形之间都不会有重复,最后只要分别计算每个小矩形的面积,并累加起来就是最终的结果了,参见代码如下:
解法一:
class Solution {
public:
int rectangleArea(vector<vector<int>>& rectangles) {
long res = 0, M = 1e9 + 7;
vector<vector<int>> all;
for (auto rectangle : rectangles) {
helper(all, rectangle, 0);
}
for (auto &a : all) {
res = (res + (long)(a[2] - a[0]) * (long)(a[3] - a[1])) % M;
}
return res;
}
void helper(vector<vector<int>>& all, vector<int> cur, int start) {
if (start >= all.size()) {
all.push_back(cur); return;
}
auto rec = all[start];
if (cur[2] <= rec[0] || cur[3] <= rec[1] || cur[0] >= rec[2] || cur[1] >= rec[3]) {
helper(all, cur, start + 1); return;
}
if (cur[0] < rec[0]) {
helper(all, {cur[0], cur[1], rec[0], cur[3]}, start + 1);
}
if (cur[2] > rec[2]) {
helper(all, {rec[2], cur[1], cur[2], cur[3]}, start + 1);
}
if (cur[1] < rec[1]) {
helper(all, {max(rec[0], cur[0]), cur[1], min(rec[2], cur[2]), rec[1]}, start + 1);
}
if (cur[3] > rec[3]) {
helper(all, {max(rec[0], cur[0]), rec[3], min(rec[2], cur[2]), cur[3]}, start + 1);
}
}
};
下面这种解法更是利用了微积分的原理,把x轴长度为1当作一个步长,然后计算每一列有多少个连续的区间,每个连续区间又有多少个小正方形,题目中给的例子每一个列都只有一个连续区间,但事实上是可以有很多个的,只要算出了每一列 1x1 小正方形的个数,将所有列都累加起来,就是整个区域的面积。这里求每列上小正方形个数的方法非常的 tricky,博主也不知道该怎么讲解,大致就是要求同一列上每个连续区间中的小正方形个数,再累加起来。对于每个矩形起始的横坐标,映射较低的y值到1,较高的y值到 -1,对于结束位置的横坐标,刚好反过来一下,映射较低的y值到 -1,较高的y值到1。这种机制跟之前那道 [The Skyline Problem](http://www.cnblogs.com/grandyang/p/4534586.html) 有些异曲同工之妙,都还是为了计算高度差服务的。要搞清楚这道题的核心思想,不是一件容易的事,博主的建议是就拿题目中给的例子带入到下面的代码中,一步一步执行,并分析结果,是能够初步的了解解题思路的,若实在有理解上的问题,博主可以进一步写些讲解,参见代码如下:
解法二:
class Solution {
public:
int rectangleArea(vector<vector<int>>& rectangles) {
long res = 0, pre_x = 0, height = 0, start = 0, cnt = 0, M = 1e9 + 7;
map<int, vector<pair<int, int>>> groupMap;
map<int, int> cntMap;
for (auto &a : rectangles) {
groupMap[a[0]].push_back({a[1], 1});
groupMap[a[0]].push_back({a[3], -1});
groupMap[a[2]].push_back({a[1], -1});
groupMap[a[2]].push_back({a[3], 1});
}
for (auto &group : groupMap) {
res = (res + (group.first - pre_x) * height) % M;
for (auto &a : group.second) {
cntMap[a.first] += a.second;
}
height = 0, start = 0, cnt = 0;
for (auto &a : cntMap) {
if (cnt == 0) start = a.first;
cnt += a.second;
if (cnt == 0) height += a.first - start;
}
pre_x = group.first;
}
return res;
}
};
Github 同步地址:
https://github.com/grandyang/leetcode/issues/850
类似题目:
参考资料:
https://leetcode.com/problems/rectangle-area-ii/
https://leetcode.com/problems/rectangle-area-ii/discuss/138028/Clean-Recursive-Solution-Java
[LeetCode All in One 题目讲解汇总(持续更新中...)](https://www.cnblogs.com/grandyang/p/4606334.html)
[LeetCode] 850. Rectangle Area II 矩形面积之二的更多相关文章
- leetcode 850. Rectangle Area II
给定一些矩形2 求覆盖面积 矩形不超过200个 1 算法1 朴素思想 虽然朴素但是代码却有意思 利用容斥原理 复杂度高达 N*2^N class Solution: def intersect(rec ...
- LeetCode 223 Rectangle Area(矩形面积)
翻译 找到在二维平面中两个相交矩形的总面积. 每一个矩形都定义了其左下角和右上角的坐标. (矩形例如以下图) 如果,总占地面积永远不会超过int的最大值. 原文 分析 这题前天试过,写了一堆推断.终究 ...
- [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 ...
- (easy)LeetCode 223.Rectangle Area
Find the total area covered by two rectilinear rectangles in a 2D plane. Each rectangle is defined b ...
- [Swift]LeetCode850. 矩形面积 II | Rectangle Area II
We are given a list of (axis-aligned) rectangles. Each rectangle[i] = [x1, y1, x2, y2] , where (x1, ...
- leetcode之Rectangle Area
Find the total area covered by two rectilinear rectangles in a 2D plane. Each rectangle is defined b ...
- leetcode:Rectangle Area
Find the total area covered by two rectilinear rectangles in a 2D plane. Each rectangle is defined b ...
- LeetCode(41)-Rectangle Area
题目: Find the total area covered by two rectilinear rectangles in a 2D plane. Each rectangle is defin ...
随机推荐
- iOS性能优化-数组、字典便利时间复杂
上图是几种时间复杂度的关系,性能优化一定程度上是为了降低程序执行效率减低时间复杂度. 如下是几种时间复杂度的实例: O(1) return array[index] == value; 复制代码 O( ...
- php,mysql结合js解决商品分类问题,从而不必联表查询
首先mysql数据表中的商品分类用varchar类型,比如AA,BB,CC,DD等 其次编写一个js文件,用于定义常量,比如 ‘AA’ = ‘中药’; 'BB' = '西药'; 'CC' = '保健 ...
- Serverless 的喧哗与骚动(一)附Serverless行业发展回顾
作者 | 阿里中间件高级技术专家 许晓斌 <Maven实战>作者,曾负责 AliExpress 微服务架构演进,现在负责阿里集团 Serverless 技术研发落地. 导读:从 2016 ...
- QGIS中查看PostGIS空间数据库中的影像
在QGIS中的Browser中是无法显示PostGIS空间数据库中的影像 要找到影像显示打开"Database" –> "DB Manager" 右击-- ...
- 练手WPF(四)——贪吃蛇小游戏的简易实现(下)
八.生成新的单节蛇身我们这里先说说游戏小原理好了,游戏运行后,通过计时器事件不断生成新的单节蛇身类SnakeNode,添加到List中的0位置,原来的蛇头变成了第二节.该节新蛇头的坐标通过蛇头前进方向 ...
- Java问题记录——IllegalMonitorStateException
Java问题记录——IllegalMonitorStateException 摘要:本文主要分析了IllegalMonitorStateException的产生原因. 部分内容来自以下博客: http ...
- HDFS基本原理
一.什么是HDFS HDFS即Hadoop分布式文件系统(Hadoop Distributed Filesystem),以流式数据访问模式来存储超大文件,它和现有的分布式文件系统有很多共同点.但同时, ...
- 设置 WPF 的全球化语言
https://stackoverflow.com/questions/7454024/setting-culture-en-in-globally-in-wpf-app Thread.Current ...
- day02 整理
目录 编程语言的分类 机器语言 汇编语言 高级语言 编译型语言(谷歌翻译) 解释型语言(同声传译) 执行python程序的两种方式 Jupyter的使用 jupyter的介绍 安装 基本使用 Jupy ...
- MySql学习笔记三
MySql学习笔记三 4.DML(数据操作语言) 插入:insert 修改:update 删除:delete 4.1.插入语句 语法: insert into 表名 (列名1,列名2,...) val ...