Bird
0
0
DSA Cprogramming

Merge Overlapping Intervals in DSA C

Choose your learning style9 modes available
Mental Model
We combine intervals that overlap into one bigger interval so no two intervals cover the same range twice.
Analogy: Imagine booking meeting rooms. If two meetings overlap in time, you merge them into one longer meeting to avoid confusion.
Intervals before merge:
[1,3] -> [2,6] -> [8,10] -> [15,18] -> null
Dry Run Walkthrough
Input: intervals: [1,3], [2,6], [8,10], [15,18]
Goal: Merge all overlapping intervals into combined intervals without overlaps
Step 1: Sort intervals by start time
[1,3] -> [2,6] -> [8,10] -> [15,18] -> null
Why: Sorting helps to easily find overlapping intervals by comparing neighbors
Step 2: Start with first interval [1,3] in merged list
Merged: [1,3]
Why: We need a base interval to compare others against
Step 3: Compare next interval [2,6] with last merged [1,3], they overlap
Merged: [1,6]
Why: Since 2 ≤ 3, intervals overlap, so merge by extending end to max(3,6)=6
Step 4: Compare next interval [8,10] with last merged [1,6], no overlap
Merged: [1,6] -> [8,10]
Why: 8 > 6 means no overlap, so add new interval
Step 5: Compare next interval [15,18] with last merged [8,10], no overlap
Merged: [1,6] -> [8,10] -> [15,18]
Why: 15 > 10 means no overlap, so add new interval
Result:
Merged intervals:
[1,6] -> [8,10] -> [15,18] -> null
Annotated Code
DSA C
#include <stdio.h>
#include <stdlib.h>

// Define interval structure
typedef struct {
    int start;
    int end;
} Interval;

// Comparator for qsort to sort intervals by start time
int compare(const void *a, const void *b) {
    Interval *i1 = (Interval *)a;
    Interval *i2 = (Interval *)b;
    return i1->start - i2->start;
}

// Function to merge overlapping intervals
// intervals: input array, n: number of intervals
// merged: output array to store merged intervals
// returns number of merged intervals
int mergeIntervals(Interval intervals[], int n, Interval merged[]) {
    if (n == 0) return 0;

    // Sort intervals by start time
    qsort(intervals, n, sizeof(Interval), compare);

    int idx = 0; // index for merged array
    merged[0] = intervals[0]; // start with first interval

    for (int i = 1; i < n; i++) {
        // If current interval overlaps with last merged
        if (intervals[i].start <= merged[idx].end) {
            // Merge by extending the end if needed
            if (intervals[i].end > merged[idx].end) {
                merged[idx].end = intervals[i].end;
            }
        } else {
            // No overlap, add new interval
            idx++;
            merged[idx] = intervals[i];
        }
    }

    return idx + 1; // number of merged intervals
}

// Helper to print intervals
void printIntervals(Interval intervals[], int n) {
    for (int i = 0; i < n; i++) {
        printf("[%d,%d]", intervals[i].start, intervals[i].end);
        if (i != n - 1) printf(" -> ");
    }
    printf(" -> null\n");
}

int main() {
    Interval intervals[] = {{1,3}, {2,6}, {8,10}, {15,18}};
    int n = sizeof(intervals) / sizeof(intervals[0]);
    Interval merged[n];

    int mergedCount = mergeIntervals(intervals, n, merged);

    printf("Merged intervals:\n");
    printIntervals(merged, mergedCount);

    return 0;
}
qsort(intervals, n, sizeof(Interval), compare);
Sort intervals by start time to prepare for merging
merged[0] = intervals[0];
Initialize merged list with first interval
if (intervals[i].start <= merged[idx].end) {
Check if current interval overlaps with last merged interval
if (intervals[i].end > merged[idx].end) { merged[idx].end = intervals[i].end; }
Extend the end of merged interval if current interval ends later
else { idx++; merged[idx] = intervals[i]; }
No overlap, add current interval as new merged interval
OutputSuccess
Merged intervals: [1,6] -> [8,10] -> [15,18] -> null
Complexity Analysis
Time: O(n log n) because we sort all intervals first, then merge in one pass O(n)
Space: O(n) for the output array to store merged intervals
vs Alternative: Naive approach compares every pair leading to O(n^2), sorting reduces it to O(n log n)
Edge Cases
empty intervals array
returns zero merged intervals without error
DSA C
if (n == 0) return 0;
all intervals non-overlapping
merged intervals equal original intervals
DSA C
else { idx++; merged[idx] = intervals[i]; }
all intervals fully overlapping
merged intervals is a single interval covering all
DSA C
if (intervals[i].start <= merged[idx].end) { if (intervals[i].end > merged[idx].end) { merged[idx].end = intervals[i].end; } }
When to Use This Pattern
When you see a list of intervals and need to combine overlapping ones, use the merge intervals pattern by sorting and merging neighbors.
Common Mistakes
Mistake: Not sorting intervals before merging, causing incorrect merges
Fix: Always sort intervals by start time before merging
Mistake: Not updating the end of merged interval when current interval extends beyond it
Fix: Update merged interval end to max of current and merged ends
Summary
It merges overlapping intervals into combined intervals without overlaps.
Use it when you need to simplify or combine ranges that may overlap.
Sort intervals by start time first, then merge neighbors by comparing ends.