ArraysNon Overlapping Intervals

Non Overlapping Intervals

16 mins read The Jat Medium Updated 11 months ago
ArrayIntervals

Problem Statement

You are given an array of intervals, where each interval is represented as an array of two integers, intervals[i] = [start_i, end_i]. Your task is to determine the minimum number of intervals you need to remove to ensure that the remaining intervals do not overlap.

Note: Intervals that only touch at a point are considered non-overlapping. For example, intervals [1, 2] and [2, 3] do not overlap.

Examples

Example 1:

Input: intervals = [
                    [1, 2],
                    [2, 3],
                    [3, 4],
                    [1, 3]
                   ]
Output: 1

Explanation:
The intervals [1,2], [2,3], and [3,4] can remain as they are non-overlapping.
The interval [1,3] overlaps with [1,2] and [2,3]. To make the remaining intervals non-overlapping, we can remove [1,3].
Example 2:

Input: intervals = [
                    [1, 2],
                    [1, 2],
                    [1, 2] 
                   ]
Output: 1

Explanation:
You need to remove two [1,2] to make the rest of the intervals non-overlapping.

To leave only one interval, we must remove 2 intervals.
Example 3:

Input: intervals = [
                    [1, 2],
                    [2, 3]
                   ]
Output: 0

Explanation:
The intervals [1,2] and [2,3] do not overlap (they touch at the endpoint).
No intervals need to be removed.

Different Approaches

1️⃣ Greedy Approach

Intuition:

The greedy approach works by sorting the intervals based on their end times. By always choosing the interval that ends the earliest, we can maximize the number of non-overlapping intervals.

Steps:

  1. Sort the intervals by their end times.
  2. Initialize a variable count to track the number of intervals to remove and lastEnd to keep track of the end of the last added non-overlapping interval.
  3. Iterate through the sorted intervals:
    • If the current interval overlaps with the last added interval (i.e., its start time is less than the lastEnd), increment the count.
    • If it does not overlap, update lastEnd to the end time of the current interval.
  4. Return the count as the minimum number of intervals to remove.

Dry Run:

intervals = [
             [1, 2],
             [2, 3],
             [3, 4],
             [1, 3]
            ]
Step 1: Sort the intervals based on end times:
intervals = [
             [1, 2],
             [2, 3],
             [1, 3],
             [3, 4]
            ]
Initialization:
intervals = [
             [1, 2],
             [2, 3],
             [1, 3],
             [3, 4]
            ]
count = 0
lastEnd = 2 (from the first interval [1, 2])
Iteration:
intervals = [
             [1, 2],
             [2, 3],
             [1, 3],
             [3, 4]
            ]
count = 0
lastEnd = 2 (from the first interval [1, 2])

i = 1 (interval [2, 3])
     current Interval Start Time < lastEnd
     2 < lastEnd (2)
     False // No overlap
     Update lastEnd = current interval's end time
     lastEnd = 3

i = 2 (interval [1, 3])
     current Interval Start Time < lastEnd
     1 < lastEnd (3)
     True // Overlap
     Increment count
          count = 1

i = 3 (interval [3, 4])
     current Interval Start Time < lastEnd
     3 < lastEnd (3)
     False // No Overlap
     Update lastEnd = current interval's end time.
     lastEnd = 4
Return
Return count = 1

Code:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int eraseOverlapIntervals(vector<vector<int>>& intervals) {
    // Step 1: Sort the intervals by end time
    sort(intervals.begin(), intervals.end(), [](const vector<int>& a, const vector<int>& b) {
        return a[1] < b[1];
    });

    int count = 0; // Count of intervals to remove
    int lastEnd = intervals[0][1]; // End time of the last added interval

    for (int i = 1; i < intervals.size(); ++i) {
        // If the current interval starts before the last one ends, we have an overlap
        if (intervals[i][0] < lastEnd) {
            count++; // Increase the count of removed intervals
        } else {
            lastEnd = intervals[i][1]; // Update the end time
        }
    }

    return count; // Return the count of removed intervals
}

int main() {
    vector<vector<int>> intervals = {{1, 2}, {2, 3}, {3, 4}, {1, 3}};
    int result = eraseOverlapIntervals(intervals);
    cout << "Minimum number of intervals to remove: " << result << endl;
    return 0;
}

Complexity Analysis:

  • Time Complexity: O(n log n)
    • Sorting the interval takes O(n log n).
    • The single pass through the intervals takes O(n).
    • Overall Complexity: O(n log n).
  • Space Complexity: O(1)
Buy Me A Coffee

Leave a comment

Your email address will not be published. Required fields are marked *

Your experience on this site will be improved by allowing cookies Cookie Policy