Problem
Given a set of non-overlapping & sorted intervals by start time, insert a new interval into the intervals (merge if necessary).
OR
You are given an array of non-overlapping intervals intervals
where intervals[i] = [starti, endi]
represent the start and the end of the ith
interval and intervals
is sorted in ascending order by starti
. 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 starti
and intervals
still does not have any overlapping intervals (merge overlapping intervals if necessary).
Return intervals
after the insertion.
Examples
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].
Solution
Method 1 - Greedy
If the list was not sorted, we could have appended the newInterval
to the end of list. And then the problem was Merge Overlapping Intervals.
But, given that the intervals are sorted, our task simplifies to finding the correct index where the newInterval
can be placed. By We can iterate through given intervals
list, and we encounter three scenarios:
- Before New Interval (
newInterval.end <interval.start
): If the end ofnewInterval
is before the start of the current interval, we insertnewInterval
into the list at this position. - After New Interval (
newInterval.start > interval.end
): If the start ofnewInterval
is after the end of the current interval, we skip these intervals and eventually insertnewInterval
after the current interval. - Overlapping Intervals: When there is an overlap, we merge
newInterval
with the current interval. The merged interval will have:c.start=min(newInterval.start, interval.start)
andc.end=max(newInterval.end, interval.end)
Here is the visual view of how the 3 cases will look. Whenever there is intersection, created a new interval.
Code
Java
Interval as array - 1 Loop Solution
public int[][] insert(int[][] intervals, int[] newInterval) {
List<int[]> ans = new LinkedList<>();
for(int[] interval: intervals){
if(interval[1] < newInterval[0]){
ans.add(interval);
}else if(interval[0] > newInterval[1]){
ans.add(newInterval);
newInterval = interval;
}else if(interval[1] >= newInterval[0] || interval[0] <= newInterval[1]){
int start = Math.min(interval[0], newInterval[0]);
int end = Math.max(interval[1], newInterval[1]);
newInterval = new int[]{start, end};
}
}
ans.add(newInterval);
return ans.toArray(int[][]::new);
}
Interval as array - 3 Loop Solution
We can also break our loop into 3 parts:
class Solution {
public int[][] insert(int[][] intervals, int[] newInterval) {
List<int[]> ans = new ArrayList<>();
int i = 0, n = intervals.length;
// Add all intervals that end before newInterval starts
while (i < n && intervals[i][1] < newInterval[0]) {
ans.add(intervals[i++]);
}
// Merge intervals that overlap with newInterval
while (i < n && intervals[i][0] <= newInterval[1]) {
newInterval[0] = Math.min(newInterval[0], intervals[i][0]);
newInterval[1] = Math.max(newInterval[1], intervals[i][1]);
i++;
}
ans.add(newInterval);
// Add remaining intervals
while (i < n) {
ans.add(intervals[i++]);
}
return ans.toArray(new int[ans.size()][]);
}
}
Interval as a class - 1 Loop Solution
public List<Interval> insert(List<Interval> intervals, Interval newInterval) {
List<Interval> ans = new ArrayList<Interval> ();
for (Interval interval: intervals) {
if (interval.end<newInterval.start) {
ans.add(interval);
} else if (interval.start > newInterval.end) {
ans.add(newInterval);
newInterval = interval;
} else if (interval.end >= newInterval.start || interval.start<= newInterval.end) {
newInterval = new Interval(Math.min(interval.start, newInterval.start), Math.max(newInterval.end, interval.end));
}
}
ans.add(newInterval);
return ans;
}
Similar code with arrays as interval:
Rust
impl Solution {
pub fn insert(intervals: Vec<Vec<i32>>, new_interval: Vec<i32>) -> Vec<Vec<i32>> {
use std::cmp::{min, max};
let mut ans = vec![];
let mut new_interval = new_interval;
for interval in intervals {
if interval[1] < new_interval[0] {
ans.push(interval);
}else if interval[0] > new_interval[1] {
ans.push(new_interval);
new_interval = interval;
}else {
let start = min(interval[0], new_interval[0]);
let end = max(interval[1], new_interval[1]);
new_interval = vec![start, end];
}
}
ans.push(new_interval);
ans
}
}