Medium级别的题:给定2维平面上若干个点,其一个最宽的条形区域(高度为无限长)使得其中不包含任何点——注意点在边界上不算包含。
数据范围:点数n满足2 <= n <= 100000, 所有点都是整点,坐标是不超过1000000000的非负整数。
例如:输入{{8, 7}, {9, 9}, {7, 4}, {9, 7}}返回1,如下图所示。
分析:无聊题,只有x坐标有意义——其实是求所有x值排序后相邻两个值的差最大值。其实题目没说清楚,如果所有点x相同,答案应该是无穷大,而非0……
代码:
class Solution {public: int maxWidthOfVerticalArea(vector<vector<int>>& points) { sort(points.begin(), points.end()); int r = 0; for (int i = 1; i < points.size(); ++i) { r = max(r, points[i][0] - points[i - 1][0]); } return r; }};
其实还有一种线性的分桶解法。利用抽屉原理,如果把n个点放入m个桶中,如果m > n,则至少有一个空桶。这里我们设mini和maxi分别是所有x值的最小和最大值。如果mini == maxi直接输出0(其实是无穷大)。
否则,我们把闭区间[mini, maxi]平均分成(n + 1)段。每段长度为(maxi - mini) / (n + 1) (不是整数除法,是实数,有理数)。
每一段是一个左闭右开的区间作为一个桶,为了方便,也为了每个点都在一个唯一的桶里,我们再设置一个长度为0的桶,即maxi本身在一个长度为0的桶里——因为是左闭右开的区间, maxi不在之前任何一个桶里。
于是我们有(n + 2)个桶。 每个x值放在一个桶里,对应编号为[(x - mini) * (n + 1) / (maxi - mini)] (下标从0开始,下取整)。
这些桶有很好的性质:
(1) 0号桶非空——因为mini在0号桶
(2) (n + 1)号桶非空——因为maxi在这个桶,这也是我们设置的changed为0的桶。
(3) 中间必然至少有一个空桶,因为桶的数量比点的数量多。
这就告诉我们如果所有点排好序后,相邻的点差值的最大值一定不会小于桶的宽度——因为空桶左和右第一个点是相邻的,并且它们的距离不小于桶的宽度。 于是,我们可以对每个桶分别求最小值和最大值,然后枚举当前桶内的小值和之前最近那个非空桶内的最大值之间的差值即可……
代码:
class Solution {public: int maxWidthOfVerticalArea(vector<vector<int>>& points) { int mini = 1234567890, maxi = 0; for (const auto& p : points) { mini = min(mini, p[0]); maxi = max(maxi, p[0]); } if (mini == maxi) return 0; const long long n = points.size(); const int d = maxi - mini; vector<vector<int>> v(n + 2); for (const auto& p : points) { int ind; auto& arr = v[ind = (n + 1) * (p[0] - mini) / d]; if (arr.empty()) { arr = {p[0], p[0]}; } else { arr[0] = min(arr[0], p[0]); arr[1] = max(arr[1], p[0]); } } int r = 0; for (int i = 1, last = v[0][1]; i < v.size(); ++i) { if (!v[i].empty()) { r = max(r, v[i][0] - last); last = v[i][1]; } } return r; }};