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;
}
};