Medium
题目描述
给你一个二维整数数组 points,其中 points[i] = [xi, yi]。同时给你一个整数 w。你需要用矩形覆盖所有给定的点。
每个矩形的下端位于某个点 (x1, 0),上端位于某个点 (x2, y2),其中 x1 <= x2,y2 >= 0,且每个矩形必须满足条件 x2 - x1 <= w。
如果一个点位于矩形内部或边界上,则认为该点被矩形覆盖。
返回使得每个点都至少被一个矩形覆盖所需的最小矩形数量。
注意:一个点可以被多个矩形覆盖。
示例 1:
输入:points = [[2,1],[1,0],[1,4],[1,8],[3,5],[4,6]], w = 1
输出:2
示例 2:
输入:points = [[0,0],[1,1],[2,2],[3,3],[4,4],[5,5],[6,6]], w = 2
输出:3
示例 3:
输入:points = [[2,3],[1,2]], w = 0
输出:2
约束条件:
1 <= points.length <= 10^5points[i].length == 20 <= xi == points[i][0] <= 10^90 <= yi == points[i][1] <= 10^90 <= w <= 10^9- 所有的
(xi, yi)都是不同的
解题思路
这是一个典型的贪心算法问题。关键观察是:
y坐标无关性:矩形的高度可以任意调整(从0到最大y值),因此y坐标不影响矩形的数量,只有x坐标是关键因素。
贪心策略:将所有点按x坐标排序后,使用贪心算法:
- 选择最左边未覆盖的点作为当前矩形的起点
- 尽可能向右扩展矩形,覆盖所有在宽度w范围内的点
- 重复这个过程直到所有点都被覆盖
算法流程:
- 提取所有不重复的x坐标并排序
- 从最小的x坐标开始,每次选择一个矩形的左端点
- 该矩形可以覆盖从当前x到x+w范围内的所有点
- 跳过已覆盖的点,继续处理下一个未覆盖的x坐标
这种贪心策略是最优的,因为每个矩形都尽可能覆盖更多的点,不会造成浪费。
代码实现
class Solution {
public:
int minRectanglesToCoverPoints(vector<vector<int>>& points, int w) {
vector<int> xCoords;
for (const auto& point : points) {
xCoords.push_back(point[0]);
}
sort(xCoords.begin(), xCoords.end());
xCoords.erase(unique(xCoords.begin(), xCoords.end()), xCoords.end());
int rectangles = 0;
int i = 0;
while (i < xCoords.size()) {
int start = xCoords[i];
rectangles++;
while (i < xCoords.size() && xCoords[i] <= start + w) {
i++;
}
}
return rectangles;
}
};
class Solution:
def minRectanglesToCoverPoints(self, points: List[List[int]], w: int) -> int:
x_coords = sorted(set(point[0] for point in points))
rectangles = 0
i = 0
while i < len(x_coords):
start = x_coords[i]
rectangles += 1
while i < len(x_coords) and x_coords[i] <= start + w:
i += 1
return rectangles
public class Solution {
public int MinRectanglesToCoverPoints(int[][] points, int w) {
var xCoords = points.Select(p => p[0]).Distinct().OrderBy(x => x).ToList();
int rectangles = 0;
int i = 0;
while (i < xCoords.Count) {
int start = xCoords[i];
rectangles++;
while (i < xCoords.Count && xCoords[i] <= start + w) {
i++;
}
}
return rectangles;
}
}
var minRectanglesToCoverPoints = function(points, w) {
const xCoords = [...new Set(points.map(point => point[0]))].sort((a, b) => a - b);
let rectangles = 0;
let i = 0;
while (i < xCoords.length) {
const start = xCoords[i];
rectangles++;
while (i < xCoords.length && xCoords[i] <= start + w) {
i++;
}
}
return rectangles;
};
复杂度分析
| 复杂度类型 | 复杂度 |
|---|---|
| 时间复杂度 | O(n log n) |
| 空间复杂度 | O(n) |
其中 n 是点的数量。时间复杂度主要来自排序操作,空间复杂度来自存储去重后的x坐标。
相关题目
. Minimum Area Rectangle (Medium)
. K Closest Points to Origin (Medium)