我将使用Scala语法提出这个问题,即使问题确实与语言无关。
假设我有两个列表
val groundtruth:List[Range]
val testresult:List[Range]
我想找到与testresult
中某些元素重叠的groundtruth
的所有元素。
我可以这样做:
def overlaps(x:Range,y:Range) = (x contains y.start) || (y contains x.start)
val result = testresult.filter{ tr => groundtruth.exists{gt => overlaps(gt,tr)}}
但这需要O(testresult.size * groundtruth.size)
时间才能运行。
是否有更快的算法来计算此结果,还是可以使exists
测试更有效的数据结构?
P.S。该算法应该适用于使用如下表达式生成的groundtruth
和testresult
。换句话说,不保证列表中范围之间的关系,Range
s的平均大小为100或更大。
(1 to 1000).map{x =>
val midPt = r.nextInt(100000);
((midPt - r.nextInt(100)) to (midPt + r.nextInt(100)));
}.toList
答案 0 :(得分:9)
尝试interval tree。 Cormen, Leiserson, Rivest and Stein在(IIRC)第14章中讨论这些问题。
或者,如果您的间隔列表都已排序且列表中的间隔不重叠,则以下算法将在线性时间内解决您的问题,并在两个列表中单次传递:
(define interval cons)
(define lower car)
(define upper cdr)
(define (overlap a b)
(cond ((or (null? a) (null? b)) '())
((< (upper a) (lower b))
(overlap (cdr a) b))
((> (lower a) (upper b))
(overlap a (cdr b)))
(#t ;; (car a) and (car b) overlap
;; EDIT: there's a bug in the following part.
;; The code shouldn't skip over both cars at once,
;; since they may also overlap with further intervals.
;; However, I'm too tired to fix this now.
(cons (interval (max (lower a) (lower b))
(min (upper a) (upper b)))
(overlap a b)))))
(我希望你能读一下Scheme:)
答案 1 :(得分:0)
如果您可以按范围起始值对groundtruth
列表进行排序,那么对于testresult
中的每个范围,您可以进行二分搜索以获取其下限小于或等于的范围子集有问题的范围。然后,您需要按顺序搜索那个上限大于或等于您正在测试的范围的上限的那些子集。
最坏的情况仍然是O(n ^ 2),因为所有groundtruth
范围都可能具有符合条件的下限,但实际数据的运行时间可能会少得多
答案 2 :(得分:0)
如果groundtruth存储在散列集中,则检查其中是否存在测试结果成员为O(n)。
编辑:我没有意识到您只使用其端点所代表的范围。 D'哦!
某种基于树的结构必须是你最好的选择。