返回
最小面积正方形:滑动窗口高效求解K点覆盖问题
java
2025-01-27 19:12:33
求解包含K个点的最小面积正方形
给定平面上的N个点,我们需要找出能够包含至少K个点的最小面积正方形。正方形的边需要与坐标轴平行,并且其顶点坐标均为整数。位于正方形边界上的点不被视为正方形内部的点。
这是一个比较常见的几何问题,核心挑战是如何高效地找到满足条件的最小正方形。 暴力枚举所有可能的K点组合在数据量较大时是不可行的,必须另辟蹊径。
暴力解法及问题
一个比较直接的思路是,遍历所有可能的K点组合,然后计算包含这K个点的最小正方形,并记录面积最小值。给出的代码展示了当 K 等于 N 时的一种优化方案,也就是将所有的点包含在一个最小正方形里。 这个解法找到所有点中的最大值和最小值,从而确定正方形的边长。
代码如下:
static int minarea(int[] x, int[] y, int k) {
//Find max y
int maxVal = Integer.MIN_VALUE;
for(int i : y){
if(i > maxVal){
maxVal = i;
}
}
//Find min y
int minVal = Integer.MAX_VALUE;
for(int i : x){
if(i < minVal){
minVal = i;
}
}
int yLength = (maxVal-minVal)+2;
//Find max x
maxVal = Integer.MIN_VALUE;
for(int i : x){
if(i > maxVal){
maxVal = i;
}
}
//Find min x
minVal = Integer.MAX_VALUE;
for(int i : x){
if(i < minVal){
minVal = i;
}
}
int xLength = (maxVal-minVal)+2;
int sqSide = (yLength > xLength)?yLength:xLength;
return sqSide*sqSide;
}
操作步骤:
- 传递点集的X坐标数组、Y坐标数组和点的总数
K
。 - 分别求出X和Y坐标数组中的最大值与最小值。
- 计算正方形在X和Y轴方向上的边长
xLength
和yLength
。需要注意的是,此处要加上 2 是因为正方形边上的点不计算在内。 - 选取
xLength
和yLength
之间的较大者作为正方形的边长sqSide
,再求边长的平方即得最小正方形面积。
然而,正如预期的,这种思路当K 小于 N时 复杂度是指数级别的,非常不高效, 需要寻求更有效的算法。
基于滑窗的优化解法
为了避免暴力枚举,可以考虑一种滑动窗口的思路,使用两个嵌套的循环遍历所有点。 可以考虑先排序X轴上的坐标,接着固定两个 X坐标定义一个矩形区域的左右边界。再用一个窗口,滑动选择矩形上下边界。此过程中,判断落在此矩形内的点的个数是否满足至少K个。如果满足,就不断缩小这个矩形的面积并持续比较,直到找到符合条件的最小面积。
代码示例(伪代码,需要根据实际语言调整) :
function minAreaSquare(points, K):
Sort points by X-coordinate.
min_area = Infinity
for i from 0 to length(points) - 1:
for j from i to length(points) - 1:
x1 = points[i][0] //左边界 X
x2 = points[j][0] //右边界 X
sort points by Y-coordinate.
l=0
r=-1 // 滑窗起始
while r < points.length() -1:
r+=1
current_points_inside = 0
for point in points:
if point[0]> x1 && point[0] < x2 && point[1] > points[l][1] && point[1] < points[r][1] :
current_points_inside = current_points_inside +1;
while current_points_inside>=K :
current_area =(x2-x1+2)*(points[r][1]-points[l][1] +2)
min_area = min(min_area, current_area)
l+=1
current_points_inside = 0
for point in points:
if point[0]> x1 && point[0] < x2 && point[1] > points[l][1] && point[1] < points[r][1]:
current_points_inside = current_points_inside+1;
return min_area
操作步骤:
- 将所有点按照 x 坐标进行排序。
- 外层两个循环遍历所有的 x 坐标组合,以确定正方形左右边界,生成一系列水平矩形。
- 内层通过 滑窗, 动态选取 Y坐标确定正方形的上下边界, 判断当前矩形内的点数,并比较是否有满足条件的面积。
代码解释:
- 排序: 按x坐标排序是为了在滑动窗口中使用单调性。
- 枚举左右边界: 外层两个循环
i
和j
用于遍历所有可能的x坐标组合。这样固定了一个矩形的左右边界。 - 按Y坐标排序 需要再次按Y轴排序。
- 滑窗处理上下边界 : 使用两个指针
l
和r
模拟一个滑窗。逐步移动r
,当窗口中的点数大于等于K
的时候,滑动l
,找到当前的局部最优解。 - 计算面积和更新最小值: 检查当前窗口中点数是否大于等于K,如果符合要求,更新面积最小值。
注意事项:
-
滑窗的关键在于逐步探索有效区域,同时维护所需的数据结构。
-
对于大数据集,需要评估上述方法的运行效率并根据情况选择是否需要额外的数据结构进行优化。
-
在生产环境中,务必对输入的边界条件和极端情况进行检查,防止异常错误发生。
以上介绍了一种通用的算法思路,并提供了一个伪代码实例。对于特定语言,开发者需要结合自身情况实现具体代码, 并根据需求优化,解决问题。