扫描线+离散化 计算矩形面积

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

计算平面中所有 rectangles 所覆盖的 总面积 。任何被两个或多个矩形覆盖的区域应只计算 一次 。返回 总面积 。因为答案可能太大,返回 10^9 + 7 的 模 。

i​​​​​​LeetCode链接

思路:

我的第一反应是计算所有矩形面积,然后减去两两相交的面积。这种做法是错误的因为每个重叠部分只要减去一次,可能会重复减去。

这道题的正确思路是把整个区域按所有矩形的边界进行划分,然后逐个计算分块的面积。

步骤:

  • 把所有矩形的左右边存到一个数组和上下边存到另一个数组,分别将它们去重,然后排序。此时得到的按从左到右和从上到下的排列边界,它们将整个区域划分为了一条条横纵排列的线段,线段组成了一个个小矩形。
  • 按左界排序矩阵。这步是为了接下来从左到右扫描做准备。
  • 创建一个二维数组,其长度等于矩形数量。其中的每个一维数组存储该矩形覆盖的上下边界的分割的线段。这步是为了之后遍历矩形时能快速地找到它覆盖的区域。
  • 创建一个长度等于上下边界-1的bool数组。它的作用是标记在本次扫描中某块区域是否已经被覆盖。
  • 创建一个与bool数组长度相同的long数组,用来存放该区域已经覆盖的总面积。
  • 从左到右遍历左右边界,每次循环时将bool数组全部值为false,在循环中遍历所有覆盖了该边界的矩形,通过二维数组找到该矩形覆盖的上下边界,如果对应的bool值为false,则计算这块面积将他加到long数组的对应位置,并将bool值为true。
  • 返回long数组总和对1000000007的模。
class Solution {
public:
    int rectangleArea(vector<vector<int>>& rectangles) {
        long res=0;int i,j,k;
        vector<int> xbound;vector<int> ybound;
        for(i=0;i<rectangles.size();i++)
        {
            xbound.push_back(rectangles[i][0]);
            xbound.push_back(rectangles[i][2]);
            ybound.push_back(rectangles[i][1]);
            ybound.push_back(rectangles[i][3]);
        }
        xbound.erase(unique(xbound.begin(),xbound.end()),xbound.end());
        ybound.erase(unique(ybound.begin(),ybound.end()),ybound.end());
        sort(xbound.begin(),xbound.end());
        sort(ybound.begin(),ybound.end());
        sort(rectangles.begin(),rectangles.end());
        int NumOfLine=ybound.size()-1;
        long area[NumOfLine];
        fill(area,area+NumOfLine,0);
        vector<vector<int>> lines;
        for(i=0;i<rectangles.size();i++)
        {
            vector<int> temp;
            j=0;k=ybound.size()-1;
            while(ybound[j]<rectangles[i][1])
            j++;
            while(ybound[k]>rectangles[i][3])
            k--;
            while(j<k)
                temp.push_back(j++);
            lines.push_back(temp);
        }
        bool flag[NumOfLine];
        for(i=0;i<xbound.size()-1;i++)//i表示扫描线
        {
            fill(flag,flag+NumOfLine,false);
            for(j=0;j<rectangles.size();j++)//j标记矩形
            {
                if(rectangles[j][0]>xbound[i])
                break;
                if(rectangles[j][2]<=xbound[i])
                continue;
                for(int y:lines[j])
                if(!flag[y])
                {
                    area[y]+=(long)(xbound[i+1]-xbound[i])*(ybound[y+1]-ybound[y]);
                    flag[y]=true;
                }
            }/**/
        }
        for(i=0;i<NumOfLine;i++)
        res+=area[i];
        return res%1000000007;
    }
};

猜你喜欢

转载自blog.csdn.net/qq_43533956/article/details/126911288