题目:
我们给出了一个(轴对齐的)二维矩形列表 rectangles 。 对于 rectangle[i] = [x1, y1, x2, y2],其中(x1,y1)是矩形 i 左下角的坐标, (xi1, yi1) 是该矩形 左下角 的坐标, (xi2, yi2) 是该矩形 右上角 的坐标。
计算平面中所有 rectangles 所覆盖的 总面积 。任何被两个或多个矩形覆盖的区域应只计算 一次 。
返回 总面积 。因为答案可能太大,返回 109 + 7 的 模 。
示例 1:
输入:rectangles = [[0,0,2,2],[1,0,2,3],[1,0,3,1]]
输出:6
解释:如图所示,三个矩形覆盖了总面积为6的区域。
从(1,1)到(2,2),绿色矩形和红色矩形重叠。
从(1,0)到(2,3),三个矩形都重叠。
示例 2:
输入:rectangles = [[0,0,1000000000,1000000000]]
输出:49
解释:答案是 1018 对 (109 + 7) 取模的结果, 即 49 。
提示:
1 <= rectangles.length <= 200
rectanges[i].length = 4
0 <= xi1, yi1, xi2, yi2 <= 109
矩形叠加覆盖后的总面积不会超越 2^63 - 1 ,这意味着可以用一个 64 位有符号整数来保存面积结果。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/rectangle-area-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路:
本质题目其实就是去计算面积,那么其实问题并不难
从下往上扫描,计算每一段之间的最大宽度,那么y的差值乘以宽度就是面积
为了扫描计算的准确,需要额外辅助
需要按照y排序,从小到大
需要对于当前区间内的范围x也进行排序,考虑x范围会有重复用一个multiset来保存
对于离开区间需要删除multiset里的key,进入则插入key
计算时候从x1,x2里x1小的开始计算,这样子就能算出最大的宽度,参见函数 QueryWidth
代码:
class Solution
{
private:
const static int MOD = 1e9 + 7;
const static int OPEN = 0;
const static int CLOSE = 1;
// 计算宽度:其实就是不断累加更大的x的差值即可
int QueryWidth(multiset<pair<int,int>>& activate)
{
int res = 0;
int maxX = -1;
for (auto [x1, x2] : activate)
{
maxX = max(maxX, x1);
// 如果x变大了,则计算差值累加更大的宽度
res += max(0, x2 - maxX);
// 不断更新最大x
maxX = max(maxX, x2);
}
return res;
}
public:
int rectangleArea(vector<vector<int>>& rectangles)
{
vector<vector<int>> rec;
for (auto v: rectangles)
{
rec.push_back({v[1], OPEN, v[0], v[2]});
rec.push_back({v[3], CLOSE, v[0], v[2]});
}
// 排序从下到上来扫描
sort(rec.begin(), rec.end());
// 存储面积和
int res = 0;
// 初始化第一个y的位置
int lastY = rec[0][0];
// 当前需要计算的面积横坐标 [x1,x2]
// 扫描过程中 对于每次OPEN则插入,CLOSE则删除
multiset<pair<int,int>> activate;
for (const vector<int> r : rec)
{
int y = r[0];
int state = r[1];
int x1 = r[2];
int x2 = r[3];
// 累加面积
res = (res + (long long)QueryWidth(activate)*(y-lastY)) % MOD;
// 更新上一个y坐标
lastY = y;
// 对于每次OPEN则插入,CLOSE则删除
if (state == OPEN)
{
activate.insert({x1, x2});
}
else
{
activate.erase(activate.find(pair<int,int>{x1, x2}) );
}
}
return res;
}
};