Facebook Pixel

2446. Determine if Two Events Have Conflict

Problem Description

You are given two events that occur on the same day, represented as two arrays of strings:

  • event1 = [startTime1, endTime1]
  • event2 = [startTime2, endTime2]

Each time is given in 24-hour format as HH:MM (e.g., "09:30", "14:45").

A conflict occurs when the two events have any overlapping time period - meaning there's at least one moment in time that belongs to both events.

Your task is to determine if these two events conflict with each other. Return true if there is a conflict, and false otherwise.

For example:

  • If event1 is ["10:00", "11:00"] and event2 is ["10:30", "12:00"], they conflict because the time period from 10:30 to 11:00 is common to both events.
  • If event1 is ["10:00", "11:00"] and event2 is ["11:30", "12:00"], they don't conflict because there's no overlapping time.

The solution checks for non-conflict conditions: if one event ends before the other starts (either event1[1] < event2[0] or event1[0] > event2[1]), there's no conflict. Otherwise, the events must overlap. Since string comparison works correctly with the HH:MM format, we can directly compare the time strings without converting them to numbers.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

When thinking about when two events conflict, it's often easier to first consider when they don't conflict. Two events can avoid conflict in only two ways:

  1. The first event ends completely before the second event starts
  2. The second event ends completely before the first event starts

If neither of these conditions is true, then the events must have some overlap.

Let's visualize this with a timeline. For events to NOT conflict:

  • Either event1 ends before event2 starts: event1[1] < event2[0]
  • Or event2 ends before event1 starts: event2[1] < event1[0] (which is the same as event1[0] > event2[1])

If we negate this logic, we get the condition for conflict: not (event1[1] < event2[0] or event1[0] > event2[1])

A key insight here is that we can directly compare the time strings without converting them to minutes or any numerical format. This works because the HH:MM format ensures that string comparison preserves chronological order. For instance, "09:30" < "10:15" < "14:00" works correctly as string comparisons.

This approach elegantly handles all edge cases, including when events touch at their boundaries (like one ending at "10:00" and another starting at "10:00"), which is considered a conflict since they share that exact moment.

Solution Approach

The implementation uses a simple logical negation approach to determine if two events conflict.

The solution checks for the two non-conflicting scenarios:

  1. event1[0] > event2[1]: Event 1 starts after Event 2 ends
  2. event1[1] < event2[0]: Event 1 ends before Event 2 starts

The key steps in the implementation:

  1. Direct String Comparison: Since the time format is HH:MM, we can directly compare the strings lexicographically. This works because:

    • Hours are zero-padded (e.g., "09:30" not "9:30")
    • The format ensures chronological order matches alphabetical order
    • "08:00" < "09:30" < "14:45" < "23:59" works correctly as string comparisons
  2. Negation Logic: Instead of checking all possible overlap scenarios, we check for non-overlap and negate it:

    return not (event1[0] > event2[1] or event1[1] < event2[0])
  3. Boundary Cases: The solution correctly handles edge cases:

    • When events touch exactly at a boundary point (e.g., one ends at "10:00" and another starts at "10:00"), the condition event1[1] < event2[0] is false, and event1[0] > event2[1] is also false, so the negation returns true (conflict exists)
    • When events are completely disjoint with a gap between them, one of the conditions will be true, making the overall result false (no conflict)

The visual representation from the reference helps understand this:

  • If the events are positioned such that neither "completely before" condition is satisfied, they must overlap somewhere in the middle, indicating a conflict.

This approach has O(1) time complexity since we're only doing two string comparisons, and O(1) space complexity as no additional data structures are needed.

Ready to land your dream job?

Unlock your dream job with a 3-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through the solution with a concrete example to understand how the conflict detection works.

Example:

  • event1 = ["09:30", "11:00"]
  • event2 = ["10:30", "12:00"]

Step 1: Identify the conditions for non-conflict Two events DON'T conflict if:

  • Condition A: event1 starts after event2 ends (event1[0] > event2[1])
  • Condition B: event1 ends before event2 starts (event1[1] < event2[0])

Step 2: Check Condition A Does event1 start after event2 ends?

  • event1[0] = "09:30"
  • event2[1] = "12:00"
  • Is "09:30" > "12:00"? No (9:30 AM is before 12:00 PM)

Step 3: Check Condition B Does event1 end before event2 starts?

  • event1[1] = "11:00"
  • event2[0] = "10:30"
  • Is "11:00" < "10:30"? No (11:00 AM is after 10:30 AM)

