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

时间:2010-07-16 23:08:48

标签: performance comparison 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);
}

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

就最少的操作而言,哪种方法最有效。

15 个答案:

答案 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)

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

Overlap madness

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!
}

答案 3 :(得分:35)

来自Simon的精彩回答,但对我来说,考虑反向案例更容易。

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

dont_overlap = x2 < y1 || x1 > y2

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

overlap = !dont_overlap = !(x2 < y1 || x1 > y2) = (x2 >= y1 && x1 <= y2)

答案 4 :(得分:17)

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

enter image description here

答案 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;

除非你在数十亿个宽间距整数上运行一些高性能范围检查器,否则我们的版本应该具有相似的性能。我的观点是,这是微观优化。