测试两个重叠整数范围的最有效方法是什么?

Wil*_*mKF 223 comparison performance integer range

给定两个包含整数范围[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);
}
Run Code Online (Sandbox Code Playgroud)

但我希望有更有效的方法来计算它.

在最少的操作方面,哪种方法最有效.

Sim*_*son 406

重叠范围意味着什么?这意味着存在一些在两个范围内的数字C,即

x1 <= C <= x2
Run Code Online (Sandbox Code Playgroud)

y1 <= C <= y2
Run Code Online (Sandbox Code Playgroud)

现在,如果我们被允许假设范围是格式良好的(因此x1 <= x2和y1 <= y2)那么它就足够了

x1 <= y2 && y1 <= x2
Run Code Online (Sandbox Code Playgroud)

  • @DavidBeck:不,如果y1> x2那么范围肯定不重叠(例如考虑[1:2]和[3:4]:y1 = 3和x2 = 2,所以y1> x2,但没有重叠) . (8认同)
  • 如果您更多地解释推理,这将是一个更好的答案 (7认同)
  • 解释在这里:/sf/ask/22815341/#325964 (5认同)
  • 我相信它应该是`x1 &lt;= y2 &amp;&amp; y1 &gt;= x2`,不是吗? (2认同)
  • @Vineet Deoraj - 为什么你认为它不起作用?x1 = 1,y1 = 1,x2 = 1,y2 = 1,因此x1 <= y2 && y1 <= x2为真,因此存在重叠. (2认同)

KFL*_*KFL 125

给定两个范围[x1,x2],[y1,y2]

def is_overlapping(x1,x2,y1,y2):
    return max(x1,y1) <= min(x2,y2)
Run Code Online (Sandbox Code Playgroud)

  • @vsync现代浏览器将内联和优化Math.max等函数,对性能不应有明显影响. (6认同)
  • @ uyuyuy99 - 只是效率不高,因为当这个检查每秒进行多次时,调用函数是你想要避免的,并且自己做很多数学运算,保持基本 (3认同)
  • 此外,请注意,`min(x2,y2)-max(x1,y1)`提供了重叠量,以备需要时使用。 (2认同)

Flo*_*ock 49

这很容易扭曲正常的人脑,所以我发现了一种更容易理解的视觉方法:

重叠疯狂

le解释

如果两个范围"太胖"以适合恰好是两者宽度之和的槽,则它们重叠.

对于范围[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!
}
Run Code Online (Sandbox Code Playgroud)

  • @WilliamKF的逻辑是正确的 (5认同)
  • @WilliamKF然后你需要更多的图像有16种不同的组合,可以放置2个范围...... (3认同)
  • 情况比图片中所描绘的更多。例如,如果w2在w1之前开始并在w1之后结束怎么办? (2认同)
  • 同意,但我认为提供第三张照片可能会有所帮助。 (2认同)
  • 使用此方法时要小心,因为总和"a2 - a1 + b2 - b1"会溢出.要修复它,将公式重新排列为"max(a2,b2) - a2 - b2 <min(a1,b1) - a1 - b1`,简化为"max(a1,b1)<min(a2,b2)" ,保存一些算术并避免任何可能的溢出(这是AX-Labs的答案).在你知道`b2-b1 = a2-a1`的特殊情况下,FloatingRock公式的另一个有用的重新排列是`max(a2,b2) - min(a1,b1) - (b2 - b1)<a2-a1`,变为`abs(b1-a1)<a2 - a1`. (2认同)

dam*_*uar 38

西蒙很好的回答,但对我来说,考虑反向案例更容易.

2个范围何时不重叠?当其中一个在另一个结束后开始时,它们不重叠:

dont_overlap = x2 < y1 || x1 > y2
Run Code Online (Sandbox Code Playgroud)

现在,当它们重叠时很容易表达:

overlap = !dont_overlap = !(x2 < y1 || x1 > y2) = (x2 >= y1 && x1 <= y2)
Run Code Online (Sandbox Code Playgroud)

  • 对我来说,更容易理解的表达式是:x2 &lt; y1 || y2 &lt; x1 // 我使用“小于”而不是“大于”。 (2认同)

AXE*_*abs 23

从最大值开始减去范围的最小值似乎可以解决问题.如果结果小于或等于零,则我们有重叠.这可视化很好:

在此输入图像描述

  • 这涵盖所有情况 (3认同)

rus*_*lik 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));
};
Run Code Online (Sandbox Code Playgroud)

或者,对于这种情况:

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);
};
Run Code Online (Sandbox Code Playgroud)

  • 相信你的编译器.表达式`x1 <= y2 && y1 <= x2` [其中没有任何分支](https://godbolt.org/g/foj6kr),假设一个相当称职的编译器和CPU架构(即使在2010年) ).实际上,在x86上,生成的代码与简单表达式与本答案中的代码基本相同. (6认同)

小智 5

如果您正在处理,同时给定两个范围[x1:x2][y1:y2]自然/反自然顺序范围,其中:

  • 自然顺序:x1 <= x2 && y1 <= y2
  • 反自然秩序: x1 >= x2 && y1 >= y2

那么你可能想用它来检查:

它们是重叠的<=> (y2 - x1) * (x2 - y1) >= 0

其中只涉及四个操作:

  • 两次减法
  • 一次乘法
  • 一比较