LeetCode/统计包含每个点的矩形数目

所以矩形左下角为(0,0),右上角为(x,y)
给你一个二维整数数组 rectangles 和 二维整数数组 points
求每个点占据的矩形数目

1. 暴力

遍历点然后遍历矩形
class Solution {
public:
    vector<int> countRectangles(vector<vector<int>>& rectangles, vector<vector<int>>& points) {
            int n = points.size();
            vector<int> res(n);
            for(int i=0;i<n;i++){//遍历每一个点
                int count = 0;
                int x = points[i][0];
                int y = points[i][1];
                for(auto&rec:rectangles)
                    if(x<=rec[0]&&y<=rec[1]) count++;
                res[i] = count;
            }
            return res;
    }
};

2. 排序+哈希+二分

思考如何让当前点迅速找到占据多少个矩形。。。必然要先对矩形数据进行预处理
注意到矩形高度范围很小,可以将矩形按高度分类,然后按长度升序排列
这样判断点的时候,只需判断更高的矩形,同时可以采用二分查找满足条件的宽度下标,从而快速求出满足宽度条件的矩形

class Solution {
public:
    vector<int> countRectangles(vector<vector<int>>& rectangles, vector<vector<int>>& points) {
            int n = points.size();
            vector<int> res(n);
            //因为高度范围小,先按长度排序
            sort(rectangles.begin(),rectangles.end());//按升序排
            vector<vector<int>> dp(101);
            for(auto&rec:rectangles)
                dp[rec[1]].push_back(rec[0]); //把相同高度的按宽度升序放到一起

            for(int i=0;i<n;i++){//遍历每一个点
                int count = 0;
                int x = points[i][0];
                int y = points[i][1];
                for(int j=y;j<=100;j++){//遍历所有更高的高度
                    if(dp[j].size()==0) continue;//当前高度没有矩形
                    auto index = lower_bound(dp[j].begin(),dp[j].end(),x);//找大于长度的下标
                    if(index!=dp[j].end()) res[i]+= dp[j].size()-(index-dp[j].begin());
                }
            }
            return res;
    }
};

3. 树状数组(拓展)

点和矩形的比较其实就是就是经典的二维偏序问题,一般使用树状数组进行处理
其实这里对高度建树,然后将矩形和点的数据按长度排序,固定长度的访问顺序
碰到矩形单点修改对应高度,碰到点查询高于点高度的值即可

class Solution {

public:
    vector<int> countRectangles(vector<vector<int>>& rectangles, vector<vector<int>>& points) {
        vector<vector<int>> vec;//把矩形和点放到一起
        for (auto &rec : rectangles) {//遍历所有矩形
            vec.push_back({rec[0], rec[1], INT_MAX});
            n = max(n, rec[1]);//记录最大高度,根据高度建树,后面修改的也是高度的值
        }
        for (int i = 0; i < points.size(); i++) { //遍历所有点
            vec.push_back({points[i][0], points[i][1], i});//把点放到矩形后面,并做好标志,记录位置
            n = max(n, points[i][1]);
        }
        tree = vector<int>(n + 1); //建立树
        sort(vec.begin(), vec.end()); //按长度进行排序,固定长度的访问顺序,然后只用看高于点高度的矩形个数前缀和即可

        vector<int> ans(points.size());//存储结果
        for (int i =  vec.size() - 1; i >= 0; i--) //从后往前遍历,因为对于点,要找高度更大的
            if (vec[i][2] == INT_MAX) updata(vec[i][1],1); //碰到矩形进行单点修改
            else ans[vec[i][2]] = getsum(n) - getsum(vec[i][1] - 1); //碰到点,计算高于当前高度的前缀和
        return ans;
    }

    int n;
    vector<int> tree;
    int lowbit(int x){//求二进制化最后一位的值
        return x&(-x);
    }
    void updata(int i,int k){ //在i位置加上k,O(logn)复杂度单点修改
        while(i<=n){//更新子树上所有值
            tree[i]+=k;
            i+=lowbit(i);//移动到父亲节点
        }
    }

    long long getsum(int i){  //求数组前i项的和
        long long res=0;
        while(i>0){//O(logn)求前缀和
            res+=tree[i];
            i-=lowbit(i);//移动到前一棵子树(子区间)
        }
        return res;
    }
};


posted @ 2023-05-18 16:12  失控D大白兔  阅读(34)  评论(0编辑  收藏  举报