57. Insert Interval

Solving the problem of inserting an interval into a sorted array in C++.

Felix Pultar
Felix Pultar

The Problem Statement

This problem is taken from LeetCode.

The Solution

We will allocate a new std::vector and reserve a capacity of intervals.size() + 1. We loop over all intervals and during each step check if the end of the newInterval is smaller than the head of the current interval. If so, we can safely insert newInterval in front without worrying about overlap. We will also append all remaining elements of intervals to our res vector and return. While we iterate through all intervals, we will also check if the head of the newInterval is bigger than the tail of the current interval. If the condition is fullfilled, we add newInterval to res but do not return yet as there might be overlaps with the remaining elements of intervals. The third clause in our if-else block concerns merging overlapping intervals. In case a collision is detected, we update head and tail of newInterval with std::min(newInterval[0]), intervals[i][0] and std::max(newInterval[1], intervals[i][1]). After the loop has finished, we know that newInterval has the right bounces but is not appended yet as the first branch of our if-else block has never executed. We thus push back currentInterval and return res. Here is the code:

class Solution {
public:

    vector<vector<int>> insert(vector<vector<int>>& intervals, vector<int>& newInterval) {
        std::vector<std::vector<int>> res;
        res.reserve(intervals.size() + 1);
        for (int i = 0; i < intervals.size(); ++i) {
            if (newInterval[1] < intervals[i][0]) {
                // check if new interval can fit in front
                res.push_back(newInterval);
                res.insert(res.end(), intervals.cbegin() + i, intervals.cend());
                return res;
            }
            else if (newInterval[0] > intervals[i][1]) {
                // check if new interval goes after current item
                res.push_back(intervals[i]);
            }
            else {
                // merge interval with current item
                newInterval = {std::min(newInterval[0], intervals[i][0]), std::max(newInterval[1], intervals[i][1])};
            }
        }
        res.push_back(newInterval);
        return res;
    }
};

Notes

The algorithm has $O(N)$ time complexity and $O(1)$ space complexity as we need to process the list once and aside from the res vector do not allocate any more space. Typically, allocating space for the result of a task is not considered to affect space complexity. In case we are concerned with the new allocation of res, we could also insert inplace after performing a linear or binary search on invervals. Afterwards, we will need to merge the interval to avoid overlap and erase duplicate elements. This process will naturally trigger lots of reallocations and is thus potentially less efficient than the solution presented. We would also need to be very careful of iterator invalidation.