Skip to content
Related Articles

Related Articles

Improve Article

Insert in sorted and non-overlapping interval array

  • Difficulty Level : Hard
  • Last Updated : 17 Dec, 2020

Given a set of non-overlapping intervals and a new interval, insert the interval at correct position. If the insertion results in overlapping intervals, then merge the overlapping intervals. Assume that the set of non-overlapping intervals is sorted on the basis of start time, to find correct position of insertion.

Prerequisite: Merge the intervals

Examples: 

Input: Set : [1, 3], [6, 9]
        New Interval : [2, 5] 
Output: [1, 5], [6, 9]
The correct position to insert new interval 
[2, 5] is between the two given intervals. 
The resulting set would have been 
[1, 3], [2, 5], [6, 9], but the intervals 
[1, 3], [2, 5] are overlapping. So, they are 
merged together in one interval [1, 5]. 

Input: Set : [1, 2], [3, 5], [6, 7], [8, 10], [12, 16]
        New Interval : [4, 9]
Output: [1, 2], [3, 10], [12, 16]
First the interval is inserted between intervals 
[3, 5] and [6, 7]. Then overlapping intervals are 
merged together in one interval.

Approach: 
Let the new interval to be inserted is : [a, b] 
Case 1 : b < (starting time of first interval in set) 
In this case simply insert new interval at the beginning of the set.
Case 2 : (ending value of last interval in set) < a 
In this case simply insert new interval at the end of the set.
Case 3 : a ? (starting value of first interval) and b ? (ending value of last interval) 
In this case the new interval overlaps with all the intervals, i.e., it contains all the intervals. So the final answer is the new interval itself.
Case 4 : The new interval does not overlap with any interval in the set and falls between any two intervals in the set 
In this case simply insert the interval in the correct position in the set. A sample test case for this is : 

Input: Set : [1, 2], [6, 9]
        New interval : [3, 5]
Output: [1, 2], [3, 5], [6, 9]

Case 5 : The new interval overlaps with the interval(s) of the set. 
In this case simply merge the new interval with overlapping intervals. To have a better understanding of how to merge overlapping intervals, refer this post : Merge Overlapping Intervals 



Example 2 of sample test cases above cover this case. 

C++




// C++ Code to insert a new interval in set of sorted
// intervals and merge overlapping intervals that are
// formed as a result of insertion.
#include <bits/stdc++.h>
 
using namespace std;
 
// Define the structure of interval
struct Interval
{
    int start;
    int end;
    Interval()
        : start(0), end(0)
    {
    }
    Interval(int s, int e)
        : start(s), end(e)
    {
    }
};
 
// A subroutine to check if intervals overlap or not.
bool doesOverlap(Interval a, Interval b)
{
    return (min(a.end, b.end) >= max(a.start, b.start));
}
 
// Function to insert new interval and
// merge overlapping intervals
vector<Interval> insertNewInterval
(vector<Interval>& Intervals, Interval newInterval)
{
    vector<Interval> ans;
    int n = Intervals.size();
 
    // If set is empty then simply insert
    // newInterval and return.
    if (n == 0)
    {
        ans.push_back(newInterval);
        return ans;
    }
 
 
    // Case 1 and Case 2 (new interval to be
    // inserted at corners)
    if (newInterval.end < Intervals[0].start ||
            newInterval.start > Intervals[n - 1].end)
    {
        if (newInterval.end < Intervals[0].start)
            ans.push_back(newInterval);
 
        for (int i = 0; i < n; i++)
            ans.push_back(Intervals[i]);
 
        if (newInterval.start > Intervals[n - 1].end)
            ans.push_back(newInterval);
 
        return ans;
    }
 
    // Case 3 (New interval covers all existing)
    if (newInterval.start <= Intervals[0].start &&
        newInterval.end >= Intervals[n - 1].end)
    {
        ans.push_back(newInterval);
        return ans;
    }
 
    // Case 4 and Case 5
    // These two cases need to check whether
    // intervals overlap or not. For this we
    // can use a subroutine that will perform
    // this function.
    bool overlap = true;
    for (int i = 0; i < n; i++)
    {
        overlap = doesOverlap(Intervals[i], newInterval);
        if (!overlap)
        {
            ans.push_back(Intervals[i]);
 
            // Case 4 : To check if given interval
            // lies between two intervals.
            if (i < n &&
                newInterval.start > Intervals[i].end &&
                newInterval.end < Intervals[i + 1].start)
                ans.push_back(newInterval);
 
            continue;
        }
 
        // Case 5 : Merge Overlapping Intervals.
        // Starting time of new merged interval is
        // minimum of starting time of both
        // overlapping intervals.
        Interval temp;
        temp.start = min(newInterval.start,
                         Intervals[i].start);
 
        // Traverse the set until intervals are
        // overlapping
        while (i < n && overlap)
        {
 
            // Ending time of new merged interval
            // is maximum of ending time both
            // overlapping intervals.
            temp.end = max(newInterval.end,
                           Intervals[i].end);
            if (i == n - 1)
                overlap = false;
            else
                overlap = doesOverlap(Intervals[i + 1],
                                          newInterval);
            i++;
        }
 
        i--;
        ans.push_back(temp);
    }
 
    return ans;
}
 
