问题描述
在一条笔直的公路上安装了 N 个路灯,从位置 0 开始安装,路灯之间的间距固定为 100 米。每个路灯都有自己的照明半径,请计算第一个路灯和最后一个路灯之间,未被照明的区间的长度和。
问题说明
路灯个数 N:1<=N<=100000; 照明半径:1<=照明半径<=100000*100
思路
- 想象各个路灯都是横坐标上的点,计算各个路灯的照亮区间;
- 按照区间的左边界,排序各个照亮区间;
- 合并交叉的区间;
- 最后,合并后的区间之间间隔的长度之和,就是未被照明的总长度。
代码实现
/** 路灯数量n,路灯照亮半径数组radiusList */
function getDarkRange(n, radiusList) {
// 1. 计算每个路灯的照亮区间
let rangeArr = [];
for (let i = 0; i < n; i++) {
let left = i * 100 - radiusList[i];
let right = i * 100 + radiusList[i];
rangeArr.push([Math.max(0, left), Math.min(100 * n, right)]);
}
// 2. 按区间的左边界排序
rangeArr.sort((a, b) => a[0] - b[0]);
// 3. 合并区间
let mergedArr = [];
let [left, right] = rangeArr[0];
for (let i = 1; i < rangeArr.length; i++) {
let [lPos, rPos] = rangeArr[i];
if (lPos <= right && rPos > right) {
right = rPos;
continue;
}
if (lPos > right) {
mergedArr.push([left, right]);
left = lPos;
right = rPos;
}
}
mergedArr.push([left, right]);
// 4. 累加间隔
let ans = 0;
for (let i = 0; i < mergedArr.length - 1; i++) {
ans += mergedArr[i + 1][0] - mergedArr[i][1];
}
return ans;
}
复杂度
- 空间复杂度:O(N), 两个大块 rangeArr 和 mergedArr,都是 O(N)级别的占用;
- 时间复杂度:O(Nlog(N)),来源于区间排序,其余部分的遍历都是 O(N)的时间复杂度;
心得体会
- 思考为什么要先排序,再合并区间;
- 体会合并区间的过程起到的效果;