路灯照明问题

27 阅读1分钟

问题描述

在一条笔直的公路上安装了 N 个路灯,从位置 0 开始安装,路灯之间的间距固定为 100 米。每个路灯都有自己的照明半径,请计算第一个路灯和最后一个路灯之间,未被照明的区间的长度和。

问题说明

路灯个数 N:1<=N<=100000; 照明半径:1<=照明半径<=100000*100

思路

  1. 想象各个路灯都是横坐标上的点,计算各个路灯的照亮区间;
  2. 按照区间的左边界,排序各个照亮区间;
  3. 合并交叉的区间;
  4. 最后,合并后的区间之间间隔的长度之和,就是未被照明的总长度。

代码实现

/** 路灯数量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)的时间复杂度;

心得体会

  • 思考为什么要先排序,再合并区间;
  • 体会合并区间的过程起到的效果;