Algorithm 给定两个已排序的间隔列表,返回两个列表之间的重叠间隔

Algorithm 给定两个已排序的间隔列表,返回两个列表之间的重叠间隔,algorithm,intervals,overlap,interval-tree,Algorithm,Intervals,Overlap,Interval Tree,您将获得两个间隔列表,A和B 在A中,间隔按起点排序。A内的间隔均不重叠 同样,在B中,间隔按其起点排序。B内的间隔均不重叠 返回两个列表之间重叠的间隔 例如: A: {[0,4], [7,12]} B: {[1,3], [5,8], [9,11]} 返回: {[1,3], [7,8], [9,11]} 我是在一次采访中得到这个消息的,结果被难住了 我想比较一下这两份清单的时间间隔。如果两者之间存在重叠,请将重叠添加到结果列表中。然后,我以较小的起始间隔推进列表指针,但在面试结束时无法找到

您将获得两个间隔列表,
A
B

A
中,间隔按起点排序。
A
内的间隔均不重叠

同样,在
B
中,间隔按其起点排序。
B
内的间隔均不重叠

返回两个列表之间重叠的间隔

例如:

A: {[0,4], [7,12]}
B: {[1,3], [5,8], [9,11]}
返回:

{[1,3], [7,8], [9,11]} 
我是在一次采访中得到这个消息的,结果被难住了

我想比较一下这两份清单的时间间隔。如果两者之间存在重叠,请将重叠添加到结果列表中。然后,我以较小的起始间隔推进列表指针,但在面试结束时无法找到有效的解决方案


解决此问题的最佳方法是什么?

因此您有两个事件列表-输入间隔和离开间隔。合并这些列表,保持当前状态为整数0、1、2(活动间隔计数)


处理与所选规则相对应的关系(当值等于[0..1]和[1..2]时)-在打开一个之前处理关闭事件,如果此类间隔不应给出交叉点

首先,找到一种方法,对于给定的一对间隔,该方法可以找到重叠(如果有的话)

/* Cases: A behind B, A overlap at start, A part of B, B part of A,
   overlap at end, B starts after A ended:
A:    2..3..4..5
Bs:   |        | 
0..1  |        |
0..1..2..3     |
0..1..2..3..4..5..6
      |  3..4  |
      |     4..5..6
      |        |  6..7
*/
case class Interval (lower: Int, upper: Int) {
    def overlap (other: Interval) : Option [Interval] = {
        if (lower > other.upper || upper < other.lower) None else 
        Some (Interval (Math.max (lower, other.lower), Math.min (upper, other.upper)))
    }
}
天真的方法:气泡重叠(首先使其工作,然后使其快速):

如果您不习惯选择/可能有一些(T)和无,那么有助于理解的核心是:

a.map (aa => b.map (bb => aa.overlap (bb))) 
res19: List[List[Option[Interval]]] = List(List(Some(Interval(1,3)), None, None), List(None, Some(Interval(7,8)), Some(Interval(9,11))))
第一次展平将两个内部列表合并为一个列表,第二次展平删除了Nones并给我们留下了间隔,而不是包装Some(Interval)

也许我可以想出一个迭代的解决方案,它不需要超过2倍的间隔,比它匹配。 …(10分钟后)。。。 这是:

def findOverlaps (l1: List[Interval], l2: List[Interval]): List[Option[Interval]] = (l1, l2) match {
    case (_, Nil) => Nil 
    case (Nil, _) => Nil
    case (a :: as, b :: bs) => {
             if (a.lower > b.upper) findOverlaps (l1, bs) 
        else if (a.upper < b.lower) findOverlaps (as, l2) 
        else if (a.upper > b.upper) a.overlap (b) :: findOverlaps (l1, bs) 
        else                        a.overlap (b) :: findOverlaps (as, l2) 
    }
}

你看,没有生成None,对于FindVerlaps(b,a),结果是相同的。

这里是我用作apache spark程序中复杂reduce步骤组件的算法实现:。奇怪的是,它也在Scala

以下是单独的算法:

  type Gap = (Int, Int)
/** The `merge`-step of a variant of merge-sort
  * that works directly on compressed sequences of integers,
  * where instead of individual integers, the sequence is 
  * represented by sorted, non-overlapping ranges of integers.
  */
