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
}