给定两个包含整数范围[x1:x2]和[y1:y2],其中x1≤x2和y1≤y2,测试两个范围是否有任何重叠的最有效方法是什么?
一个简单的实现如下:
bool testOverlap(int x1, int x2, int y1, int y2) {
return (x1 >= y1 && x1 <= y2) ||
(x2 >= y1 && x2 <= y2) ||
(y1 >= x1 && y1 <= x2) ||
(y2 >= x1 && y2 <= x2);
}
但我希望有更有效的方法来计算它。
就最少的操作而言,哪种方法最有效。
答案 0 :(得分:361)
重叠范围意味着什么?这意味着在两个范围内存在一些数字C,即
x1 <= C <= x2
和
y1 <= C <= y2
现在,如果允许我们假设范围是格式良好的(因此x1 <= x2和y1 <= y2)那么它就足够了
x1 <= y2 && y1 <= x2
答案 1 :(得分:119)
给出两个范围[x1,x2],[y1,y2]
def is_overlapping(x1,x2,y1,y2):
return max(x1,y1) <= min(x2,y2)
答案 2 :(得分:43)
这很容易扭曲正常的人脑,所以我找到了一种更容易理解的视觉方法:
如果两个范围“太胖”以适合恰好是两者的宽度之和的插槽,则它们会重叠。
对于范围[a1, a2]
和[b1, b2]
,这将是:
/**
* we are testing for:
* max point - min point < w1 + w2
**/
if max(a2, b2) - min(a1, b1) < (a2 - a1) + (b2 - b1) {
// too fat -- they overlap!
}
答案 3 :(得分:35)
来自Simon的精彩回答,但对我来说,考虑反向案例更容易。
2个范围何时不重叠?当其中一个在另一个结束后开始时,它们不会重叠:
dont_overlap = x2 < y1 || x1 > y2
现在,当它们重叠时很容易表达:
overlap = !dont_overlap = !(x2 < y1 || x1 > y2) = (x2 >= y1 && x1 <= y2)
答案 4 :(得分:17)
答案 5 :(得分:10)
我想这个问题是关于最快但不是最短的代码。最快的版本必须避免分支,所以我们可以这样写:
简单案例:
static inline bool check_ov1(int x1, int x2, int y1, int y2){
// insetead of x1 < y2 && y1 < x2
return (bool)(((unsigned int)((y1-x2)&(x1-y2))) >> (sizeof(int)*8-1));
};
或者,对于这种情况:
static inline bool check_ov2(int x1, int x2, int y1, int y2){
// insetead of x1 <= y2 && y1 <= x2
return (bool)((((unsigned int)((x2-y1)|(y2-x1))) >> (sizeof(int)*8-1))^1);
};
答案 6 :(得分:6)
return x2 >= y1 && x1 <= y2;
答案 7 :(得分:2)
如果你正在处理,给定两个范围[x1:x2]
和[y1:y2]
,自然/反自然顺序范围同时在:
x1 <= x2 && y1 <= y2
或x1 >= x2 && y1 >= y2
然后你可能想用它来检查:
它们重叠&lt; =&gt; (y2 - x1) * (x2 - y1) >= 0
强>
仅涉及四个操作:
答案 8 :(得分:0)
你已经拥有了最有效的代表 - 除非你确定x1&lt; x2等,然后使用其他人提供的解决方案。
你应该注意到一些编译器实际上会为你优化这个 - 通过在这4个表达式中的任何一个返回true时返回。如果一个返回true,那么最终结果也是如此 - 因此可以跳过其他检查。
答案 9 :(得分:0)
如果有人正在寻找可计算实际重叠的单线:
int overlap = ( x2 > y1 || y2 < x1 ) ? 0 : (y2 >= y1 && x2 <= y1 ? y1 : y2) - ( x2 <= x1 && y2 >= x1 ? x1 : x2) + 1; //max 11 operations
如果您要减少几个操作,但要增加几个变量:
bool b1 = x2 <= y1;
bool b2 = y2 >= x1;
int overlap = ( !b1 || !b2 ) ? 0 : (y2 >= y1 && b1 ? y1 : y2) - ( x2 <= x1 && b2 ? x1 : x2) + 1; // max 9 operations
答案 10 :(得分:0)
以相反的方式思考:如何使两个范围不重叠?给定[x1, x2]
,则[y1, y2]
应该位于外部 [x1, x2]
,即y1 < y2 < x1 or x2 < y1 < y2
,它等效于y2 < x1 or x2 < y1
。
因此,使两个范围重叠的条件是:not(y2 < x1 or x2 < y1)
,相当于y2 >= x1 and x2 >= y1
(与Simon接受的答案相同)。
答案 11 :(得分:0)
我的情况不同。我想检查两个时间范围是否重叠。不应有单位时间重叠。这是Go实现。
func CheckRange(as, ae, bs, be int) bool {
return (as >= be) != (ae > bs)
}
测试用例
if CheckRange(2, 8, 2, 4) != true {
t.Error("Expected 2,8,2,4 to equal TRUE")
}
if CheckRange(2, 8, 2, 4) != true {
t.Error("Expected 2,8,2,4 to equal TRUE")
}
if CheckRange(2, 8, 6, 9) != true {
t.Error("Expected 2,8,6,9 to equal TRUE")
}
if CheckRange(2, 8, 8, 9) != false {
t.Error("Expected 2,8,8,9 to equal FALSE")
}
if CheckRange(2, 8, 4, 6) != true {
t.Error("Expected 2,8,4,6 to equal TRUE")
}
if CheckRange(2, 8, 1, 9) != true {
t.Error("Expected 2,8,1,9 to equal TRUE")
}
if CheckRange(4, 8, 1, 3) != false {
t.Error("Expected 4,8,1,3 to equal FALSE")
}
if CheckRange(4, 8, 1, 4) != false {
t.Error("Expected 4,8,1,4 to equal FALSE")
}
if CheckRange(2, 5, 6, 9) != false {
t.Error("Expected 2,5,6,9 to equal FALSE")
}
if CheckRange(2, 5, 5, 9) != false {
t.Error("Expected 2,5,5,9 to equal FALSE")
}
您会看到边界比较中存在XOR模式
答案 12 :(得分:0)
给出:
[x1,x2]
[y1,y2]
那么x1 <= y2 || x2 >= y1
将始终有效。
x1 ... x2
y1 .... y2
如果x1 > y2
,则它们不重叠
或
x1 ... x2
y1 ... y2
如果x2 < y1
不重叠。
答案 13 :(得分:0)
没什么新鲜的。只是更具可读性。
def overlap(event_1, event_2):
start_time_1 = event_1[0]
end_time_1 = event_1[1]
start_time_2 = event_2[0]
end_time_2 = event_2[1]
start_late = max(start_time_1, start_time_2)
end_early = min(end_time_1, end_time_2)
# The event that starts late should only be after the event ending early.
if start_late > end_early:
print("Absoloutly No overlap!")
else:
print("Events do overlap!")
答案 14 :(得分:-7)
这是我的版本:
int xmin = min(x1,x2)
, xmax = max(x1,x2)
, ymin = min(y1,y2)
, ymax = max(y1,y2);
for (int i = xmin; i < xmax; ++i)
if (ymin <= i && i <= ymax)
return true;
return false;
除非你在数十亿个宽间距整数上运行一些高性能范围检查器,否则我们的版本应该具有相似的性能。我的观点是,这是微观优化。