【问题标题】:Find all non-overlapping intervals within another interval查找另一个区间内的所有非重叠区间
【发布时间】:2022-01-26 15:46:15
【问题描述】:

我有一个区间数组,另一个区间定义为范围。目标是创建一个数组数组,其中包含所有不重叠但在定义范围内的区间的开始和结束编号。

最初的用途是我有一个服务器为数十万个对象提供服务,这些对象的时间戳彼此相隔一秒。可以使用任意两个时间戳发出请求,因此我需要存储来自服务器的查询对象,并且下次使用两个不同时间戳发出请求时,仅查询丢失的对象。这个问题使用小数字来简化事情。

输入:

const intervals = [
  [3, 5],
  [7, 9],
];

const range = [2, 11];

这种情况下的输出是[[2, 3], [5, 7], [9, 11]]

间隔总是按开始日期排序,输入间隔中永远不会重叠,因为合并和排序是先完成的,根据这个答案https://stackoverflow.com/a/67717721/13585195

我已经设法为这个特定案例提出了一个解决方案,但是在尝试涵盖其他案例时会出现问题,例如:

  1. 输入:间隔:[[3, 5]]; 范围:[4, 8]; 输出:[[5, 8]]
  2. 输入:间隔:[[7, 11]]; 范围:[2, 8]; 输出:[[2, 7]]
  3. 输入:间隔:[[3, 5], [6, 8]]; 范围:[4, 7]; 输出:[[5, 6]]
  4. 输入:间隔:[[5, 10], [15, 20], [25, 30]]; 范围:[0, 35]; 输出:[[0, 5], [10, 15], [20, 25], [30, 35]]

我现在拥有的代码检查想要的范围是否已经在缓存中,以及它是否与缓存的日期部分重叠:

  const partiallyCached = cachedDates.some(
    (cachedDate) =>
      range.start.getTime() <= cachedDate.end.getTime() &&
      cachedDate.start.getTime() <= range.end.getTime()
  );

  if (partiallyCached) {
    console.log("Partially cached, merging query");

    const queryRange = functionToFindNonOverlappingIntervalsInRange(cachedDates, range);

    const newCachedDates = mergeOverlappingDateRanges([...cachedDates, range]);

    return {
      cache: newCachedDates,
      queryRange,
    };
  }

我还想知道我是否应该继续编写if 语句来缩小上述每个案例的范围并为每个案例编写一个单独的函数,或者是否可以编写一个函数来解决所有案例。

【问题讨论】:

  • 第一个 [2, 3] 是什么意思?
  • @NinaScholz 在他的示例中,OP 提到他/她可以解决它,但由于某种原因不想要第一个间隙。
  • 示例案例错误,我编辑了帖子并更正了它。

标签: javascript arrays date intervals date-range


【解决方案1】:

您可以取范围的起始值并检查间隔并构建一个新数组。

const
    getInbetween = (intervals, range) => {
        const
            result = [];
            
        let value = range[0],
            index = 0;

        while (value < range[1] && index < intervals.length) {
            let [left, right] = intervals[index];
            if (value < left) result.push([value, left]);
            value = right;
            index++;
        }
        if (value < range[1]) result.push([value, range[1]]);
        return result;
    };

console.log(getInbetween([[3, 5], [7, 9]], [2, 11]));
console.log(getInbetween([[3, 5], [7, 9]], [4, 11]));
console.log(getInbetween([[3, 5], [7, 9]], [4, 8]));
.as-console-wrapper { max-height: 100% !important; top: 0; }

【讨论】:

    【解决方案2】:

    假设这是已排序的,并且所有区间都已合并,则只需考虑几种情况。

    1. 范围的开始在第一个元素之前。
    2. 范围的开头与第一个元素相交。
    3. 范围的结尾与最后一个元素相交。
    4. 范围的结尾超出了最后一个元素。
    5. 元素位于范围的起点和终点。

    function getNonOverlappingIntervals(intervals, [rangeStart, rangeStop]) {
        const output = [];
        let prevStop = null;
    
        const intervalsInRange = intervals.filter(([start, stop]) => {
            if (rangeStart <= start && rangeStop >= stop) return true;
            if (start < rangeStart && stop > rangeStart) return true;
            if (start < rangeStop && stop > rangeStop) return true;
            return false;
        });
    
        // check if rangeStart precedes first interval
        if (intervalsInRange[0][0] > rangeStart) {
            output.push([rangeStart, intervalsInRange[0][0]]);
            prevStop = intervalsInRange[0][1];
        } else if (intervalsInRange[0][0] < rangeStart) {
            prevStop = intervalsInRange[0][1];
        }
    
        // iterate intervals and compare against last checked interval
        if (intervalsInRange.length > 2) {
            for (let i = 1; i < intervalsInRange.length; i++) {
                output.push([prevStop, intervalsInRange[i][0]]);
                prevStop = intervalsInRange[i][1];
            }
        }
    
        // check if rangeStop exceeds last interval
        if (intervalsInRange[intervalsInRange.length - 1][1] < rangeStop) {
            output.push([intervalsInRange.at(-1)[1], rangeStop]);
        }
    
        return output;
    }
    
    console.log(getNonOverlappingIntervals([[3, 5],[7, 9]], [2, 11]));
    console.log(getNonOverlappingIntervals([[3, 5]], [4, 8]));
    console.log(getNonOverlappingIntervals([[7, 11]], [2, 8]));
    console.log(getNonOverlappingIntervals([[3, 5], [6, 8]], [4, 7]));
    console.log(getNonOverlappingIntervals([[5, 10], [15, 20], [25, 30]], [0, 35]));

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多