Step 4: Apply the negation logic Since neither non-conflict condition is true:

  • not (false or false) = not false = true

Therefore, the events do conflict.

Verification: Let's visualize the overlap on a timeline:

event1: [09:30 -------- 11:00]
event2:         [10:30 -------- 12:00]
                 ^^^^^^
                overlap from 10:30 to 11:00

The overlap period from 10:30 to 11:00 confirms our result - these events conflict!

Counter-example with no conflict: If event2 were ["11:30", "12:00"] instead:

  • Condition A: Is "09:30" > "12:00"? No
  • Condition B: Is "11:00" < "11:30"? Yes!
  • Result: not (false or true) = not true = false (no conflict)

This demonstrates how the algorithm correctly identifies both conflicting and non-conflicting events using simple string comparisons.

Solution Implementation

1from typing import List
2
3class Solution:
4    def haveConflict(self, event1: List[str], event2: List[str]) -> bool:
5        """
6        Determine if two events have a time conflict.
7      
8        Args:
9            event1: List containing [start_time, end_time] as strings in "HH:MM" format
10            event2: List containing [start_time, end_time] as strings in "HH:MM" format
11      
12        Returns:
13            bool: True if events overlap, False otherwise
14        """
15        # Two events DO NOT conflict if:
16        # 1. Event1 starts after event2 ends (event1[0] > event2[1])
17        # 2. Event1 ends before event2 starts (event1[1] < event2[0])
18        # 
19        # Therefore, events HAVE a conflict when neither of these conditions is true
20        # Using De Morgan's law: not (A or B) = (not A) and (not B)
21        # Which means: events overlap when event1 doesn't start after event2 ends 
22        # AND event1 doesn't end before event2 starts
23      
24        return not (event1[0] > event2[1] or event1[1] < event2[0])
25
1class Solution {
2    /**
3     * Determines if two events have a time conflict.
4     * Each event is represented by a start and end time in "HH:MM" format.
5     * 
6     * @param event1 Array containing start time [0] and end time [1] of first event
7     * @param event2 Array containing start time [0] and end time [1] of second event
8     * @return true if the events overlap, false otherwise
9     */
10    public boolean haveConflict(String[] event1, String[] event2) {
11        // Extract start and end times for better readability
12        String event1Start = event1[0];
13        String event1End = event1[1];
14        String event2Start = event2[0];
15        String event2End = event2[1];
16      
17        // Two events do NOT conflict if:
18        // 1. Event1 starts after Event2 ends (event1Start > event2End), OR
19        // 2. Event1 ends before Event2 starts (event1End < event2Start)
20        // 
21        // Therefore, events DO conflict when neither condition is true
22        boolean event1StartsAfterEvent2Ends = event1Start.compareTo(event2End) > 0;
23        boolean event1EndsBeforeEvent2Starts = event1End.compareTo(event2Start) < 0;
24      
25        return !(event1StartsAfterEvent2Ends || event1EndsBeforeEvent2Starts);
26    }
27}
28
1class Solution {
2public:
3    bool haveConflict(vector<string>& event1, vector<string>& event2) {
4        // Two events have a conflict if they overlap in time
5        // Events do NOT conflict if:
6        // 1. event1 starts after event2 ends (event1[0] > event2[1])
7        // 2. event1 ends before event2 starts (event1[1] < event2[0])
8        // If neither condition is true, the events must overlap
9        return !(event1[0] > event2[1] || event1[1] < event2[0]);
10    }
11};
12
1/**
2 * Determines if two events have a time conflict
3 * @param event1 - First event with [startTime, endTime] in "HH:MM" format
4 * @param event2 - Second event with [startTime, endTime] in "HH:MM" format
5 * @returns true if the events overlap, false otherwise
6 */
7function haveConflict(event1: string[], event2: string[]): boolean {
8    // Two events don't conflict only when:
9    // 1. Event1 starts after Event2 ends (event1[0] > event2[1])
10    // 2. Event1 ends before Event2 starts (event1[1] < event2[0])
11    // If neither condition is true, the events overlap
12    return !(event1[0] > event2[1] || event1[1] < event2[0]);
13}
14

Time and Space Complexity

The time complexity is O(1) because the algorithm performs a fixed number of operations regardless of input size. It only compares two pairs of strings (the start and end times of two events) using simple comparison operators. String comparison in this context is O(1) since the time strings have a fixed format (HH:MM) with constant length.

