假设我有两个向量"开始"和"停止",按升序排序。
Vector 1 = [start1 stop1;
start2 stop2;
start3 stop3];
Vector 2 = [start4 stop4;
start5 stop5;
start6 stop6];
确定这两个向量的交集/重叠的最有效方法是什么?
答案 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