确定交叉路口的最有效方法

时间:2015-08-17 22:49:09

标签: algorithm

假设我有两个向量"开始"和"停止",按升序排序。

Vector 1 = [start1 stop1;
        start2 stop2;
        start3 stop3];

Vector 2 = [start4 stop4;
        start5 stop5;
        start6 stop6];

确定这两个向量的交集/重叠的最有效方法是什么?

2 个答案:

答案 0 :(得分:2)

我必须在几次这样做。这是一项简单的任务,但逻辑可能会非常混乱。

必须决定的一件事,就是间隔是关闭还是打开。也就是说,[1,3][3,5]的区间是否在[3,3]处有交叉点,或者没有交叉点?我强烈建议“没有交叉”(封闭的间隔往往比开放或半开的间隔更加痛苦),但你的用例可能需要另外。

我认为最简单的方法是从每个列表中保持“当前部分间隔”。 “部分”是指每个间隔可以从底部“消失”,因为识别并输出与来自另一个列表的间隔的交叉点。这简化了逻辑,只强制您一次考虑两个间隔,而不是处理与V1中某个间隔相关的所有V2间隔。

为了进一步简化代码,您可以允许间隔暂时无效,并且从两个当前间隔开始无效。这使代码更加不必要地分支,但这意味着您只需要在一个地方并使用一个规则来处理它们。

所以伪代码是这样的(我正在破坏性地读取V1和V2,并写入VI):

v1a,v1b = 0,0                    # Empty and hence invalid
v2a,v2b = 0,0                    # intervals to start with.

while True:
    if v1a >= v1b:               # Handle an invalid V1 interval
        if V1.empty():           # If there's no more V1s,
            return               # No more intersections are possible.
        else:
            v1a,v2a = V1.pop()   # Grab the next full interval from V1
    if v2a >= v2b:
        if V2.empty(): 
            return
        else:
            v2a,v2b = V2.pop()

    lower_bound = max(v1a, v2a)  # Determine the overlap, if any, between
    upper_bound = min(v1b, v2b)  # the current two intervals.

    if lower_bound < upper_bound:
        VI.push(lower_bound, upper_bound) # Output the overlapping interval.

    v1a = max(v1a, upper_bound)  # Snip away the region which has now been
    v2a = max(v2a, upper_bound)  # handled. This may make one or both invalid.

最后两行是棘手的一点。如果有一个交叉点,那么upper_bound是它的上端:它下面没有剩余的交叉范围,因此它们可以从一个或两个当前间隔中移除。但是,如果两个当前间隔重叠,那么它可以将较低间隔的a设置为自己的b,使其无效并导致它在下一次迭代中被替换。

答案 1 :(得分:1)

我相信你可以利用列表排序然后执行以下操作的事实(伪代码)

抓住第一个跨度 确定跨距是否重叠 如果跨距重叠,则max(开始)到min(结束)是重叠 以最小的一端增加跨度 *合并结果 - 您可能需要传递结果并合并重叠元素

这是一些实现此功能的python(注意 - a和b将是包含(start,end)元组的列表):

try:
        while True:
            if b_span[1]>a_span[0] and b_span[0]<a_span[1]:
                overlaps.append((a_span[0] if a_span[0] > b_span[0] else b_span[0],
                                 a_span[1] if a_span[1] < b_span[1] else b_span[1]))
            if a_span[1] < b_span[1]:
                a_span = a.pop(0)
            else:
                b_span = b.pop(0)
    except IndexError:
        pass