【问题标题】:Find if entire range is covered up given a set of N intervals给定一组 N 个区间,查找是否覆盖了整个范围
【发布时间】:2012-09-09 21:56:58
【问题描述】:

假设我有 N 个 [start,end] 形式的区间。我需要确定这些间隔是否覆盖了整个范围。

例如:如果我的间隔是 [4.5,5.765] 和 [5.8,10] 并且间隔是 [5,10] 它应该报告错误,而对于相同的数据如果间隔是 [6,9.99] 它应该报告真实。

我需要 1e-9 的精度。间隔和范围将在 [-1000,1000] 内。

这个问题可以在 O(NlgN) 时间内解决吗?其中 N = 间隔数。

【问题讨论】:

  • 间隔是否预先排序?你关心空间限制吗?
  • 没有。间隔没有预先排序。但它保证间隔将在 range[-1000,1000] 范围内。抱歉,现在我已经更新了。而且我有 256 Mb 的空间。但我认为这并不重要。您是否正在考虑存储每个值。嗯!!
  • 所以理论上你可以创建一个 [-1000 * 1e9, 1000*1e9] 的 BitSet 并随时屏蔽这些位。这在区间数上是线性的,但取决于总范围和每个区间的范围。不幸的是,这会占用相当多的空间......
  • 我认为如果我有整数值或者精度会低得多,则使用位掩码会更合适。这会占用很多空间。有没有更好的算法。我听说过区间树,但是我不确定它是否可以完成这项任务。
  • 你可以假设 N

标签: algorithm range


【解决方案1】:

如果您对所有区间 (O(N * log N)) 的起点和终点进行排序,那么在 O(N) 传递中您可以跟踪:

  • -10001000 之间数轴上的当前位置,该位置又取任意区间的每个起点/终点。
  • “当前”打开了多少个区间,即在数轴上的这一点有多少个区间相交。

如果在此遍中的任何一点,当前值在目标范围内且当前区间数为 0,则目标范围不被区间覆盖。如果在您到达目标范围的末端之前从未发生过这种情况,那么目标就被覆盖了。

由于区间已关闭,请记住对值为 r 的“终点”进行排序在值为 r 的“起点”之前进行排序,以确保您返回“true”区间为[0,1][1,2]且目标为[0,2]的情况。

IEEE 双精度足以满足 +/-1000 范围内的粒度 1e-9,但请注意 5.8 无法以二进制浮点数精确表示的问题。因此,根据计算间隔的方式,计算或表示错误可能会引入微小的“间隙”。出于这个原因,您可能希望在开始之前进行某种舍入到最接近的十亿分之一,和/或使用以 10 为底的而不是以 2 为底的表示所涉及的值。

【讨论】:

  • 有点意思:排序后,我相信你可以使用不相交集得到所有个闭区间。
【解决方案2】:

虽然你已经得到了一些好的答案,但我想我会贡献一些简单明了的东西。

你还没有告诉我们间隔是否可以重叠,所以我假设它们可以。 (否则,一个简单的 O(N) 搜索将告诉您您的范围是否在某个区间内。)

如果区间集在多个范围内保持不变,最好的办法是根据区间的起点对区间进行预排序。 (这通常是一个 O(N logN) 操作,但您只需执行一次)。然后,你可以这样做:

checkRange(range, intervals[])
    for each ( intv in intervals )
        if intv.start > range.start
            return false
        if intv.end >= range.end
            return true
        if intv.end > range.start
            range.start = interval.end

    return false

这只是一个 O(N) 通行证。

如果间隔集可以针对每个范围进行更改,那么以下递归算法可能会或可能不会比每次对间隔进行排序更好:

delta = 1e-9

checkRange(range, intervals[])
    for each ( intv in intervals )
        if intv.start <= range.start and intv.end >= range.end
            return true
        if intv.end < range.start or intv.start > range.end
            continue
        if intv.start < range.start and intv.end > range.start
            range.start = interval.end
            continue
        if intv.start < range.end and intv.end > range.end
            range.start = interval.end
            continue
        range1 = new range(start = range.start, end = intv.start - delta)
        range2 = new range(start = intv.end + delta, end = range.end)
        intervals = intervals after intv
        return checkRange(range1, intervals) and checkRange(range2, intervals)

因为,对于数组或链表,您可以将intervals after intv 保留在与原始intervals[] 相同的内存空间中,这只是为递归迭代使用了一些堆栈空间,仅此而已。至于计算复杂度,比我更好的人将不得不研究证明它的东西,但我觉得它可能相当不错。

【讨论】:

    【解决方案3】:

    您可以进行模糊排序。 最好的情况是O(n),平均情况是O(n log n)。这类似于快速排序。最好的情况发生在所有间隔中至少存在一个点,即它们都重叠。一般来说,重叠越多,算法比其他排序算法更好。

    这里是对该算法的详细分析。 http://web.media.mit.edu/~dlanman/courses/cs157/HW3.pdf

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-02-22
      • 2013-04-23
      • 1970-01-01
      • 1970-01-01
      • 2018-05-30
      • 1970-01-01
      • 1970-01-01
      • 2021-12-23
      相关资源
      最近更新 更多