// Driver code
int main()
{
    vector<Interval> Intervals;
    Interval newInterval;
 
    newInterval.start = 1;
    newInterval.end = 2;
    Intervals.push_back(newInterval);
    newInterval.start = 3;
    newInterval.end = 5;
    Intervals.push_back(newInterval);
    newInterval.start = 6;
    newInterval.end = 7;
    Intervals.push_back(newInterval);
    newInterval.start = 8;
    newInterval.end = 10;
    Intervals.push_back(newInterval);
    newInterval.start = 12;
    newInterval.end = 16;
    Intervals.push_back(newInterval);
    newInterval.start = 4;
    newInterval.end = 9;
 
    vector<Interval> ans =
          insertNewInterval(Intervals, newInterval);
 
    for (int i = 0; i < ans.size(); i++)
        cout << ans[i].start << ", "
             << ans[i].end << "\n";
 
    return 0;
}
Output
1, 2
3, 10
12, 16

Time Complexity: O(N) 
Auxiliary Space: O(N) 

Another Approach Using Stack:

We will be pushing pairs in the stack until it merges with the intervals or finds a suitable place for fitting it.

Below is the implementation of the above approach:

C++




// C++ program for above approach
#include <iostream>
#include <stack>
using namespace std;
 
// Program to merge interval
void mergeInterval2(pair<int, int> arr[],
                    int n, pair<int,
                               int> newPair)
     
    // Create stack of type
    // pair<int, int>
    stack< pair<int, int> > stk;
     
    // Pushing first pair
    stk.push(arr[0]);
    
    // Storing the top element
    pair<int, int> top = stk.top();
   
    // Checking is newPair.first
    // is less than top.second
    if (newPair.first < top.second)
    {
         
        // Pop the top element
        // as it will merge with the
        // previous range
        stk.pop();
       
        // Re-assigning top.first
        top.first = min(top.first,
                          newPair.first);
       
        // Re-assigning top.second
        top.second = max(top.second,
                          newPair.second);
       
        // Push the current interval
        stk.push(top);
    }
    else
    {
         
       // Push the new pair as it does
       // not intersect to first pair
       stk.push(newPair);
    }
 
    // Iterate i from 1 to n - 1
    for (int i = 1; i < n; i++)
    {
         
        // Store the top element of
        // the stack stk
        pair<int, int> top = stk.top();
       
        // Checking is arr[i].first
        // is less than top.second
        if (arr[i].first < top.second)
        {
             
           
            // Pop the top element
            // as it will merge with the
            // previous range
            stk.pop();
           
            // Re-assigning top.first
            top.first = min(top.first,
                            arr[i].first);
           
            // Re-assigning top.second
            top.second = max(top.second,
                            arr[i].second);
           
            // Push the current interval
            stk.push(top);
        }
         
        else
        {
             
            // Push the new pair as it does
            // not intersect to first pair
            stk.push(arr[i]);
        }
    }
     
    // Storing the final intervals
    stack< pair<int,int> > finalIntervals;
   
    // Poping the stack elements
    while (stk.empty() != true)
    {
        pair<int, int> ele =
                       stk.top();
        stk.pop();
        
        // Push ele in finalIntervals
        finalIntervals.push(ele);  
    }
   
     
    // Displaying the final result
    while (finalIntervals.empty() != true)
    {
        pair<int, int> ele =
                       finalIntervals.top();
        finalIntervals.pop();
       
        cout << ele.first << ", "
             << ele.second << endl;
    }
}
 
// Driver Code
int main()
{
 
    pair<int, int> arr2[] = {
        { 1, 2 }, { 3, 5 }, { 6, 7 },
                 { 8, 10 }, { 12, 16 }
    };
    pair<int, int> newPair{ 4, 9 };
    int n2 = sizeof(arr2) / sizeof(arr2[0]);
 
    // Function Call
    mergeInterval2(arr2, n2, newPair);
 
    return 0;
}

Python3




# Python3 program for above approach
 
