web-dev-qa-db-ja.com

2つの整数範囲の重複をテストする最も効率的な方法は何ですか?

2つの包括的整数範囲[x1:x2]および[y1:y2]が与えられた場合、x1≤x2およびy1≤y2の場合、2つの範囲に重複があるかどうかをテストする最も効率的な方法は何ですか?

簡単な実装は次のとおりです。

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);
}

しかし、これを計算するより効率的な方法があると期待しています。

操作が最も少ないという点で、どの方法が最も効率的でしょう。

206
WilliamKF

範囲が重なるとはどういう意味ですか?これは、両方の範囲にある数Cが存在することを意味します。

x1 <= C <= x2

そして

y1 <= C <= y2

ここで、範囲が整形式であると仮定できる場合(x1 <= x2およびy1 <= y2)、テストするのに十分です。

x1 <= y2 && y1 <= x2
378
Simon Nickerson

2つの範囲[x1、x2]、[y1、y2]がある場合

def is_overlapping(x1,x2,y1,y2):
    return max(x1,y1) <= min(x2,y2)
123
KFL

これは正常な人間の脳を簡単にゆがめることができるので、視覚的なアプローチの方が理解しやすいことがわかりました。

Overlap madness

ル説明

2つの範囲が"too fat"で、両方の幅の合計に正確に一致するスロットに収まる場合、それらは重なります。

範囲[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!
}
46
FloatingRock

Simon からのすばらしい答えですが、私にとっては逆のケースについて考える方が簡単でした。

2つの範囲が重ならないのはいつですか?それらの1つが他の1つが終了した後に開始する場合、それらはオーバーラップしません。

dont_overlap = x2 < y1 || x1 > y2

重複する場合の表現が簡単になりました。

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

範囲の終了の最小値を開始の最大値から減算すると、うまくいくようです。結果がゼロ以下の場合、重複しています。これはそれをよく視覚化します:

enter image description here

20
AXE-Labs

質問は最短のコードではなく、最速のコードに関するものだと思います。最速のバージョンでは分岐を回避する必要があるため、次のように記述できます。

簡単な場合:

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);
};
10
ruslik
return x2 >= y1 && x1 <= y2;

対処している場合、2つの範囲[x1:x2]および[y1:y2]が与えられた場合、自然/反自然順序範囲は同時に:

  • 自然順序:x1 <= x2 && y1 <= y2または
  • 反自然秩序:x1 >= x2 && y1 >= y2

次に、これを使用して確認することができます。

それらはオーバーラップ<=> (y2 - x1) * (x2 - y1) >= 0

four操作のみが含まれる場合:

  • 2つの減算
  • 1つの乗算
  • 1つの比較
2
Yankuan Zhang

誰かが実際のオーバーラップを計算するワンライナーを探している場合:

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
1
Victor.dMdB

逆の方法:方法2つの範囲が重複しないようにする[x1, x2]の場合、[y1, y2]外部[x1, x2]である必要があります。つまり、y1 < y2 < x1 or x2 < y1 < y2y2 < x1 or x2 < y1と同等です。

したがって、2つの範囲を作成する条件は重複します:not(y2 < x1 or x2 < y1)、これはy2 >= x1 and x2 >= y1と同等です(Simonが受け入れた回答と同じです)。

0
Duke

すでに最も効率的な表現があります-x1 <x2などであることが確実にわからない限り、チェックする必要があるのは最低限であり、他の人が提供するソリューションを使用してください。

おそらく、いくつかのコンパイラは実際にこれを最適化することに注意する必要があります-これらの4つの式のいずれかがtrueを返すとすぐに戻ります。 1つがtrueを返すと、最終結果も返されるため、他のチェックはスキップできます。

0
Mark H

私の場合は異なります。 2つの時間範囲が重複していることを確認します。単位時間の重複があってはなりません。 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パターンがあることがわかります

0
Ajeet47