华为机试:信号塔最优布置算法解析
·
1. 题目背景与核心需求解析
这道题目来自华为2025年秋招非AI方向的机试题库,属于典型的算法优化类问题。题目要求在城市中布置信号塔时,找到所有相邻信号塔之间的最小距离的最大可能值。这实际上是一个在约束条件下求最优解的问题,在通信基站部署、物流仓储规划等领域都有实际应用价值。
1.1 问题形式化描述
给定一个有序数组表示城市道路的位置(假设道路是直线型的),需要在这些位置上布置一定数量的信号塔。要求所有相邻信号塔之间的距离都不小于某个值d,我们的目标是找到这个d的最大可能值。
输入格式:
- 道路位置数组(已排序):positions = [x1, x2, ..., xn]
- 需要布置的信号塔数量:k
输出:
- 相邻信号塔之间的最小距离的最大可能值
1.2 实际应用场景
这个问题在实际中有多个应用场景:
- 通信基站部署:确保基站覆盖范围不重叠的同时最大化覆盖区域
- 物流仓库选址:在一条运输线上合理分布仓库,降低运输成本
- 城市设施规划:如公交站、消防站等公共设施的合理布局
2. 解题思路与算法选择
2.1 暴力搜索法的局限性
最直观的想法是尝试所有可能的信号塔布置组合,然后找出其中满足条件的最小距离的最大值。但是这种方法的时间复杂度是组合数C(n,k),当n和k较大时(比如n=10000,k=5000),计算量会变得不可接受。
2.2 二分查找与贪心算法的结合
更高效的解法是结合二分查找和贪心算法:
- 首先确定搜索范围:最小距离d的可能取值在0到positions[-1]-positions[0]之间
- 使用二分查找在这个范围内搜索可能的d值
- 对于每个候选的d值,使用贪心算法验证是否可以布置k个信号塔
2.3 算法正确性证明
这种方法的正确性基于以下观察:
- 如果某个d值可行,那么所有小于d的值也都可行
- 如果某个d值不可行,那么所有大于d的值也都不可行
- 这满足二分查找的应用条件,可以高效地找到边界值
3. 代码实现与解析
3.1 Java实现
import java.util.Arrays;
public class Solution {
public int maxMinDistance(int[] positions, int k) {
Arrays.sort(positions);
int left = 0;
int right = positions[positions.length - 1] - positions[0];
int result = 0;
while (left <= right) {
int mid = left + (right - left) / 2;
if (canPlace(positions, k, mid)) {
result = mid;
left = mid + 1;
} else {
right = mid - 1;
}
}
return result;
}
private boolean canPlace(int[] positions, int k, int d) {
int count = 1;
int last = positions[0];
for (int i = 1; i < positions.length; i++) {
if (positions[i] - last >= d) {
count++;
last = positions[i];
if (count >= k) return true;
}
}
return count >= k;
}
}
3.2 C++实现
#include <vector>
#include <algorithm>
using namespace std;
class Solution {
public:
int maxMinDistance(vector<int>& positions, int k) {
sort(positions.begin(), positions.end());
int left = 0;
int right = positions.back() - positions.front();
int result = 0;
while (left <= right) {
int mid = left + (right - left) / 2;
if (canPlace(positions, k, mid)) {
result = mid;
left = mid + 1;
} else {
right = mid - 1;
}
}
return result;
}
private:
bool canPlace(vector<int>& positions, int k, int d) {
int count = 1;
int last = positions[0];
for (int i = 1; i < positions.size(); i++) {
if (positions[i] - last >= d) {
count++;
last = positions[i];
if (count >= k) return true;
}
}
return count >= k;
}
};
3.3 Python实现
def max_min_distance(positions, k):
positions.sort()
left, right = 0, positions[-1] - positions[0]
result = 0
while left <= right:
mid = (left + right) // 2
if can_place(positions, k, mid):
result = mid
left = mid + 1
else:
right = mid - 1
return result
def can_place(positions, k, d):
count = 1
last = positions[0]
for i in range(1, len(positions)):
if positions[i] - last >= d:
count += 1
last = positions[i]
if count >= k:
return True
return count >= k
4. 算法复杂度分析
4.1 时间复杂度
- 排序阶段:O(n log n),其中n是道路位置的数量
- 二分查找阶段:O(log(max_dist)),其中max_dist是最大可能距离
- 每次验证:O(n) 总体时间复杂度为O(n log n + n log(max_dist)),对于大多数实际应用场景,这已经足够高效
4.2 空间复杂度
除了输入数据外,算法只需要常数级别的额外空间,因此空间复杂度是O(1)
5. 边界条件与测试用例
5.1 典型测试用例
-
基础用例:
- 输入:[1,2,3,4,5], k=3
- 输出:2(布置在1,3,5位置)
-
所有位置都相同:
- 输入:[5,5,5,5], k=2
- 输出:0(只能布置在相同位置)
-
最大距离用例:
- 输入:[1,10,100,1000], k=2
- 输出:999(布置在1和1000位置)
5.2 特殊边界情况
- k=1:可以布置在任何位置,返回任意大值(实际应返回无穷大,但根据题目约束可能返回特定值)
- k=n:必须在每个位置都布置信号塔,返回最小相邻距离
- 空数组或k=0:根据题目要求处理异常情况
6. 算法优化与变种
6.1 提前终止优化
在canPlace函数中,一旦count达到k就可以提前返回true,不需要继续遍历剩余位置。这个小优化可以在某些情况下显著减少实际运行时间。
6.2 变种问题
- 多维空间布置:将问题扩展到二维或三维空间
- 带权重布置:不同位置布置信号塔的成本不同
- 动态布置:道路位置会随时间变化
7. 实际工程应用建议
7.1 性能优化
对于大规模数据(n>1e6),可以考虑以下优化:
- 使用更高效的排序算法(如基数排序,如果数据范围有限)
- 并行化验证过程
- 使用近似算法快速得到初步解
7.2 工程实现注意事项
- 输入验证:确保positions数组已排序,k值合法
- 数值溢出:对于大整数情况,使用long类型
- 浮点数处理:如果位置坐标是浮点数,需要调整比较方式
8. 常见错误与调试技巧
8.1 常见错误
- 忘记排序输入数组
- 二分查找边界条件处理不当
- 贪心验证时计数逻辑错误
- 整数溢出问题
8.2 调试建议
- 打印中间结果:在二分查找过程中打印left, right, mid值
- 小规模测试:先用小数据验证算法正确性
- 边界测试:专门测试k=1, k=n等边界情况
9. 华为机试准备建议
9.1 算法准备重点
- 掌握基础算法:排序、二分查找、贪心算法
- 熟悉常见算法模板:如本题的二分答案模板
- 练习代码实现速度:华为机试有时间限制
9.2 解题技巧
- 先理解题意,明确输入输出
- 思考暴力解法,再考虑优化
- 注意边界条件和特殊输入
- 编写清晰的代码,适当添加注释
10. 扩展学习资源
- 《算法导论》中的二分查找和贪心算法章节
- LeetCode类似题目:
-
- Koko Eating Bananas
-
- Capacity To Ship Packages Within D Days
-
- Divide Chocolate
-
- 华为OJ其他题目练习
在实际工程应用中,这类问题经常出现在资源分配、设施布局等场景。掌握这种二分答案的思路,可以解决一大类"最大化最小值"或"最小化最大值"的问题。建议读者在理解本题的基础上,尝试解决上面提到的LeetCode类似题目,加深对这种解题模式的理解。
更多推荐



所有评论(0)