# Program to merge interval
def mergeInterval2(arr, n, newPair) :
     
    # Create stack of type
    # pair<int, int>
    stk = []
     
    # Pushing first pair
    stk.append(arr[0])
     
    # Storing the top element
    top = stk[len(stk) - 1]
     
    # Checking is newPair.first
    # is less than top.second
    if (newPair[0] < top[1]) :
         
        # Pop the top element
        # as it will merge with the
        # previous range
        stk.pop()
         
        # Re-assigning top.first
        top[0] = min(top[0], newPair[0])
         
        # Re-assigning top.second
        top[1] = max(top[1], newPair[1])
         
        # Push the current interval
        stk.append(top)
 
    else :
        # Push the new pair as it does
        # not intersect to first pair
        stk.append(newPair)
 
    # Iterate i from 1 to n - 1
    for i in range(1, n) :
         
        # Store the top element of
        # the stack stk
        top = stk[len(stk) - 1]
         
        # Checking is arr[i].first
        # is less than top.second
        if (arr[i][0] < top[1]) :
             
            # Pop the top element
            # as it will merge with the
            # previous range
            stk.pop()
             
            # Re-assigning top.first
            top[0] = min(top[0], arr[i][0])
             
            # Re-assigning top.second
            top[1] = max(top[1], arr[i][1])
             
            # Push the current interval
            stk.append(top)
         
        else :
             
            # Push the new pair as it does
            # not intersect to first pair
            stk.append(arr[i])
     
    # Storing the final intervals
    finalIntervals = []
     
    # Poping the stack elements
    while (len(stk) > 0) :
     
        ele = stk[len(stk) - 1]
        stk.pop()
         
        # Push ele in finalIntervals
        finalIntervals.append(ele)
     
    # Displaying the final result
    while (len(finalIntervals) > 0) :
     
        ele = finalIntervals[len(finalIntervals) - 1]
        finalIntervals.pop()
         
        print(ele[0] , end = ", ")
        print(ele[1])
 
arr2 = [ [ 1, 2 ], [ 3, 5 ], [ 6, 7 ], [ 8, 10 ], [ 12, 16 ] ]
 
newPair = [ 4, 9 ]
n2 = len(arr2)
 
# Function Call
mergeInterval2(arr2, n2, newPair)
 
# This code is contributed by divyesh072019

C#




// C# program for above approach
using System;
using System.Collections;
 
class GFG{
     
// Function to merge interval
static void mergeInterval2(Tuple<int, int>[] arr,
                    int n, Tuple<int, int> newPair)
     
    // Create stack of type
    // pair<int, int>
    Stack stk = new Stack();
      
    // Pushing first pair
    stk.Push(arr[0]);
     
    // Storing the top element
    Tuple<int,
          int> top = (Tuple<int,
                            int>)stk.Peek();
    
    // Checking is newPair.first
    // is less than top.second
    if (newPair.Item1 < top.Item2)
    {
         
        // Pop the top element
        // as it will merge with the
        // previous range
        stk.Pop();
        
        // Re-assigning top.first and top.second
        top = new Tuple<int, int>(Math.Min(top.Item1,
                                           newPair.Item1),
                                  Math.Max(top.Item2,
                                           newPair.Item2));
        
        // Push the current interval
        stk.Push(top);
    }
    else
    {
         
        // Push the new pair as it does
        // not intersect to first pair
        stk.Push(newPair);
    }
  
    // Iterate i from 1 to n - 1
    for(int i = 1; i < n; i++)
    {
         
        // Store the top element of
        // the stack stk
        Tuple<int,
              int> Top = (Tuple<int,
                                int>)stk.Peek();
        
        // Checking is arr[i].first
        // is less than top.second
        if (arr[i].Item1 < Top.Item2)
        {
             
            // Pop the top element
            // as it will merge with the
            // previous range
            stk.Pop();
            
            // Re-assigning top.first and top.second
            Top = new Tuple<int, int>(Math.Min(Top.Item1,
                                               arr[i].Item1),
                                      Math.Max(Top.Item2,
                                               arr[i].Item2));
            
            // Push the current interval
            stk.Push(Top);
        }
        else
        {
             
            // Push the new pair as it does
            // not intersect to first pair
            stk.Push(arr[i]);
        }
    }
      
    // Storing the final intervals
    Stack finalIntervals = new Stack();
    
    // Poping the stack elements
    while (stk.Count != 0)
    {
        Tuple<int,
              int> ele = (Tuple<int,
                                int>)stk.Peek();
        stk.Pop();
         
        // Push ele in finalIntervals
        finalIntervals.Push(ele);  
    }
     
    // Displaying the final result
    while (finalIntervals.Count != 0)
    {
        Tuple<int,
              int> ele = (Tuple<int,
                                int>)finalIntervals.Peek();
                                 
        finalIntervals.Pop();
        
        Console.WriteLine(ele.Item1 + ", " + ele.Item2);
    }
}
 
// Driver Code
static void Main()
{
    Tuple<int, int>[] arr2 =
    {
        Tuple.Create(1, 2),
        Tuple.Create(3, 5),
        Tuple.Create(6, 7),
        Tuple.Create(8, 10),
        Tuple.Create(12, 16),
    };
     
    Tuple<int,
          int> newPair = new Tuple<int,
                                   int>(4, 9);
    int n2 = arr2.Length;
     
    // Function Call
    mergeInterval2(arr2, n2, newPair);
}
}
 
// This code is contributed by divyeshrabadiya07
Output
1, 2
3, 10
12, 16

Time Complexity: O(N) 
Auxiliary Space: O(N)
 

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.  To complete your preparation from learning a language to DS Algo and many more,  please refer Complete Interview Preparation Course.

In case you wish to attend live classes with experts, please refer DSA Live Classes for Working Professionals and Competitive Programming Live for Students.




My Personal Notes arrow_drop_up
Recommended Articles
Page :