Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@
* [Decoding](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/huffman/decoding.py)
* [Encoding](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/huffman/encoding.py)
* Intervals
* Can Attend Meetings
* [Test Can Attend Meetings](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/intervals/can_attend_meetings/test_can_attend_meetings.py)
* Car Pooling
* [Test Car Pooling](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/intervals/car_pooling/test_car_pooling.py)
* Count Days
Expand Down
23 changes: 23 additions & 0 deletions algorithms/intervals/can_attend_meetings/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Can Attend Meetings

Write a function to check if a person can attend all the meetings scheduled without any time conflicts. Given an array
intervals, where each element [s1, e1] represents a meeting starting at time s1 and ending at time e1, determine if
there are any overlapping meetings. If there is no overlap between any meetings, return true; otherwise, return false.

Note that meetings ending and starting at the same time, such as (0,5) and (5,10), do not conflict.

Examples:

```text
Input: intervals = [(1,5),(3,9),(6,8)]
Output: False

Explanation: The meetings (1,5) and (3,9) overlap.
```

```text
Input: intervals = [(10,12),(6,9),(13,15)]
Output: True

Explanation: There are no overlapping meetings, so the person can attend all.
```
60 changes: 60 additions & 0 deletions algorithms/intervals/can_attend_meetings/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from typing import List


def can_attend_meetings(intervals: List[List[int]]) -> bool:
"""
Checks if an employee can attend all meetings given a list of intervals representing the start and end times of each
meeting.

A person can attend all meetings if and only if none of the meetings overlap. By sorting the intervals by start time,
we can easily check if any two consecutive intervals overlap.

We iterate over each interval, beginning with the second interval in the sorted list. We compare the start time of
the current interval with the end time of the previous interval. If the start time of the current interval is less
than the end time of the previous interval, then the two intervals overlap and the person cannot attend both meetings,
so we return false.

Otherwise, the person can attend both meetings, and we continue to the next interval. If we reach the end of the
list without finding any overlapping intervals, then the person can attend all meetings, and we return true.

Complexity Analysis

Time Complexity: O(n * logn) where n is the number of intervals. The time complexity is dominated by the sorting step.

Space Complexity:

Since we are sorting the intervals and creating a new sorted_intervals variable that has the sorted intervals by time
the space incurred is O(n). However, if sorting in place, then the space cost becomes O(1) and in that case no extra
extra space would be used beyond a few variables.

Args:
intervals(list): list of intervals where each entry is a list containing the start and end time of a meeting
Returns:
bool: True if an employee can attend all meetings, false otherwise
"""
if len(intervals) == 0:
return True

# Sort the intervals by start time first to enable easier iteration through the intervals. Meetings with similar
# start times will be close to each other, allowing quick and early exit if they overlap.
sorted_intervals = sorted(intervals, key=lambda x: x[0])

# Keep track of the last seen end time.
# We initialize the first interval's end time to keep track of the last interval's end that we have seen so far
last_end_time = sorted_intervals[0][1]

# We then iterate through the list checking if there is any overlaps
# Start from the second interval in the list to check if it overlaps with the previous interval.
for current_interval in sorted_intervals[1:]:
# Get the start and end of the current interval
current_start, current_end = current_interval

if current_start < last_end_time:
# there is an overlap, we return here
return False

# Otherwise, we update the last end time we have seen with this interval's end time
last_end_time = current_end

# If no overlap is found, we return True
return True
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import unittest
from typing import List
from parameterized import parameterized
from algorithms.intervals.can_attend_meetings import can_attend_meetings

CAN_ATTEND_MEETINGS_TEST_CASES = [
([[1, 5], [3, 9], [6, 8]], False),
([[10, 12], [6, 9], [13, 15]], True),
([[0, 30], [5, 10], [15, 20]], False),
([[7, 10], [2, 4]], True),
([[1, 2], [2, 3], [3, 4]], True),
([[1, 2], [2, 3], [3, 4]], True),
([[1, 3], [2, 4], [4, 6]], False),
([[0, 1], [3, 5], [6, 7]], True),
([[10, 20], [20, 30], [30, 40]], True),
([[1, 5], [6, 10], [11, 15]], True),
([[5, 10], [15, 20], [10, 15]], True),
]


class CanAttendMeetingsTestCase(unittest.TestCase):
@parameterized.expand(CAN_ATTEND_MEETINGS_TEST_CASES)
def test_can_attend_meetings(self, intervals: List[List[int]], expected: bool):
actual = can_attend_meetings(intervals)
self.assertEqual(expected, actual)


if __name__ == "__main__":
unittest.main()
Loading