Skip to content

Commit 614ad1a

Browse files
committed
feat: add Merge Intervals
1 parent e810c96 commit 614ad1a

File tree

7 files changed

+210
-1
lines changed

7 files changed

+210
-1
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
{
2+
"problem_name": "merge_intervals",
3+
"solution_class_name": "Solution",
4+
"problem_number": "56",
5+
"problem_title": "Merge Intervals",
6+
"difficulty": "Medium",
7+
"topics": "Array, Sorting",
8+
"tags": ["grind-75"],
9+
"readme_description": "Given an array of `intervals` where `intervals[i] = [starti, endi]`, merge all overlapping intervals, and return an array of the non-overlapping intervals that cover all the intervals in the input.",
10+
"readme_examples": [
11+
{
12+
"content": "```\nInput: intervals = [[1,3],[2,6],[8,10],[15,18]]\nOutput: [[1,6],[8,10],[15,18]]\n```\n**Explanation:** Since intervals [1,3] and [2,6] overlap, merge them into [1,6]."
13+
},
14+
{
15+
"content": "```\nInput: intervals = [[1,4],[4,5]]\nOutput: [[1,5]]\n```\n**Explanation:** Intervals [1,4] and [4,5] are considered overlapping."
16+
},
17+
{
18+
"content": "```\nInput: intervals = [[4,7],[1,4]]\nOutput: [[1,7]]\n```\n**Explanation:** Intervals [1,4] and [4,7] are considered overlapping."
19+
}
20+
],
21+
"readme_constraints": "- `1 <= intervals.length <= 10^4`\n- `intervals[i].length == 2`\n- `0 <= starti <= endi <= 10^4`",
22+
"readme_additional": "",
23+
"solution_imports": "",
24+
"solution_methods": [
25+
{
26+
"name": "merge",
27+
"parameters": "intervals: list[list[int]]",
28+
"return_type": "list[list[int]]",
29+
"dummy_return": "[]"
30+
}
31+
],
32+
"test_imports": "import pytest\nfrom leetcode_py.test_utils import logged_test\nfrom .solution import Solution",
33+
"test_class_name": "MergeIntervals",
34+
"test_helper_methods": [
35+
{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }
36+
],
37+
"test_methods": [
38+
{
39+
"name": "test_merge",
40+
"parametrize": "intervals, expected",
41+
"parametrize_typed": "intervals: list[list[int]], expected: list[list[int]]",
42+
"test_cases": "[([[1,3],[2,6],[8,10],[15,18]], [[1,6],[8,10],[15,18]]), ([[1,4],[4,5]], [[1,5]]), ([[4,7],[1,4]], [[1,7]])]",
43+
"body": "result = self.solution.merge(intervals)\nassert result == expected"
44+
}
45+
],
46+
"playground_imports": "from solution import Solution",
47+
"playground_test_case": "# Example test case\nintervals = [[1,3],[2,6],[8,10],[15,18]]\nexpected = [[1,6],[8,10],[15,18]]",
48+
"playground_execution": "result = Solution().merge(intervals)\nresult",
49+
"playground_assertion": "assert result == expected"
50+
}

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
PYTHON_VERSION = 3.13
2-
PROBLEM ?= longest_palindrome
2+
PROBLEM ?= merge_intervals
33
FORCE ?= 0
44
COMMA := ,
55

