You are given an array of non-overlapping intervals intervals
where intervals[i] = [start<sub>i</sub>, end<sub>i</sub>]
represent the start and the end of the i<sup>th</sup>
interval, and intervals
is sorted in ascending order by start<sub>i</sub>
. You are also given an interval newInterval = [start, end]
that represents the start and end of another interval.
Insert newInterval
into intervals
such that intervals
is still sorted in ascending order by start<sub>i</sub>
and intervals
still does not have any overlapping intervals (merge overlapping intervals if necessary).
Return intervals
after the insertion.
Note that you don't need to modify intervals
in-place. You can make a new array and return it.
Example 1:
Input: intervals = [[1,3],[6,9]], newInterval = [2,5]
Output: [[1,5],[6,9]]
Example 2:
Input: intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]
Output: [[1,2],[3,10],[12,16]]
Explanation: Because the new interval [4,8] overlaps with [3,5],[6,7],[8,10].
Can you provide a function that inserts newInterval
into intervals
while maintaining the sorted, non-overlapping properties of the intervals?
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 set of existing time intervals and a new time interval to insert into the set. The brute force approach involves going through all possibilities of how the new interval can fit within the existing set, checking overlaps and merging as needed.
Here's how the algorithm would work step-by-step:
def insert_interval_brute_force(existing_intervals, new_interval):
# Add the new interval to the list
combined_intervals = existing_intervals + [new_interval]
# Sort the intervals based on start time
combined_intervals.sort(key=lambda interval: interval[0])
merged_intervals = []
index = 0
while index < len(combined_intervals):
current_interval = combined_intervals[index]
# Start by assuming no overlap
while index + 1 < len(combined_intervals) and \
current_interval[1] >= combined_intervals[index + 1][0]:
next_interval = combined_intervals[index + 1]
# Perform the merge
current_interval = [min(current_interval[0], next_interval[0]), \
max(current_interval[1], next_interval[1])]
index += 1
merged_intervals.append(current_interval)
index += 1
return merged_intervals
The optimal approach avoids needlessly comparing the new interval with every existing interval. It breaks down the task into three clear stages: adding intervals that come completely before the new one, merging overlapping intervals, and adding intervals that come completely after the new one.
Here's how the algorithm would work step-by-step:
def insert_interval(existing_intervals, new_interval):
merged_intervals = []
interval_index = 0
# Add all intervals ending before the new interval.
while interval_index < len(existing_intervals) and existing_intervals[interval_index][1] < new_interval[0]:
merged_intervals.append(existing_intervals[interval_index])
interval_index += 1
# Merge overlapping intervals.
while interval_index < len(existing_intervals) and existing_intervals[interval_index][0] <= new_interval[1]:
# Adjust the new interval to encompass the overlapping interval.
new_interval[0] = min(new_interval[0], existing_intervals[interval_index][0])
new_interval[1] = max(new_interval[1], existing_intervals[interval_index][1])
interval_index += 1
merged_intervals.append(new_interval)
# Add all remaining intervals.
while interval_index < len(existing_intervals):
# Add the rest of the intervals as they do not overlap.
merged_intervals.append(existing_intervals[interval_index])
interval_index += 1
return merged_intervals
Case | How to Handle |
---|---|
Empty intervals array | If the intervals array is empty, return the new interval as the only element in the resulting array. |
Null intervals array or new interval | Throw an IllegalArgumentException or return null to indicate invalid input. |
New interval completely before all existing intervals | Insert the new interval at the beginning of the result list. |
New interval completely after all existing intervals | Append the new interval at the end of the result list. |
New interval overlaps with multiple existing intervals. | Merge all overlapping intervals into a single, larger merged interval. |
New interval is contained entirely within an existing interval | The existing interval remains unchanged in the resulting array as there is no merging required. |
New interval is identical to an existing interval. | The new interval will merge with the existing, with the result equivalent to the original interval, so no change is needed. |
Large input size (many intervals) | Ensure the algorithm has linear time complexity and does not use excessive memory, which might require optimization of operations like list insertions and deletions. |