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);
}
しかし、これを計算するより効率的な方法があると期待しています。
操作が最も少ないという点で、どの方法が最も効率的でしょう。
範囲が重なるとはどういう意味ですか?これは、両方の範囲にある数Cが存在することを意味します。
x1 <= C <= x2
そして
y1 <= C <= y2
ここで、範囲が整形式であると仮定できる場合(x1 <= x2およびy1 <= y2)、テストするのに十分です。
x1 <= y2 && y1 <= x2
2つの範囲[x1、x2]、[y1、y2]がある場合
def is_overlapping(x1,x2,y1,y2):
return max(x1,y1) <= min(x2,y2)
これは正常な人間の脳を簡単にゆがめることができるので、視覚的なアプローチの方が理解しやすいことがわかりました。
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!
}
Simon からのすばらしい答えですが、私にとっては逆のケースについて考える方が簡単でした。
2つの範囲が重ならないのはいつですか?それらの1つが他の1つが終了した後に開始する場合、それらはオーバーラップしません。
dont_overlap = x2 < y1 || x1 > y2
重複する場合の表現が簡単になりました。
overlap = !dont_overlap = !(x2 < y1 || x1 > y2) = (x2 >= y1 && x1 <= y2)
質問は最短のコードではなく、最速のコードに関するものだと思います。最速のバージョンでは分岐を回避する必要があるため、次のように記述できます。
簡単な場合:
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);
};
return x2 >= y1 && x1 <= y2;
対処している場合、2つの範囲[x1:x2]
および[y1:y2]
が与えられた場合、自然/反自然順序範囲は同時に:
x1 <= x2 && y1 <= y2
またはx1 >= x2 && y1 >= y2
次に、これを使用して確認することができます。
それらはオーバーラップ<=> (y2 - x1) * (x2 - y1) >= 0
four操作のみが含まれる場合:
誰かが実際のオーバーラップを計算するワンライナーを探している場合:
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
逆の方法:方法2つの範囲が重複しないようにする? [x1, x2]
の場合、[y1, y2]
は外部[x1, x2]
である必要があります。つまり、y1 < y2 < x1 or x2 < y1 < y2
はy2 < x1 or x2 < y1
と同等です。
したがって、2つの範囲を作成する条件は重複します:not(y2 < x1 or x2 < y1)
、これはy2 >= x1 and x2 >= y1
と同等です(Simonが受け入れた回答と同じです)。
すでに最も効率的な表現があります-x1 <x2などであることが確実にわからない限り、チェックする必要があるのは最低限であり、他の人が提供するソリューションを使用してください。
おそらく、いくつかのコンパイラは実際にこれを最適化することに注意する必要があります-これらの4つの式のいずれかがtrueを返すとすぐに戻ります。 1つがtrueを返すと、最終結果も返されるため、他のチェックはスキップできます。
私の場合は異なります。 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パターンがあることがわかります