top of page

Non-Overlapping Intervals

  • mosesg1123
  • 2 days ago
  • 4 min read

Managing schedules and resources is everywhere in the real world. Whether it’s video playback buffers, CPU job scheduling, or booking conference rooms, overlapping intervals cause conflicts. This problem is a great warm-up for greedy thinking and practicing pattern recognition around intervals.


Problem Statement

You are given an array of intervals where each interval is represented as [start, end]. Your goal is to remove the minimum number of intervals so that the rest do not overlap. Return that minimum number.


Example:

Input: [[1,3], [2,4], [3,5]]

Output: 1

Reason: Removing [2,4] leaves two non-overlapping intervals.


1. Clarify Requirements Before Jumping Into Code

  • I want to be sure what counts as overlap. If one interval ends exactly where another starts, that does not count as overlap.

  • Intervals can be in any order

  • Output is just the count of removed intervals, not the resulting list.


2. Identify the Category of the Question

Our first instinct for a solution here is to walk through the intervals in order and just kick out the intervals that overlap. We're trusting that we will find the optimal global solution by zooming into a small subset of intervals and making a local decision. That is the essence of a greedy algorithm, making that the likely category for this question.

Additionally, since intervals can be provided in any order, I may need to consider sorting the input. That's also a decent hint that greedy algorithm may be the solution here, since many greedy algorithms require sorting as a pre-processing step.


3. Consider a Brute-Force Approach to Understand the Problem

Imagine we wanted to be 100% confident that we had the best possible solution to this problem. To do that, we would probably need to try every possible subset of non-overlapping intervals. Then we can simply pick the largest, and subtract that from the total number of intervals to get our result.

But that's a lot of processing. We're generating O(2^n) subsets - definitely too slow for our runtime.

It's important to remember that greedy algorithms don't guarantee the best possible solution, but sometimes that's ok, especially when the alternative is so much worse.


4. Brainstorm More Solutions

The fact that the input doesn't have any input complicates the problem, since the only way to identify the next best possible interval in my solution is to scan the whole set.


So, what if we start by sorting the input? That way, we know exactly where we need to look for the next interval.


The question then becomes, how do we sort? We have two options: we can sort by the start time of an interval or we can sort by the end time. Let's check both.


Option 1: Sort by Start Time, Then Check Overlaps

So we sort all of the intervals by start time in O(n log n) time. We start iterating through our sorted input and find a couple of intervals that overlap. Which one do we keep?

We already sorted on the start time, so let's think about what we can do with the other half of the interval - the end time. Do we keep the interval that ends sooner or the interval that ends later?

Keeping the one the interval that ends later could potentially block future intervals. So let's choose the greedy option - keep the interval that ends soonest so that we can maximize the amount of time we have open for future potential intervals.

Iterating through our input costs O(n) time, giving us a total runtime complexity of O(n log n).


Option 2: Sort by End + Greedy Selection

Now let's think about how our solution would change if we sorted by the end time.

At the end of the day, we're still doing the same thing as in Option 1 - choosing the greedy option by keeping the intervals that end soonest. The difference is that Option 2 makes it much easier to identify which intervals end soonest, leading to some cleaner code.

So, of the two options here, sorting by end time is preferred!


Complexity

  • Sorting: O(n log n)

  • Scanning: O(n)

  • Final runtime: O(n log n)


Final chosen solution → Greedy by earliest end time ✅


5. Discuss Trade-Offs Between Your Solutions

Approach

Time

Space

Pros

Cons

Brute Force Subsets

O(2^n)

O(n)

Guaranteed optimal

Completely impractical

Sort by Start + Compare

O(n log n)

O(1)

Much faster

Trickier logic, can mis-optimize

✅ Sort by End + Greedy

O(n log n)

O(1)

Clean, optimal, widely accepted

Sorting cost unavoidable


6. Write Pseudocode to Structure Your Thoughts

function eraseOverlapIntervals(intervals):
    sort intervals by end ascending
    countKeep = 1
    prevEnd = intervals[0].end
    
    for i from 1 to intervals.length - 1:
        if intervals[i].start >= prevEnd:
            countKeep += 1
            prevEnd = intervals[i].end
    
    return intervals.length - countKeep

7. Consider Edge Cases

  • Empty list → 0 removals

  • Only one interval → 0 removals

  • Intervals fully overlapping → remove all but one

  • Already sorted or already non-overlapping — minimal removals


8. Write Full Code Syntax (Java)

import java.util.Arrays;

public class Solution {
    public int eraseOverlapIntervals(int[][] intervals) {
        if (intervals.length == 0) return 0;

        Arrays.sort(intervals, (a, b) -> a[1] - b[1]);

        int countKeep = 1;
        int prevEnd = intervals[0][1];

        for (int i = 1; i < intervals.length; i++) {
            if (intervals[i][0] >= prevEnd) {
                countKeep++;
                prevEnd = intervals[i][1];
            }
        }

        return intervals.length - countKeep;
    }
}

9. Test Your Code

System.out.println(new Solution().eraseOverlapIntervals(
    new int[][]{{1,2},{2,3},{3,4},{1,3}})); // 1

System.out.println(new Solution().eraseOverlapIntervals(
    new int[][]{{1,2},{1,2},{1,2}})); // 2

System.out.println(new Solution().eraseOverlapIntervals(
    new int[][]{{1,2},{2,3}})); // 0

System.out.println(new Solution().eraseOverlapIntervals(
    new int[][]{})); // 0

System.out.println(new Solution().eraseOverlapIntervals(
    new int[][]{{0,10},{1,5},{6,9}})); // 1

10. Key Lessons to Remember for Future Questions

  • Greedy algorithms often involve some kind of pre-processing with sorting

  • Intervals that end earlier leave more space for others

  • This same strategy applies to scheduling CPU jobs, networking windows, and event timelines

Recent Posts

See All
Merge Intervals

"Merge Intervals" is one of those classic algorithm problems that shows up frequently in technical interviews. It's a great test of your...

 
 
 
Jump Game II

Jump Game II is a classic follow-up to the original Jump Game problem. It’s not just about whether you can reach the end... now you have to do it in the fewest jumps possible! That small change turns

 
 
 
Jump Game

The "Jump Game" question is a popular one for interviews because it tests your ability to think greedily and work with dynamic movement through an array. It's a great warm-up for range-based greedy lo

 
 
 

Comments


Drop Me a Line, Let Me Know What You Think

Thanks for submitting!

© 2023 by Train of Thoughts. Proudly created with Wix.com

bottom of page