leetcode/merge_intervals/README.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Merge Intervals
2+
3+
**Difficulty:** Medium
4+
**Topics:** Array, Sorting
5+
**Tags:** grind-75
6+
7+
**LeetCode:** [Problem 56](https://leetcode.com/problems/merge-intervals/description/)
8+
9+
## Problem Description
10+
11+
Given an array of `intervals` where `intervals[i] = [starti, endi]`, merge all overlapping intervals, and return an array of the non-overlapping intervals that cover all the intervals in the input.
12+
13+
## Examples
14+
15+
### Example 1:
16+
17+
```
18+
Input: intervals = [[1,3],[2,6],[8,10],[15,18]]
19+
Output: [[1,6],[8,10],[15,18]]
20+
```
21+
22+
**Explanation:** Since intervals [1,3] and [2,6] overlap, merge them into [1,6].
23+
24+
### Example 2:
25+
26+
```
27+
Input: intervals = [[1,4],[4,5]]
28+
Output: [[1,5]]
29+
```
30+
31+
**Explanation:** Intervals [1,4] and [4,5] are considered overlapping.
32+
33+
### Example 3:
34+
35+
```
36+
Input: intervals = [[4,7],[1,4]]
37+
Output: [[1,7]]
38+
```
39+
40+
**Explanation:** Intervals [1,4] and [4,7] are considered overlapping.
41+
42+
## Constraints
43+
44+
- `1 <= intervals.length <= 10^4`
45+
- `intervals[i].length == 2`
46+
- `0 <= starti <= endi <= 10^4`

leetcode/merge_intervals/__init__.py

Whitespace-only changes.
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": null,
6+
"id": "imports",
7+
"metadata": {},
8+
"outputs": [],
9+
"source": [
10+
"from solution import Solution"
11+
]
12+
},
13+
{
14+
"cell_type": "code",
15+
"execution_count": null,
16+
"id": "setup",
17+
"metadata": {},
18+
"outputs": [],
19+
"source": [
20+
"# Example test case\n",
21+
"intervals = [[1, 3], [2, 6], [8, 10], [15, 18]]\n",
22+
"expected = [[1, 6], [8, 10], [15, 18]]"
23+
]
24+
},
25+
{
26+
"cell_type": "code",
27+
"execution_count": null,
28+
"id": "execute",
29+
"metadata": {},
30+
"outputs": [],
31+
"source": [
32+
"result = Solution().merge(intervals)\nresult"
33+
]
34+
},
35+
{
36+
"cell_type": "code",
37+
"execution_count": null,
38+
"id": "test",
39+
"metadata": {},
40+
"outputs": [],
41+
"source": [
42+
"assert result == expected"
43+
]
44+
}
45+
],
46+
"metadata": {
47+
"kernelspec": {
48+
"display_name": "leetcode-py-py3.13",
49+
"language": "python",
50+
"name": "python3"
51+
},
52+
"language_info": {
53+
"codemirror_mode": {
54+
"name": "ipython",
55+
"version": 3
56+
},
57+
"file_extension": ".py",
58+
"mimetype": "text/x-python",
59+
"name": "python",
60+
"nbconvert_exporter": "python3",
61+
"pygments_lexer": "ipython3",
62+
"version": "3.13.7"
63+
}
64+
},
65+
"nbformat": 4,
66+
"nbformat_minor": 5
67+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
class Solution:
2+
# Time: O(n log n)
3+
# Space: O(1)
4+
def merge(self, intervals: list[list[int]]) -> list[list[int]]:
5+
intervals.sort()
6+
merged = [intervals[0]]
7+
8+
for start, end in intervals[1:]:
9+
if start <= merged[-1][1]:
10+
merged[-1][1] = max(merged[-1][1], end)
11+
else:
12+
merged.append([start, end])
13+
14+
return merged

leetcode/merge_intervals/tests.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import pytest
2+
3+
from leetcode_py.test_utils import logged_test
4+
5+
from .solution import Solution
6+
7+
8+
class TestMergeIntervals:
9+
def setup_method(self):
10+
self.solution = Solution()
11+
12+
@pytest.mark.parametrize(
13+
"intervals, expected",
14+
[
15+
# Original test cases
16+
([[1, 3], [2, 6], [8, 10], [15, 18]], [[1, 6], [8, 10], [15, 18]]),
17+
([[1, 4], [4, 5]], [[1, 5]]),
18+
([[4, 7], [1, 4]], [[1, 7]]),
19+
# Edge cases
20+
([[1, 1]], [[1, 1]]), # Single point interval
21+
([[1, 2], [3, 4]], [[1, 2], [3, 4]]), # No overlap
22+
([[1, 4], [2, 3]], [[1, 4]]), # Complete overlap
23+
([[1, 10], [2, 6], [8, 10], [15, 18]], [[1, 10], [15, 18]]), # Multiple merges
24+
([[0, 0], [1, 1], [2, 2]], [[0, 0], [1, 1], [2, 2]]), # All single points
25+
([[1, 3], [2, 6], [8, 10], [9, 12], [15, 18]], [[1, 6], [8, 12], [15, 18]]), # Chain merge
26+
([[4, 5], [4, 6]], [[4, 6]]), # Same start time
27+
],
28+
)
29+
@logged_test
30+
def test_merge(self, intervals: list[list[int]], expected: list[list[int]]):
31+
result = self.solution.merge(intervals)
32+
assert result == expected

0 commit comments

Comments
 (0)