Solution: Insert Interval
Let's solve the Insert Interval problem using the Merge Intervals pattern.
Statement
Given a sorted list of nonoverlapping intervals and a new interval, your task is to insert the new interval into the correct position while ensuring that the resulting list of intervals remains sorted and nonoverlapping. Each interval is a pair of nonnegative numbers, the first being the start time and the second being the end time of the interval.
Constraints:
-
existing_intervals.length
-
existing_intervals[i].length
,new_interval.length
== 2 -
start time end time
-
The list of intervals is sorted in ascending order based on the .
Solution
So far, you’ve probably brainstormed some approaches and have an idea of how to solve this problem. Let’s explore some of these approaches and figure out which one to follow based on considerations such as time complexity and any implementation constraints.
Naive approach
The naive approach involves iterating through the list of intervals and checking for overlaps with a new interval. If overlap occurs, the new interval merges with the existing one. After iterating the entire list, if no overlap occurs, append the new interval. Finally, we sort the list based on the start times of the intervals to ensure the correct order of intervals.
Iterating through the intervals to merge or append the new interval based on overlaps takes
Optimized approach using the merge intervals pattern
The solution’s essence lies in integrating a new interval into a sorted list of nonoverlapping intervals while preserving order and nonoverlap. It involves linearly scanning the list of intervals and identifying the correct position to insert the new interval while handling overlaps. The new interval is simply inserted into the appropriate position if there are no overlaps. If overlaps are detected, the intervals are merged accordingly.
Now, let's look at the workflow of the implementation:
The problem requires us to do two things. First, we need to insert a new interval into a sequence of nonoverlapping intervals. Second, the result should also be a list of nonoverlapping intervals. This requires merging the new interval with any overlapping interval(s) in the input. Therefore, the merge interval pattern applies.
Note: In the following section, we will gradually build the solution. Alternatively, you can skip straight to just the code.
Step-by-step solution construction
First, we process the intervals that start before the new interval and then insert the new interval itself. Additionally, we need to merge the new interval with the existing intervals in the input.
Here’s how we’ll implement this feature:
Since the intervals are sorted, we’ll create an empty list,
output
, and add the intervals that start before the new interval.Next, we’ll add the new interval to the
output
list and merge it with the previously added interval if there is an overlap.Finally, we’ll add the remaining intervals to the
output
list, merging them with the previously added intervals when they overlap.
We’ll examine these steps and how they work individually to gain a more comprehensive understanding of our solution. The first step is to see the new interval to be added and append all the intervals that start before it to a new list, which we will use as our output later.
import java.util.*;class Solution {public static void insertInterval(int[][] existingIntervals, int[] newInterval) {// Read the starting and ending time of the new interval, into separate variablesint newStart = newInterval[0];int newEnd = newInterval[1];System.out.println("The new interval starts at " + newStart + " and ends at " + newEnd + ".");// Initialize variables to help in iterating over the existing intervals listint i = 0;int n = existingIntervals.length;System.out.println("There are " + n + " intervals present in the list already.");// Initialize an empty list to store the outputList<int[]> output = new ArrayList<>();// Append all intervals that start before the new interval to the output listSystem.out.println("Let's start adding these intervals into our output list one by one, until we come across an overlapping interval.");System.out.println(new String(new char[100]).replace('\0', '-'));while (i < n && existingIntervals[i][0] < newStart) {output.add(existingIntervals[i]);System.out.println("We can add " + (i + 1) + " intervals in our new list without merging any intervals yet:");System.out.println(display(output));i += 1;System.out.println(new String(new char[100]).replace('\0', '-'));}System.out.println();}public static String display(List<int[]> l1) {StringBuilder resultStr = new StringBuilder("[");if (!l1.isEmpty()) {for (int i = 0; i < l1.size() - 1; i++) {resultStr.append("[").append(l1.get(i)[0]).append(", ").append(l1.get(i)[1]).append("], ");}resultStr.append("[").append(l1.get(l1.size() - 1)[0]).append(", ").append(l1.get(l1.size() - 1)[1]).append("]");}resultStr.append("]");return resultStr.toString();}// Driver Codepublic static void main(String[] args) {int[][] newIntervals = {{5, 7},{8, 9},{10, 12},{1, 3},{1, 10}};int[][][] existingIntervals = {{{1, 2}, {3, 5}, {6, 8}},{{1, 3}, {5, 7}, {10, 12}},{{8, 10}, {12, 15}},{{5, 7}, {8, 9}},{{3, 5}}};for (int i = 0; i < newIntervals.length; i++) {System.out.println("Existing intervals: " + display(Arrays.asList(existingIntervals[i])));System.out.println("New interval: [" + newIntervals[i][0] + ", " + newIntervals[i][1] + "]");insertInterval(existingIntervals[i], newIntervals[i]);System.out.println(new String(new char[100]).replace('\0', '-'));}}}
After appending the intervals that start before the new interval to the output list, we check if any intervals in the output list overlap with the new interval. If an overlap is found, we merge the intervals by updating the end time of the last interval in the output list to the maximum of its current end time and the end time of the new interval.
In this step, we handle the merging of intervals if there is an overlap with the new interval.
import java.util.*;class Solution {public static void insertInterval(int[][] existingIntervals, int[] newInterval) {// Read the starting and ending time of the new interval into separate variablesint newStart = newInterval[0];int newEnd = newInterval[1];System.out.println("The new interval starts at " + newStart + " and ends at " + newEnd + ".");// Initialize variables to help in iterating over the existing intervals listint i = 0;int n = existingIntervals.length;System.out.println("There are " + n + " intervals present in the list already.");// Initialize an empty list to store the outputList<int[]> output = new ArrayList<>();// Append all intervals that start before the new interval to the output listSystem.out.println("Let's start adding these intervals into our output list one by one, until we come across an overlapping interval.");System.out.println(new String(new char[100]).replace('\0', '-'));while (i < n && existingIntervals[i][0] < newStart) {output.add(existingIntervals[i]);i += 1;}System.out.println("The current output list of intervals without any overlapping intervals is: " + Arrays.deepToString(output.toArray()));// If the new interval starts after the end of the last interval appended to the output list,// just append the new interval to the output list.if (output.size() == 0 || output.get(output.size() - 1)[1] < newStart) {output.add(newInterval);} else {// Otherwise, merge the two intervalsoutput.get(output.size() - 1)[1] = Math.max(output.get(output.size() - 1)[1], newEnd);}System.out.println("The output after merging this overlapping interval will be: " + Arrays.deepToString(output.toArray()));i += 1;System.out.println(new String(new char[100]).replace('\0', '-'));}// Driver Codepublic static void main(String[] args) {int[][] newIntervals = {{5, 7},{8, 9},{10, 12},{1, 3},{1, 10}};int[][][] existingIntervals = {{{1, 2}, {3, 5}, {6, 8}},{{1, 3}, {5, 7}, {10, 12}},{{8, 10}, {12, 15}},{{5, 7}, {8, 9}},{{3, 5}}};for (int i = 0; i < newIntervals.length; i++) {System.out.println("Existing intervals: " + Arrays.deepToString(existingIntervals[i]));System.out.println("New interval: [" + newIntervals[i][0] + ", " + newIntervals[i][1] + "]");insertInterval(existingIntervals[i], newIntervals[i]);System.out.println(new String(new char[100]).replace('\0', '-'));}}}
In this step, we handle the remaining intervals in the existing interval list after adding the new interval. We iterate through the remaining intervals and merge them with the intervals in the output list if there is an overlap. By comparing start and end times, we determine if an interval should be appended or merged. This process ensures that all overlapping intervals are correctly merged into the output list.
Finally, we obtain the final output list representing the merged intervals from the existing and new intervals.
import java.util.*;class Solution {public static int[][] insertInterval(int[][] existingIntervals, int[] newInterval) {// Read the starting and ending time of the new interval into separate variablesint newStart = newInterval[0];int newEnd = newInterval[1];System.out.println("The new interval starts at " + newStart + " and ends at " + newEnd + ".");// Initialize variables to help in iterating over the existing intervals arrayint i = 0;int n = existingIntervals.length;System.out.println("There are " + n + " intervals present in the list already. We append the intervals that have the starting point smaller than our new interval to add.");// Initialize a list to store the output temporarilyList<int[]> outputList = new ArrayList<>();// Append all intervals that start before the new interval to the output listwhile (i < n && existingIntervals[i][0] < newStart) {outputList.add(existingIntervals[i]);i += 1;}System.out.println("The output before we add the new interval is: " + Arrays.deepToString(outputList.toArray()));// If the new interval starts after the end of the last interval appended to the output list,// just append the new interval to the output list.if (outputList.size() == 0 || outputList.get(outputList.size() - 1)[1] < newStart) {outputList.add(newInterval);} else {// Otherwise, merge the two intervalsoutputList.get(outputList.size() - 1)[1] = Math.max(outputList.get(outputList.size() - 1)[1], newEnd);}// Copy any remaining intervals to the output list,// similarly merging any overlapping intervals as we gowhile (i < n) {int[] existingInterval = existingIntervals[i];int start = existingInterval[0];int end = existingInterval[1];if (outputList.get(outputList.size() - 1)[1] < start) {outputList.add(existingInterval);} else {outputList.get(outputList.size() - 1)[1] = Math.max(outputList.get(outputList.size() - 1)[1], end);}i += 1;}// Convert the list back to a 2D arrayint[][] outputArray = outputList.toArray(new int[0][0]);System.out.println("The output after we add the new interval and merge the overlapping intervals is: " + Arrays.deepToString(outputList.toArray()));return outputArray;}// Driver Codepublic static void main(String[] args) {int[][] newIntervals = {{5, 7},{8, 9},{10, 12},{1, 3},{1, 10}};int[][][] existingIntervals = {{{1, 2}, {3, 5}, {6, 8}},{{1, 3}, {5, 7}, {10, 12}},{{8, 10}, {12, 15}},{{5, 7}, {8, 9}},{{3, 5}}};for (int i = 0; i < newIntervals.length; i++) {System.out.println("Existing intervals: " + Arrays.deepToString(existingIntervals[i]));System.out.println("New interval: [" + newIntervals[i][0] + ", " + newIntervals[i][1] + "]");insertInterval(existingIntervals[i], newIntervals[i]);System.out.println(new String(new char[100]).replace('\0', '-'));}}}
Just the code
Here’s the complete solution to this problem:
import java.util.*;class Solution {public static int[][] insertInterval(int[][] existingIntervals, int[] newInterval) {int newStart = newInterval[0];int newEnd = newInterval[1];int i = 0;int n = existingIntervals.length;List<int[]> outputList = new ArrayList<>();while (i < n && existingIntervals[i][0] < newStart) {outputList.add(existingIntervals[i]);i += 1;}if (outputList.size() == 0 || outputList.get(outputList.size() - 1)[1] < newStart) {outputList.add(newInterval);} else {outputList.get(outputList.size() - 1)[1] = Math.max(outputList.get(outputList.size() - 1)[1], newEnd);}while (i < n) {int[] ei = existingIntervals[i];int start = ei[0];int end = ei[1];if (outputList.get(outputList.size() - 1)[1] < start) {outputList.add(ei);} else {outputList.get(outputList.size() - 1)[1] = Math.max(outputList.get(outputList.size() - 1)[1], end);}i += 1;}return outputList.toArray(new int[0][0]);}// Driver codepublic static void main(String[] args) {int[][] newIntervals = {{5, 7},{8, 9},{10, 12},{1, 3},{1, 10}};int[][][] existingIntervals = {{{1, 2}, {3, 5}, {6, 8}},{{1, 3}, {5, 7}, {10, 12}},{{8, 10}, {12, 15}},{{5, 7}, {8, 9}},{{3, 5}}};for (int i = 0; i < newIntervals.length; i++) {System.out.print((i + 1) + ".\tExisting intervals: ");System.out.println(Arrays.deepToString(existingIntervals[i]));System.out.println("\tNew interval: [" + newIntervals[i][0] + ", " + newIntervals[i][1] + "]");int[][] output = insertInterval(existingIntervals[i], newIntervals[i]);System.out.println("\tUpdated intervals: " + Arrays.deepToString(output));System.out.println(new String(new char[100]).replace('\0', '-'));}}}
Solution summary
- Append all intervals occurring before the new interval to the
output
list until we find an interval that starts after the starting point of the new interval. - If there is an overlap between the last interval in the
output
list and the new interval, merge them by updating the end value of the last interval. Otherwise, append the new interval to theoutput
list. - Continue iterating through the remaining intervals and merge the overlapping intervals with the last interval in the
output
list. - Return the final
output
list containing the merged intervals.
Time complexity
The time complexity is , where is the number of intervals in the input list. This is because we iterate through the list once, checking and merging intervals as necessary.
Space complexity
The space complexity is .
Level up your interview prep. Join Educative to access 70+ hands-on prep courses.