如何使用 JavaScript 检测时间线区间重叠并动态分配非重叠编号范围

15次阅读

如何使用 JavaScript 检测时间线区间重叠并动态分配非重叠编号范围

本文介绍一种高效、可复用的 javascript 方法,用于判断二维数组中多个时间区间(起始/结束值)是否相互重叠,并基于重叠关系为每个条目分配连续且不冲突的编号范围(如 `1-30`、`31-60`),适用于调度系统、甘特图或资源排期等场景。

在实际开发中(如课程排期、任务甘特图、音视频轨道管理),我们常需判断多个时间区间是否存在重叠,并据此动态分配唯一、连续的“槽位编号”(如编号 1–30 表示第一个 30 单位资源块)。核心逻辑是:若当前区间与任意已处理区间重叠,则延续前序编号范围;否则,从下一个可用编号开始分配新范围

以下是一个健壮、易理解的实现方案:

function checkTimelineOverlap(timelineArray) {   const result = [];   let currentStart = 1;   let currentEnd = 0; // 初始末尾设为 0,确保首个无重叠项从 1 开始    for (let i = 0; i < timelineArray.length; i++) {     const [name, startStr, endStr, incrementStr] = timelineArray[i];     const startNum = parseInt(startStr, 10);     const endNum = parseInt(endStr, 10);     const incrementNum = parseInt(incrementStr, 10);      // 检查是否与之前任一区间重叠(标准区间重叠判定)     const overlapNames = [];     for (let j = 0; j < i; j++) {       const [prevName, prevStartStr, prevEndStr] = timelineArray[j];       const prevStart = parseInt(prevStartStr, 10);       const prevEnd = parseInt(prevEndStr, 10);        // 重叠条件:两区间有交集 ⇔ !(A 在 B 左侧 或 A 在 B 右侧)       // 即:!(endNum < prevStart || startNum > prevEnd)       if (!(endNum < prevStart || startNum > prevEnd)) {         overlapNames.push(prevName);       }     }      const overlapMessage = overlapNames.length > 0       ? `overlap with ${overlapNames.join(", ")}`       : "no overlap";      if (overlapNames.length > 0) {       // 重叠 → 延续编号:从 currentEnd + 1 开始,长度为 incrementNum       currentStart = currentEnd + 1;       currentEnd = currentStart + incrementNum - 1;     } else {       // 无重叠 → 重置编号:从 1 开始分配新块       currentStart = 1;       currentEnd = incrementNum;     }      result.push(`${name}, ${overlapMessage}, ${currentStart}-${currentEnd}`);   }    return result; }

关键改进点说明:

  • 正确重叠判定:使用 !(end prevEnd) 替代冗余三条件,逻辑更简洁、无遗漏(覆盖包含、相交、被包含所有情况);
  • 编号分配策略清晰:无重叠时强制重置为 1–N;有重叠时严格接续前一个 currentEnd + 1,避免跳跃或回退;
  • 数值安全:显式指定 parseInt(str, 10),防止八进制误解析;
  • 语义明确:变量命名(currentStart/currentEnd)直指编号范围状态,便于维护。

? 使用示例:

立即学习Java免费学习笔记(深入)”;

const timelineArray = [   ["name1", "384", "456", "30"],   ["name2", "72", "192", "30"],   ["name3", "384", "456", "30"],   ["name4", "384", "456", "15"],   ["name5", "384", "576", "30"],   ["name6", "96", "240", "12"],   ["name7", "384", "456", "12"] ];  console.log(checkTimelineOverlap(timelineArray)); // 输出符合预期: // [ //   "name1, no overlap, 1-30", //   "name2, no overlap, 1-30", //   "name3, overlap with name1, 31-60", //   "name4, overlap with name1, name3, 61-75", //   "name5, overlap with name1, name3, name4, 76-105", //   "name6, overlap with name2, 31-42", //   "name7, overlap with name1, name3, name4, name5, 106-117" // ]

⚠️ 注意事项:

  • 算法按数组顺序依次处理,因此输入顺序直接影响结果(例如将 name2 放在 name1 前,其编号范围仍为 1–30);若需全局最优排布,应先按时间区间排序(如按 start 升序);
  • 当前逻辑假设 increment 表示本条目所需编号长度(而非固定偏移量),请确保业务语义一致;
  • 如需支持浮点时间戳或毫秒级精度,将 parseInt 替换为 parseFloat 并注意小数比较精度问题。

通过此方案,你可快速集成到前端排期组件或 node.js 后端服务中,实现可靠、可预测的时间线资源编号分配。

text=ZqhQzanResources