def mergeIntervals(as: List[Gap], bs: List[Gap]): List[Gap] = {
  require(!as.isEmpty, "as must be non-empty")
  require(!bs.isEmpty, "bs must be non-empty")
  // assuming that `as` and `bs` both are either lists with a single
  // interval, or sorted lists that arise as output of
  // this method, recursively merges them into a single list of
  // gaps, merging all overlapping gaps.
  @annotation.tailrec
  def mergeRec(
    gaps: List[Gap],
    gapStart: Int,
    gapEndAccum: Int,
    as: List[Gap],
    bs: List[Gap]
  ): List[Gap] = {
    as match {
      case Nil => {
        bs match {
          case Nil => (gapStart, gapEndAccum) :: gaps
          case notEmpty => mergeRec(gaps, gapStart, gapEndAccum, bs, Nil)
        }
      }
      case (a0, a1) :: at => {
        if (a0 <= gapEndAccum) {
          mergeRec(gaps, gapStart, gapEndAccum max a1, at, bs)
        } else {
          bs match {
            case Nil => mergeRec((gapStart, gapEndAccum) :: gaps, a0, gapEndAccum max a1, at, bs)
            case (b0, b1) :: bt => if (b0 <= gapEndAccum) {
              mergeRec(gaps, gapStart, gapEndAccum max b1, as, bt)
            } else {
              if (a0 < b0) {
                mergeRec((gapStart, gapEndAccum) :: gaps, a0, a1, at, bs)
              } else {
                mergeRec((gapStart, gapEndAccum) :: gaps, b0, b1, as, bt)
              }
            }
          }
        }
      }
    }
  }
  val (a0, a1) :: at = as
  val (b0, b1) :: bt = bs

  val reverseRes = 
    if (a0 < b0) 
      mergeRec(Nil, a0, a1, at, bs)
    else
      mergeRec(Nil, b0, b1, as, bt)

  reverseRes.reverse
}
type Gap=(Int,Int)
/**“merge”-merge sort变量的步骤
*直接作用于压缩的整数序列,
*其中,序列不是单个整数,而是
*由排序的、不重叠的整数范围表示。
*/
def合并间隔(as:List[Gap],bs:List[Gap]):List[Gap]={
require(!as.isEmpty,“as必须非空”)
require(!bs.isEmpty,“bs必须为非空”)
//假设'as'和'bs'都是带有单个
//间隔,或作为的输出出现的排序列表
//此方法递归地将它们合并到一个列表中
//间隙,合并所有重叠间隙。
@注释.tailrec
def mergeRec(
差距:列出[差距],
间隙:Int,
gapEndAccum:Int,
as:列表[Gap],
bs:列表[Gap]
):列表[间隙]={
相配{
案例无=>{
bs匹配{
案例Nil=>(间隙开始,间隙累积)::间隙
case notEmpty=>mergeRec(间隙、间隙开始、间隙累积、bs、无)
}
}
案例(a0,a1)::at=>{
如果(a0合并)(间隙开始,间隙累积)::间隙,a0,间隙累积最大a1,at,bs)

案例(b0,b1)::bt=>如果(b0)我不熟悉Scala,所以不太理解代码。你能澄清一下吗?谢谢!这个例子有用吗:
A:{[7,12],[8,15],[9,16]}.B:{[5,8],[9,11],[10,15],[11,17]}
。返回:
{[7,16]}
?@user9577088:这违反了你给出的断言。让我引用:“一个重叠的区间中没有一个。”对于B也是如此。用另一个例子修复了。
A:{[7,12],[13,19]}.B:{[5,8],[9,11],[12,15},[16,18]}
。返回:
{[7,18]}
。第一个例子包含(5,8)(9,11)和(7,12)。您的解决方案是(7,8)(9,11)而不是(7,11)。在出现有效答案后,您不能更改目标。您可以提出一个与问题本身不矛盾的新问题,但您可以在此处邀请并链接到此问题。由于您迄今为止没有接受任何答案,我现在非常保留投入时间的做法。是的,它们不应重叠。使用另一个示例修复。我已删除sec这是一个例子,因为它没有意义。
a.map (aa => b.map (bb => aa.overlap (bb))) 
res19: List[List[Option[Interval]]] = List(List(Some(Interval(1,3)), None, None), List(None, Some(Interval(7,8)), Some(Interval(9,11))))
def findOverlaps (l1: List[Interval], l2: List[Interval]): List[Option[Interval]] = (l1, l2) match {
    case (_, Nil) => Nil 
    case (Nil, _) => Nil
    case (a :: as, b :: bs) => {
             if (a.lower > b.upper) findOverlaps (l1, bs) 
        else if (a.upper < b.lower) findOverlaps (as, l2) 
        else if (a.upper > b.upper) a.overlap (b) :: findOverlaps (l1, bs) 
        else                        a.overlap (b) :: findOverlaps (as, l2) 
    }
}
scala> findOverlaps (a, b)
res0: List[Option[Interval]] = List(Some(Interval(1,3)), Some(Interval(7,8)), Some(Interval(9,11)))
  type Gap = (Int, Int)
/** The `merge`-step of a variant of merge-sort
  * that works directly on compressed sequences of integers,
  * where instead of individual integers, the sequence is 
  * represented by sorted, non-overlapping ranges of integers.
  */
def mergeIntervals(as: List[Gap], bs: List[Gap]): List[Gap] = {
  require(!as.isEmpty, "as must be non-empty")
  require(!bs.isEmpty, "bs must be non-empty")
  // assuming that `as` and `bs` both are either lists with a single
  // interval, or sorted lists that arise as output of
  // this method, recursively merges them into a single list of
  // gaps, merging all overlapping gaps.
  @annotation.tailrec
  def mergeRec(
    gaps: List[Gap],
    gapStart: Int,
    gapEndAccum: Int,
    as: List[Gap],
    bs: List[Gap]
  ): List[Gap] = {
    as match {
      case Nil => {
        bs match {
          case Nil => (gapStart, gapEndAccum) :: gaps
          case notEmpty => mergeRec(gaps, gapStart, gapEndAccum, bs, Nil)
        }
      }
      case (a0, a1) :: at => {
        if (a0 <= gapEndAccum) {
          mergeRec(gaps, gapStart, gapEndAccum max a1, at, bs)
        } else {
          bs match {
            case Nil => mergeRec((gapStart, gapEndAccum) :: gaps, a0, gapEndAccum max a1, at, bs)
            case (b0, b1) :: bt => if (b0 <= gapEndAccum) {
              mergeRec(gaps, gapStart, gapEndAccum max b1, as, bt)
            } else {
              if (a0 < b0) {
                mergeRec((gapStart, gapEndAccum) :: gaps, a0, a1, at, bs)
              } else {
                mergeRec((gapStart, gapEndAccum) :: gaps, b0, b1, as, bt)
              }
            }
          }
        }
      }
    }
  }
  val (a0, a1) :: at = as
  val (b0, b1) :: bt = bs

  val reverseRes = 
    if (a0 < b0) 
      mergeRec(Nil, a0, a1, at, bs)
    else
      mergeRec(Nil, b0, b1, as, bt)

  reverseRes.reverse
}