这里有一个实现,遵循罗马的分治原则:
首先,找到一种方法,对于给定的两个区间,找到它们的重叠部分(如果有的话)。
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)))
}
}
那是一种有限责任的方法,用于决定两个区间。
如果您不熟悉Scala:Interval是一个类,第一行可以被视为构造函数。Lower和upper应该是自解释的(类型为Int)。
该类具有重叠方法,它接受该类的第二个实例(other),并将重叠的结果作为新的Interval返回。但是包装成了Option,这意味着:如果没有重叠,则返回None。如果我们找到一个,它就是Some(Interval)。您可以将其理解为List,它可以为空,也可以只包含一个元素。这是一种避免NullpointerException的技术,通过使用类型来表示可能没有结果。
如果一个Interval的上限小于另一个Interval的下限,则不能有重叠,因此我们返回None。
对于重叠,我们将两个下限中的最大值作为下限,并将两个上限中的最小值作为新的上限。
数据:
val a = List (Interval (0, 4), Interval (7, 12))
val b = List (Interval (1, 3), Interval (5, 8), Interval (9, 11))
天真的方法:气泡重叠(先让它工作,然后再让它快):
scala> a.map (aa => b.map (bb => aa.overlap (bb))).flatten.flatten
res21: List[Interval] = List(Interval(1,3), Interval(7,8), Interval(9,11))
如果你不习惯使用Option/Maybe,其中Some(T)和None可能有所帮助,核心内容是:
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))))
第一个flatten将两个内部列表合并为一个列表,第二个flatten移除了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)
}
}
前两行检查两个列表是否有一个为空,如果是,则不会有更多的重叠。
(a :: as, b :: bs) 是(l1, l2)的匹配,其中a是l1的头部,as是l1的尾部(可能是Nil),类似地,b是l2的头部,bs是l2的尾部。
如果a.lower > b.upper,则我们取b列表的尾部,并递归地使用整个l1列表和类似的方法处理整个l2列表,但只使用l1列表的尾部,如果b.lower > a.upper。
否则,我们应该有一个重叠,因此我们在任一情况下都要使用a.overlap(b),其中一方是具有更高上限的整个列表,而另一方是其余列表。
scala> findOverlaps (a, b)
res0: List[Option[Interval]] = List(Some(Interval(1,3)), Some(Interval(7,8)), Some(Interval(9,11)))
您看,没有生成 None,对于 findOverlaps(b, a) 也是相同的结果。