Skip to content

Commit 5ec2ed0

Browse files
author
Mauricio Klein
committed
Add solution for challenge #33
1 parent 9cef2d4 commit 5ec2ed0

File tree

6 files changed

+69
-0
lines changed

6 files changed

+69
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,4 @@
3232
- [x] [Challenge 30: Merge sort](challenge-30/)
3333
- [x] [Challenge 31: Find cycle in indirected graph](challenge-31/)
3434
- [x] [Challenge 32: Shortest path in a indirected acyclic graph](challenge-32/)
35+
- [x] [Challenge 33: Merge Overlapping Intervals](challenge-33/)

challenge-33/Makefile

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
test:
2+
python test_*.py
3+
4+
.PHONY: test

challenge-33/README.md

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Merge Overlapping Intervals
2+
3+
This problem was asked by Microsoft.
4+
5+
## Description
6+
7+
You are given an array of intervals - that is, an array of tuples (start, end). The array may not be sorted, and could contain overlapping intervals. Return another array where the overlapping intervals are merged.
8+
9+
## Example
10+
11+
```
12+
Input: [(1, 3), (5, 8) , (4, 10), (20, 25)]
13+
Output: [(1, 3), (4, 10), (20, 25)]
14+
Explanation: (5, 8) and (4, 10) can be merged into (4, 10)
15+
```

challenge-33/__init__.py

Whitespace-only changes.

challenge-33/solver.py

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#
2+
# Time complexity: O(n*log(n)) (for the sort)
3+
# Space complexity: O(n) (for the result array)
4+
#
5+
def merge_overlapping_intervals(intervals):
6+
# Sort intervals by start timestamp
7+
intervals.sort(key=lambda interval: interval[0])
8+
9+
merged_intervals = []
10+
11+
for interval in intervals:
12+
if merged_intervals and overlap(merged_intervals[-1], interval):
13+
merged_intervals[-1] = merge(merged_intervals[-1], interval)
14+
else:
15+
merged_intervals.append(interval)
16+
17+
return merged_intervals
18+
19+
def overlap(prev_i, next_i):
20+
start, end = next_i[0], prev_i[1]
21+
22+
return start <= end
23+
24+
def merge(prev_i, next_i):
25+
prev_start, prev_end = prev_i
26+
next_start, next_end = next_i
27+
28+
return (prev_start, max(prev_end, next_end))

challenge-33/test_solver.py

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import unittest
2+
from solver import merge_overlapping_intervals
3+
4+
class TestSolver(unittest.TestCase):
5+
def test_partial_overlapping(self):
6+
self.assertEqual(merge_overlapping_intervals([(1, 3), (5, 8) , (4, 10), (20, 25)]), [(1, 3), (4, 10), (20, 25)])
7+
8+
def test_full_overlap(self):
9+
self.assertEqual(merge_overlapping_intervals([(1, 3), (5, 8) , (6, 7), (20, 25)]), [(1, 3), (5, 8), (20, 25)])
10+
11+
def test_multiple_overlaps(self):
12+
self.assertEqual(merge_overlapping_intervals([(1, 5), (3, 6) , (4, 9), (20, 25)]), [(1, 9), (20, 25)])
13+
14+
def test_no_overlaps(self):
15+
self.assertEqual(merge_overlapping_intervals([(1, 4), (5, 8), (20, 25)]), [(1, 4), (5, 8), (20, 25)])
16+
17+
def test_no_intervals(self):
18+
self.assertEqual(merge_overlapping_intervals([]), [])
19+
20+
if __name__ == "__main__":
21+
unittest.main()

0 commit comments

Comments
 (0)