LeetCode 矩形面积II(扫描法)

我们给出了一个(轴对齐的)矩形列表 rectangles 。 对于 rectangle[i] = [x1, y1, x2, y2],其中(x1,y1)是矩形 i 左下角的坐标,(x2,y2)是该矩形右上角的坐标。

找出平面中所有矩形叠加覆盖后的总面积。 由于答案可能太大,请返回它对 10 ^ 9 + 7 取模的结果。
LeetCode 矩形面积II(扫描法)_第1张图片
示例 1:

输入:[[0,0,2,2],[1,0,2,3],[1,0,3,1]]
输出:6
解释:如图所示。

示例 2:

输入:[[0,0,1000000000,1000000000]]
输出:49
解释:答案是 10^18 对 (10^9 + 7) 取模的结果, 即 (10^9)^2 → (-7)^2 = 49 。

提示:

1 <= rectangles.length <= 200
rectanges[i].length = 4
0 <= rectangles[i][j] <= 10^9
矩形叠加覆盖后的总面积不会超越 2^63 - 1 ,这意味着可以用一个 64 位有符号整数来保存面积结果。

思 路 分 析 : \color{blue}思路分析: 这道题最主要的问题是如何才能防止重复计算面积,如果我们是顺序处理rectangles,每次处理一个矩形,那么重复计算将变得非常难以处理。为此我们将矩形面价按照x轴(或者y轴)进行切割,然后再在y轴(或者x轴)进行累计求和。下面将选择在x轴方向进行切割。

关于区间合并,请参考 LeetCode Range模块
算法描述:

第一步:将所有矩形的x坐标放入xVec
第二步:按照升序排序x坐标
第三步:在xVec中进行去重
第四步:逆序扫描x坐标段,计算在(xVec[i], xVec[i + 1])段中的面积
	假设xVec[i] = 1, xVec[i + 1] = 2,则所有矩形在这个x区间段中存在交集的矩形y轴段是
	矩形[0,0,2,2]中的Y轴区间段[0, 2],矩形[1,0,2,3]中的Y轴区间段[0, 3],矩形[1,0,3,1]中的Y轴区间段[0,1],合并时候Y轴区间段段为[0, 3](类似区间的合并)
	distanceX = xVec[i + 1] - xVec[i] = 1, distanceY = 3 - 0 = 3,所以S[2] = distanceX * distanceY = 3

LeetCode 矩形面积II(扫描法)_第2张图片

class Solution {
public:
    int rectangleArea(vector<vector<int>>& rectangles) {
        vector<int> xVec;//用于存放所有矩形的x坐标
        int sumArea = 0, mod = 7 + 1e9;
        //第一步:将所有矩形的x坐标放入xVec
        for (const auto &rectangle : rectangles){
            xVec.push_back(rectangle[0]);
            xVec.push_back(rectangle[2]);
        }
        //第二步:按照升序排序x坐标
        sort(xVec.begin(), xVec.end());
        //第三步:在xVec中进行去重(unique是STL中的去重函数,它会把重复的元素移动到xVec的后端,并且返回第一个重复的值的迭代器)
        xVec.erase(unique(xVec.begin(), xVec.end()), xVec.end());
        //第四步:逆序扫描x坐标段,计算在(xVec[i], xVec[i + 1])段中的面积
        for (int i = xVec.size() - 2; i >= 0; --i){
            list<pair<int, int>> myList;//按照递增的顺序存储所有不重复、重叠的y轴坐标段
            //如果rectangle在(xVec[i], xVec[i + 1])段中有面积,则将它两个y轴坐标放入list
            for (const auto &rectangle : rectangles){
                if (rectangle[0] <= xVec[i] && rectangle[2] >= xVec[i + 1]){
                    addRange(myList, rectangle[1], rectangle[3]);
                }
            }
            //然后我们需要把y轴这些区间段的长度进行求和
            long distanceY = 0;
            for (const auto &item : myList){
                distanceY += item.second - item.first;
            }
            //xVec[i + 1] - xVec[i]表示x轴区间段的宽度,distanceY是在这个x轴段y轴各个区间段长度的和
            sumArea = (sumArea + (xVec[i + 1] - xVec[i]) * distanceY) % mod;
        }
        return sumArea;
    }
    //添加Range[left, right]
	void addRange(list<pair<int, int>> &myList, int left, int right) {
		auto it = myList.begin();
        //第一步:确定[left,right]插入的位置(第一个与它有交集的元素)
		while (it != myList.end() && it->second < left) {
			++it;
		}
        //第二步:判断是插入到list中还是修改list
        //如果是插入尾端、或者两个Range之间(list中没有Range与它有交集),直接插入
		if (it == myList.end() || it->first > right) {
			myList.insert(it, { left, right});
		}
		else {
            //此时修改it指向的元素
			it->first = min(it->first, left);
			it->second = max(it->second, right);
            //然后看it后面是否有需要合并的Rande
			auto beforeIt = it++;
			while (it != myList.end() && beforeIt->second >= it->first) {
				beforeIt->second = max(it->second, beforeIt->second);
				it = myList.erase(it);
			}
		}
	}
};

LeetCode 矩形面积II(扫描法)_第3张图片

你可能感兴趣的:(LeetCode,图)