【问题标题】:How do I find gaps between ranges? [closed]如何找到范围之间的差距? [关闭]
【发布时间】:2021-06-05 22:17:35
【问题描述】:

让我们使用这个范围的例子:

const ranges = [
  [
    0,
    10,
  ],
  [
    20,
    30,
  ],
  [
    40,
    50,
  ],
];

我想找到两个范围值之间的缺失范围,例如如果输入是[-10, 60],那么预期的输出必须是:

const islands = [
  [
    -10,
    -1,
  ],
  [
    11,
    19,
  ],
  [
    31,
    39,
  ],
  [
    51,
    60,
  ],
];

我尝试搜索“不相交的范围”和“不相交的范围”以及类似的关键字。这似乎是一个以前可以解决一百万次的问题。也许我只是使用了错误的关键字。

【问题讨论】:

    标签: javascript arrays algorithm range


    【解决方案1】:

    在区间中查找交叉点的主要数据结构之一是Interval Tree。您可以在ranges 上构建一个区间树,并通过在树上查询来跟踪输入范围与它们的交点。然后,从输入范围的左到右扫一扫,找出间隙。

    您可以在 javascript 中找到许多区间树的实现,例如 this one

    【讨论】:

      【解决方案2】:

      我确实设法编写了一个实现,涵盖了我能想到的所有边缘情况。

      如果没有其他人提供权威答案,我会分享这个(我希望有一个更聪明的解决方案):

      const getGaps = (ranges: RangesType): RangesType => {
        const gaps = [];
      
        // $FlowFixMe
        for (const index in ranges) {
          const start = ranges[Number(index)][1];
          const end = ranges[Number(index) + 1]?.[0];
      
          if (start < end) {
            gaps.push([
              start + 1,
              end - 1,
            ]);
          }
        }
      
        return gaps;
      };
      
      const getMissingRanges = (ranges: RangesType, from: number, to: number): RangesType => {
        if (ranges.length === 0) {
          return [
            [
              from,
              to,
            ],
          ];
        }
      
        const gaps = [
          [
            Number.NEGATIVE_INFINITY,
            ranges[0][0] - 1,
          ],
          ...getGaps(
            ranges,
          ),
          [
            ranges[ranges.length - 1][1] + 1,
            Number.POSITIVE_INFINITY,
          ],
        ];
      
        return gaps
          .filter((gap) => {
            return isRangeOverlapping(gap, [from, to]);
          })
          .map((gap) => {
            return [
              Math.max(gap[0], from),
              Math.min(gap[1], to),
            ];
          });
      };
      

      【讨论】:

      • 这通过了gist中描述的所有测试用例。
      【解决方案3】:

      const findMissing = (arr, ranges) => {
        [min, max] = arr;
        return ranges.reduce((acc, a, i) => {
          if (a[0] < min) return acc;
          if (min < a[0]) acc.push([min, a[0] - 1]);
          if (i == ranges.length - 1 && max > a[1]) acc.push([a[1] + 1, max]);
          min = a[1] + 1;
          return acc
        }, [])
      
      }
      
      let ranges = [ [2, 10], [5, 7], [40, 50] ]
      console.log(findMissing([-10, 60], ranges));
      
      ranges = [ [0, 10],[20, 30],[40, 50]];
      console.log(findMissing([-10, 60], ranges));

      【讨论】:

      • 我显然过于复杂了。谢谢!
      • @Gajus 不正确。您会发现它不适用于以下情况,例如:const ranges = [ [2, 10], [5, 7], [40, 50] ]; 和输入范围 [-10, 60]
      • @Gajus 比这更复杂。因为区间可以部分重叠,甚至被其他区间完全覆盖。
      • @OmG - 所以预期的结果是 [-10,1], [ 9,6], [8,39] ... ?
      • 预期结果是[-10, 1], [11, 39], [51, 60]
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-04-17
      • 1970-01-01
      • 2011-07-10
      • 2019-09-21
      • 1970-01-01
      • 2019-12-07
      • 2022-12-04
      相关资源
      最近更新 更多