You are given a list of time intervals represented as an array of arrays, where each inner array contains the start and end time of an interval. The goal is to merge all overlapping intervals and return a new array containing only the non-overlapping intervals that cover all the intervals in the input.
For example:
Input: intervals = [[1,3],[2,6],[8,10],[15,18]]
Output: [[1,6],[8,10],[15,18]]
[1,3]
and [2,6]
overlap, merge them into [1,6]
.Input: intervals = [[1,4],[4,5]]
Output: [[1,5]]
[1,4]
and [4,5]
are considered overlapping.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
We have a list of time periods, like appointments, each with a start and end time. The brute force way to merge these overlapping periods is to check every possible pair of periods to see if they overlap and can be combined. This is a very thorough, but not very efficient approach.
Here's how the algorithm would work step-by-step:
def merge_intervals_brute_force(intervals):
merged_intervals = intervals[:]
number_of_intervals = len(intervals)
for i in range(number_of_intervals):
for j in range(number_of_intervals):
# Avoid comparing an interval with itself
if i == j:
continue
first_interval = merged_intervals[i]
second_interval = merged_intervals[j]
# Check for valid intervals
if first_interval is None or second_interval is None:
continue
first_start = first_interval[0]
first_end = first_interval[1]
second_start = second_interval[0]
second_end = second_interval[1]
# Check if the intervals overlap
if (first_start <= second_end and first_end >= second_start):
# Merge overlapping intervals to encompass both ranges
new_start = min(first_start, second_start)
new_end = max(first_end, second_end)
merged_intervals[i] = [new_start, new_end]
merged_intervals[j] = None
# Filter out any intervals set to None (merged intervals)
result = [interval for interval in merged_intervals if interval is not None]
return result
The most efficient way to merge intervals involves sorting them first, then combining overlapping intervals as you go. Sorting allows you to process intervals in order, making it easy to identify overlaps and create the merged set.
Here's how the algorithm would work step-by-step:
def merge_intervals(intervals):
# Sort the intervals based on their start times.
intervals.sort(key=lambda interval: interval[0])
merged_intervals = []
for interval in intervals:
# If the list of merged intervals is empty or if the current
# interval does not overlap with the last interval, append it.
if not merged_intervals or merged_intervals[-1][1] < interval[0]:
merged_intervals.append(interval)
else:
# Otherwise, there is overlap, so we merge the current and previous
# intervals, updating the end time of the last merged interval
merged_intervals[-1][1] = max(merged_intervals[-1][1], interval[1])
return merged_intervals
Case | How to Handle |
---|---|
Empty input intervals array | Return an empty list, as there are no intervals to merge. |
Single interval in the input array | Return the input array as is, since there's nothing to merge. |
Intervals are already non-overlapping and sorted | After sorting the intervals, no merging will occur and the original sorted list will be returned. |
Intervals are in reverse sorted order | The sorting step ensures correct merging regardless of the initial order. |
Intervals with identical start and end points (e.g., [1, 1]) | These intervals should be handled correctly during the merging process. |
Intervals with large integer values causing potential overflow during comparisons | Ensure the comparison logic uses appropriate data types and handles potential overflow issues. |
Intervals that completely overlap (e.g., [1, 5] and [2, 4]) | The merging logic should correctly reduce these to the encompassing interval [1, 5]. |
Input contains intervals with negative numbers | The solution should correctly handle negative start and end points after sorting. |