Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
Merge Intervals in Python
Merging intervals is a common problem where we combine overlapping intervals in a collection. For example, if we have intervals [[1,3], [2,6], [8,10], [15,18]], the result after merging overlapping intervals would be [[1,6], [8,10], [15,18]] because [1,3] and [2,6] overlap and merge into [1,6].
Algorithm Steps
The approach uses sorting and a stack-based method ?
- If the interval list is empty, return an empty list
- Sort intervals by their start time
- Initialize a stack and add the first interval
- For each remaining interval:
- Get the last interval from the stack
- If intervals overlap (last end ? current start), merge them
- Otherwise, add the current interval to the stack
- Return the stack containing merged intervals
Simple Implementation
Here's a clean implementation using Python's built-in sorting ?
def merge_intervals(intervals):
if not intervals:
return []
# Sort intervals by start time
intervals.sort(key=lambda x: x[0])
merged = [intervals[0]]
for current in intervals[1:]:
last = merged[-1]
# Check if intervals overlap
if last[1] >= current[0]:
# Merge intervals
last[1] = max(last[1], current[1])
else:
# No overlap, add current interval
merged.append(current)
return merged
# Test the function
intervals = [[1,3], [2,6], [8,10], [15,18]]
result = merge_intervals(intervals)
print(result)
[[1, 6], [8, 10], [15, 18]]
Stack-Based Implementation
The original approach using explicit stack operations ?
class Solution:
def merge(self, intervals):
if len(intervals) == 0:
return []
# Sort intervals by start time
intervals.sort(key=lambda x: x[0])
stack = []
stack.append(intervals[0])
for i in range(1, len(intervals)):
last_element = stack[-1]
if last_element[1] >= intervals[i][0]:
# Merge overlapping intervals
last_element[1] = max(intervals[i][1], last_element[1])
stack.pop()
stack.append(last_element)
else:
stack.append(intervals[i])
return stack
# Test the implementation
solution = Solution()
intervals = [[1,3], [2,6], [8,10], [15,18]]
result = solution.merge(intervals)
print(result)
[[1, 6], [8, 10], [15, 18]]
Edge Cases
Let's test with various edge cases ?
def merge_intervals(intervals):
if not intervals:
return []
intervals.sort(key=lambda x: x[0])
merged = [intervals[0]]
for current in intervals[1:]:
last = merged[-1]
if last[1] >= current[0]:
last[1] = max(last[1], current[1])
else:
merged.append(current)
return merged
# Test edge cases
test_cases = [
[[1,4], [4,5]], # Adjacent intervals
[[1,4], [2,3]], # Completely overlapping
[[1,3], [5,7], [9,12]], # No overlaps
[[1,10], [2,6], [8,9]] # Multiple overlaps
]
for i, intervals in enumerate(test_cases, 1):
result = merge_intervals(intervals)
print(f"Test {i}: {intervals} ? {result}")
Test 1: [[1, 4], [4, 5]] ? [[1, 5]] Test 2: [[1, 4], [2, 3]] ? [[1, 4]] Test 3: [[1, 3], [5, 7], [9, 12]] ? [[1, 3], [5, 7], [9, 12]] Test 4: [[1, 10], [2, 6], [8, 9]] ? [[1, 10]]
Time Complexity
The time complexity is O(n log n) due to sorting, where n is the number of intervals. The merging process takes O(n) time, making sorting the dominant factor.
Conclusion
Merging intervals requires sorting by start time and then checking for overlaps. The key insight is that two intervals [a,b] and [c,d] overlap if b ? c when sorted by start time. Use Python's built-in sort for simplicity.
