1. 问题描述与理解
最近在准备华为秋招时遇到一道关于信号塔最小距离计算的算法题,题目大意是:给定平面上N个信号塔的坐标(二维点),要求找出所有信号塔对中距离平方最小的那个值。这里的距离平方定义为(x1-x2)² + (y1-y2)²。
这个问题实际上是计算几何中经典的"最近点对"问题的变种。在实际工程中,这种算法可以应用于基站部署优化、无线网络规划等场景。比如在5G网络建设中,需要合理规划基站位置以避免信号干扰,这时候就需要快速计算出最近的基站对。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 暴力解法与复杂度分析
最直观的解法是暴力枚举所有点对,计算它们的距离平方并记录最小值。对于一个包含n个点的集合,这样的时间复杂度是O(n²)。
python复制def brute_force(points):
min_dist = float('inf')
n = len(points)
for i in range(n):
for j in range(i+1, n):
dx = points[i][0] - points[j][0]
dy = points[i][1] - points[j][1]
dist_sq = dx*dx + dy*dy
if dist_sq < min_dist:
min_dist = dist_sq
return min_dist
虽然这种方法简单直接,但当n较大时(比如n=10^5),O(n²)的时间复杂度是完全不可接受的。我们需要寻找更高效的算法。
3. 分治算法设计
3.1 基本思路
分治法是将问题分解为更小的子问题,递归求解后再合并结果。对于最近点对问题,我们可以:
- 将所有点按x坐标排序
- 将平面垂直划分为左右两部分,点数大致相等
- 递归计算左右两部分的最小距离
- 合并时考虑跨越左右两部分的点对可能产生更小距离
3.2 关键步骤详解
3.2.1 预处理排序
首先需要对所有点按x坐标排序,这可以在O(n log n)时间内完成。排序后我们可以方便地将点集划分为左右两部分。
java复制// Java示例:按x坐标排序
Arrays.sort(points, (a, b) -> Double.compare(a[0], b[0]));
3.2.2 递归基处理
当点集规模很小时(比如n≤3),直接使用暴力法计算最小距离。这是递归的终止条件。
cpp复制// C++示例:处理小规模情况
if (points.size() <= 3) {
return bruteForce(points);
}
3.2.3 分割平面
找到中间点的x坐标作为分割线,将点集分为左右两部分:
python复制mid = len(points) // 2
mid_point = points[mid]
left = points[:mid]
right = points[mid:]
3.2.4 递归求解
分别递归计算左右两部分的最小距离:
java复制double leftMin = closestPair(left);
double rightMin = closestPair(right);
double minDist = Math.min(leftMin, rightMin);
3.2.5 合并处理
这是算法最关键的步骤。我们需要检查距离分割线不超过minDist的点(称为"条带"区域),这些点可能形成比当前minDist更小的点对。
python复制strip = []
for point in points:
if (point[0] - mid_point[0])**2 < min_dist:
strip.append(point)
然后对这些条带内的点按y坐标排序,只需检查每个点后面最多7个点即可:
cpp复制// 按y坐标排序
sort(strip.begin(), strip.end(), [](const P
