Problem overview
The method intersect(self, A1, B1, A2, B2) receives two closed intervals, [A1, B1] and [A2, B2]. It returns True if the intervals share at least one number and False if they do not. "Closed" means the end points belong to the interval, so [1, 4] includes both 1 and 4.
Take the examples. [1, 6] and [3, 8] overlap on 3 to 6, so the answer is True. [1, 4] and [4, 6] share only the number 4, which is enough, so the answer is True. [1, 8] contains [4, 6] completely, so the answer is True. [4, 6] and [1, 3] have nothing in common, so the answer is False.
Approach: find the cases that do not overlap
There are many ways two intervals can overlap: partially from the left, partially from the right, one inside the other, both equal. Checking each one is easy to get wrong. There are only two ways they can fail to overlap:
- The first interval ends before the second starts:
B1 < A2. - The second interval ends before the first starts:
B2 < A1.
If neither is true, the intervals must overlap, so the answer is the negation of "one is entirely to the left of the other".
The comparisons are strict (<, not <=). When B1 == A2 the intervals touch at one number, and for closed intervals a shared end point counts as an intersection. With <= the example [1, 4] and [4, 6] would wrongly come out as False.
Step by step
- Write the "misses" condition.
B1 < A2 or B2 < A1is true exactly when one interval lies entirely to the left of the other. - Put it in parentheses and negate it with
not. Without the parentheses,notwould apply only to the first comparison. - Return the result directly. The expression already evaluates to
TrueorFalse, so noif/elseis needed.
The solution in Python
class Solution:
def intersect(self, A1: int, B1: int, A2: int, B2: int) -> bool:
return not (B1 < A2 or B2 < A1)
A few Python details:
- Comparison operators already produce a
bool, andorandnotkeep it that way, so the singlereturnreplaces anifthat returnsFalseand a second return ofTrue. orshort-circuits: ifB1 < A2is true, the second comparison is never evaluated.notbinds more loosely than comparison operators but more tightly thanor, which is why the parentheses matter:not B1 < A2 or B2 < A1would mean(not (B1 < A2)) or (B2 < A1), a different condition.
An equivalent form
Applying De Morgan's laws, not (P or Q) becomes (not P) and (not Q), and the negation of < is >=. So the same test can be written as A2 <= B1 and A1 <= B2: each interval starts no later than the other one ends. Both forms return identical answers for every input.
Complexity
- Time: O(1). At most two comparisons, whatever the values are.
- Space: O(1). No extra variables.
Edge cases and common mistakes
- Touching end points.
[1, 3]and[3, 5]intersect at 3, and the strict comparisons giveTrue. - Single-point intervals.
[2, 2]against[2, 2]isTrue, while[2, 2]against[3, 3]isFalse. - Order of the two intervals. The result is the same if you swap them:
intersect(5, 7, 1, 3)andintersect(1, 3, 5, 7)both returnFalse. That is why the condition checks both directions. - Checking only one direction. Testing just
B1 < A2misses the case where the second interval is on the left, like[4, 6]and[1, 3]. - Using
andwhereorbelongs. The intervals miss each other when either condition holds, not when both hold.
Testing
s = Solution()
print(s.intersect(1, 6, 3, 8)) # True
print(s.intersect(1, 4, 4, 6)) # True
print(s.intersect(1, 8, 4, 6)) # True
print(s.intersect(4, 6, 1, 3)) # False
print(s.intersect(1, 3, 5, 7)) # False
Since the comparisons work on any numbers, the same method handles floats: intersect(1.5, 2.5, 2.5, 3) is True.