The space complexity is O(1) because the algorithm uses no additional data structures or variables that scale with input size. It only performs direct comparisons on the input parameters and returns a boolean result, requiring constant extra space.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Incorrect Boundary Handling - Treating Touch Points as Non-Conflicts

The Pitfall: A common mistake is assuming that when two events touch exactly at their boundaries (one ends exactly when the other starts), they don't conflict. This leads to using >= or <= comparisons instead of > or <.

Incorrect Implementation:

def haveConflict(self, event1: List[str], event2: List[str]) -> bool:
    # WRONG: Using >= and <= for boundary conditions
    return not (event1[0] >= event2[1] or event1[1] <= event2[0])

Why It's Wrong:

  • If event1 = ["10:00", "11:00"] and event2 = ["11:00", "12:00"]
  • Using event1[1] <= event2[0] would evaluate to "11:00" <= "11:00" = True
  • This would return False (no conflict), but the events DO conflict at exactly 11:00

The Fix: Use strict comparisons (> and <) to ensure touching boundaries are considered conflicts:

def haveConflict(self, event1: List[str], event2: List[str]) -> bool:
    return not (event1[0] > event2[1] or event1[1] < event2[0])

2. Attempting Time Conversion When String Comparison Suffices

The Pitfall: Unnecessarily converting time strings to minutes or other numeric formats, adding complexity and potential for bugs.

Overcomplicated Approach:

def haveConflict(self, event1: List[str], event2: List[str]) -> bool:
    def timeToMinutes(time_str):
        hours, minutes = map(int, time_str.split(':'))
        return hours * 60 + minutes
  
    start1 = timeToMinutes(event1[0])
    end1 = timeToMinutes(event1[1])
    start2 = timeToMinutes(event2[0])
    end2 = timeToMinutes(event2[1])
  
    return not (start1 > end2 or end1 < start2)

Why It's Unnecessary:

  • The "HH:MM" format with zero-padding ensures lexicographic order matches chronological order
  • String comparison is simpler, faster, and less error-prone
  • No risk of conversion errors or edge cases with parsing

The Better Approach: Stick with direct string comparison as shown in the original solution.

3. Confusing the Logic - Double Negation Errors

The Pitfall: Getting confused with the negation logic and accidentally implementing the opposite condition.

Common Mistakes:

# WRONG: Forgetting the 'not'
def haveConflict(self, event1: List[str], event2: List[str]) -> bool:
    return event1[0] > event2[1] or event1[1] < event2[0]  # Returns True for NO conflict

# WRONG: Using 'and' instead of 'or'
def haveConflict(self, event1: List[str], event2: List[str]) -> bool:
    return not (event1[0] > event2[1] and event1[1] < event2[0])  # Incorrect logic

How to Avoid:

  • Remember: Check for non-overlap conditions with OR, then negate
  • Test with simple examples: ["10:00", "11:00"] and ["10:30", "11:30"] should return True
  • Think of it as: "Events conflict UNLESS one is completely before the other"
Discover Your Strengths and Weaknesses: Take Our 3-Minute Quiz to Tailor Your Study Plan:

Given a sorted array of integers and an integer called target, find the element that equals to the target and return its index. Select the correct code that fills the ___ in the given code snippet.

1def binary_search(arr, target):
2    left, right = 0, len(arr) - 1
3    while left ___ right:
4        mid = (left + right) // 2
5        if arr[mid] == target:
6            return mid
7        if arr[mid] < target:
8            ___ = mid + 1
9        else:
10            ___ = mid - 1
11    return -1
12
1public static int binarySearch(int[] arr, int target) {
2    int left = 0;
3    int right = arr.length - 1;
4
5    while (left ___ right) {
6        int mid = left + (right - left) / 2;
7        if (arr[mid] == target) return mid;
8        if (arr[mid] < target) {
9            ___ = mid + 1;
10        } else {
11            ___ = mid - 1;
12        }
13    }
14    return -1;
15}
16
1function binarySearch(arr, target) {
2    let left = 0;
3    let right = arr.length - 1;
4
5    while (left ___ right) {
6        let mid = left + Math.trunc((right - left) / 2);
7        if (arr[mid] == target) return mid;
8        if (arr[mid] < target) {
9            ___ = mid + 1;
10        } else {
11            ___ = mid - 1;
12        }
13    }
14    return -1;
15}
16

Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More