Maximum Area Rectangle With Point Constraints II

Maximum Area Rectangle With Point Constraints II

There are n points on an infinite plane. You are given two integer arrays xCoord and yCoord where (xCoord[i], yCoord[i]) represents the coordinates of the ith point.

Your task is to find the maximum area of a rectangle that:

  • Can be formed using four of these points as its corners.
  • Does not contain any other point inside or on its border.
  • Has its edges parallel to the axes.

Return the maximum area that you can obtain or -1 if no such rectangle is possible.

 

Example 1:

Input: xCoord = [1,1,3,3], yCoord = [1,3,1,3]

Output: 4

Explanation:

We can make a rectangle with these 4 points as corners and there is no other point that lies inside or on the border. Hence, the maximum possible area would be 4.

Example 2:

Input: xCoord = [1,1,3,3,2], yCoord = [1,3,1,3,2]

Output: -1

Explanation:

There is only one rectangle possible is with points [1,1], [1,3], [3,1] and [3,3] but [2,2] will always lie inside it. Hence, returning -1.

Example 3:

Input: xCoord = [1,1,3,3,1,3], yCoord = [1,3,1,3,2,2]

Output: 2

Explanation:

The maximum area rectangle is formed by the points [1,3], [1,2], [3,2], [3,3], which has an area of 2. Additionally, the points [1,1], [1,2], [3,1], [3,2] also form a valid rectangle with the same area.

 

Constraints:

1 <= xCoord.length == yCoord.length <= 2 * 105

0 <= xCoord[i], yCoord[i] <= 8 * 107

All the given points are unique.

 

解题思路

  赛时想复杂了,罚坐了一个多小时都没做出来。

  考虑枚举每一个点作为矩阵的右上角(对应矩阵坐标系的右下角)。假设当前枚举到的右上角的点是 (x2,y2),由于矩形的边要与坐标轴平行,因此矩形左上角的点的纵坐标应该是 y2,那么我们从所有纵坐标是 y2 的点中,找到小于 x2 的最大横坐标(否则矩形的边上会包含其他点),记为 x1。同理矩形右下角的点的横坐标应该是 x2,从所有横坐标是 x2 的点中,找到小于 y2 的最大纵坐标,记为 y1。这样我们也确定了矩形左下角的点 (x1,y1)。当然上述矩形存在的条件是点 (x2,y2)(x1,y2)(x2,y1)(x1,y1) 要同时存在。

  那么我们如何快速找到纵坐标是 y2 的所有点中,横坐标小于 x2 的最大值?我们可以给所有纵坐标值开一个 std::set 用来存储纵坐标相同的点的横坐标,每次查询的时候二分即可。同理给所有横坐标值开一个哈希表存储横坐标相同的点的纵坐标。另外还可以以横坐标为第一关键字,纵坐标为第二关键字来从小到大枚举每个点,并维护每个横坐标最大的纵坐标,每个纵坐标最大的横坐标。

  最后的问题是确定了矩形的左下角 (x1,y1),右上角 (x2,y2) 后,然后快速判定矩形内是否含有其他的点?这个可以用二维数点的做法实现。参考二维前缀和,把询问的矩形 (x1,y1,x2,y2) 拆成 4 个部分:R1:(1,1,x2,y2)R2:(1,1,x11,y2)R3:(1,1,x2,y11)R4:(1,1,x11,y11)。用 C(R) 表示矩形 R 内点的数量,那么矩形 (x1,y1,x2,y2) 内点的数量等价于 C(R1)C(R2)C(R3)+C(R4)

  我们把所有询问的矩形都拆成这 4 个部分,并以四元组 (x,y,k,i) 的形式表示,其中 x,y 表示拆分后的矩形的右上角的坐标(因为所有拆分矩形的左下角都是 (1,1) 因此忽略),k 是系数 11,对应要减去还是加上这个矩形内点的数量,i 是这个拆分出来的矩形对应原本第 i 个询问的矩形。然后对四元组从小到大排序,在枚举的过程中用树状数组来维护所有横坐标小于等于当前四元组对应的 x 的点的纵坐标,然后在树状数组中查询所有纵坐标不超过 y 的点的数量,就是这个矩形 (1,1,x,y) 内点的数量。

  最后如果矩形内点的数量恰好等于 4(因为有 4 个端点),说明这是一个合法矩形。

  AC 代码如下,时间复杂度为 O(nmlognm)

class Solution {
public:
    long long maxRectangleArea(vector<int>& xCoord, vector<int>& yCoord) {
        int n = xCoord.size();
        set<array<int, 2>> st;
        vector<int> xs;
        for (int i = 0; i < n; i++) {
            st.insert({xCoord[i], yCoord[i]});
            xs.push_back(yCoord[i]);
        }
        sort(xs.begin(), xs.end());
        xs.erase(unique(xs.begin(), xs.end()));
        map<int, int> r, c;
        vector<array<int, 4>> p, q;
        auto find = [&](int x) {
            return lower_bound(xs.begin(), xs.end(), x) - xs.begin() + 1;
        };
        for (auto &[x, y] : st) {
            if (r.count(x) && c.count(y) && st.count({c[y], r[x]})) {
                int x1 = c[y], y1 = find(r[x]), x2 = x, y2 = find(y);
                p.push_back({x1, y1, x2, y2});
                q.push_back({x2, y2, 1, int(p.size()) - 1});
                q.push_back({x1 - 1, y2, -1, int(p.size()) - 1});
                q.push_back({x2, y1 - 1, -1, int(p.size()) - 1});
                q.push_back({x1 - 1, y1 - 1, 1, int(p.size()) - 1});
            }
            r[x] = y, c[y] = x;
        }
        sort(q.begin(), q.end());
        vector<int> s(p.size()), tr(xs.size() + 1);
        auto lowbit = [&](int x) {
            return x & -x;
        };
        auto add = [&](int x) {
            for (int i = x; i <= xs.size(); i += lowbit(i)) {
                tr[i]++;
            }
        };
        auto query = [&](int x) {
            int ret = 0;
            for (int i = x; i; i -= lowbit(i)) {
                ret += tr[i];
            }
            return ret;
        };
        for (int i = 0; i < q.size(); i++) {
            while (!st.empty() && st.begin()->at(0) <= q[i][0]) {
                add(find(st.begin()->at(1)));
                st.erase(st.begin());
            }
            s[q[i][3]] += query(q[i][1]) * q[i][2];
        }
        long long ret = -1;
        for (int i = 0; i < p.size(); i++) {
            if (s[i] == 4) ret = max(ret, 1ll * (p[i][2] - p[i][0]) * (xs[p[i][3] - 1] - xs[p[i][1] - 1]));
        }
        return ret;
    }
};

 

参考资料

  静态二维数点问题【力扣周赛 427】:https://www.bilibili.com/video/BV1YeqHYSEhK/

posted @   onlyblues  阅读(32)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
历史上的今天:
2023-12-09 [HNOI2009] 梦幻布丁
Web Analytics
点击右上角即可分享
微信分享提示