
本文介绍一种高效、可复用的 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 并注意小数比较精度问题。










