Skip to content

Commit 63dce89

Browse files
committed
feat: add Middle of the Linked List
1 parent 1e31975 commit 63dce89

File tree

7 files changed

+261
-1
lines changed

7 files changed

+261
-1
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"problem_name": "middle_of_the_linked_list",
3+
"solution_class_name": "Solution",
4+
"problem_number": "876",
5+
"problem_title": "Middle of the Linked List",
6+
"difficulty": "Easy",
7+
"topics": "Linked List, Two Pointers",
8+
"tags": ["grind-75"],
9+
"readme_description": "Given the `head` of a singly linked list, return *the middle node of the linked list*.\n\nIf there are two middle nodes, return **the second middle** node.",
10+
"readme_examples": [
11+
{
12+
"content": "![Example 1](https://assets.leetcode.com/uploads/2021/07/23/lc-midlist1.jpg)\n\n```\nInput: head = [1,2,3,4,5]\nOutput: [3,4,5]\n```\n**Explanation:** The middle node of the list is node 3."
13+
},
14+
{
15+
"content": "![Example 2](https://assets.leetcode.com/uploads/2021/07/23/lc-midlist2.jpg)\n\n```\nInput: head = [1,2,3,4,5,6]\nOutput: [4,5,6]\n```\n**Explanation:** Since the list has two middle nodes with values 3 and 4, we return the second one."
16+
}
17+
],
18+
"readme_constraints": "- The number of nodes in the list is in the range `[1, 100]`.\n- `1 <= Node.val <= 100`",
19+
"readme_additional": "",
20+
"solution_imports": "from leetcode_py import ListNode",
21+
"solution_methods": [
22+
{
23+
"name": "middle_node",
24+
"parameters": "head: ListNode | None",
25+
"return_type": "ListNode | None",
26+
"dummy_return": "None"
27+
}
28+
],
29+
"test_imports": "import pytest\nfrom leetcode_py.test_utils import logged_test\nfrom leetcode_py import ListNode\nfrom .solution import Solution",
30+
"test_class_name": "MiddleOfTheLinkedList",
31+
"test_helper_methods": [
32+
{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }
33+
],
34+
"test_methods": [
35+
{
36+
"name": "test_middle_node",
37+
"parametrize": "head_list, expected_list",
38+
"parametrize_typed": "head_list: list[int], expected_list: list[int]",
39+
"test_cases": "[([1, 2, 3, 4, 5], [3, 4, 5]), ([1, 2, 3, 4, 5, 6], [4, 5, 6]), ([1], [1]), ([1, 2], [2])]",
40+
"body": "head = ListNode.from_list(head_list)\nexpected = ListNode.from_list(expected_list)\nresult = self.solution.middle_node(head)\nassert result == expected"
41+
}
42+
],
43+
"playground_imports": "from solution import Solution\nfrom leetcode_py import ListNode",
44+
"playground_test_case": "# Example test case\nhead_list = [1, 2, 3, 4, 5]\nexpected_list = [3, 4, 5]",
45+
"playground_execution": "head = ListNode.from_list(head_list)\nresult = Solution().middle_node(head)\nresult",
46+
"playground_assertion": "expected = ListNode.from_list(expected_list)\nassert result == expected"
47+
}

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 ?= diameter_of_binary_tree
2+
PROBLEM ?= middle_of_the_linked_list
33
FORCE ?= 0
44
COMMA := ,
55

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Middle of the Linked List
2+
3+
**Difficulty:** Easy
4+
**Topics:** Linked List, Two Pointers
5+
**Tags:** grind-75
6+
7+
**LeetCode:** [Problem 876](https://leetcode.com/problems/middle-of-the-linked-list/description/)
8+
9+
## Problem Description
10+
11+
Given the `head` of a singly linked list, return _the middle node of the linked list_.
12+
13+
If there are two middle nodes, return **the second middle** node.
14+
15+
## Examples
16+
17+
### Example 1:
18+
19+
![Example 1](https://assets.leetcode.com/uploads/2021/07/23/lc-midlist1.jpg)
20+
21+
```
22+
Input: head = [1,2,3,4,5]
23+
Output: [3,4,5]
24+
```
25+
26+
**Explanation:** The middle node of the list is node 3.
27+
28+
### Example 2:
29+
30+
![Example 2](https://assets.leetcode.com/uploads/2021/07/23/lc-midlist2.jpg)
31+
32+
```
33+
Input: head = [1,2,3,4,5,6]
34+
Output: [4,5,6]
35+
```
36+
37+
**Explanation:** Since the list has two middle nodes with values 3 and 4, we return the second one.
38+
39+
## Constraints
40+
41+
- The number of nodes in the list is in the range `[1, 100]`.
42+
- `1 <= Node.val <= 100`

leetcode/middle_of_the_linked_list/__init__.py

Whitespace-only changes.
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": 5,
6+
"id": "imports",
7+
"metadata": {},
8+
"outputs": [],
9+
"source": [
10+
"from solution import Solution\n",
11+
"\n",
12+
"from leetcode_py import ListNode"
13+
]
14+
},
15+
{
16+
"cell_type": "code",
17+
"execution_count": 6,
18+
"id": "setup",
19+
"metadata": {},
20+
"outputs": [],
21+
"source": [
22+
"# Example test case\n",
23+
"head_list = [1, 2, 3, 4, 5]\n",
24+
"expected_list = [3, 4, 5]"
25+
]
26+
},
27+
{
28+
"cell_type": "code",
29+
"execution_count": 7,
30+
"id": "execute",
31+
"metadata": {},
32+
"outputs": [
33+
{
34+
"data": {
35+
"text/html": [
36+
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
37+
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
38+
" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
39+
"<!-- Generated by graphviz version 13.1.2 (20250808.2320)\n",
40+
" -->\n",
41+
"<!-- Pages: 1 -->\n",
42+
"<svg width=\"242pt\" height=\"44pt\"\n",
43+
" viewBox=\"0.00 0.00 242.00 44.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
44+
"<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 40)\">\n",
45+
"<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-40 238,-40 238,4 -4,4\"/>\n",
46+
"<!-- node_0 -->\n",
47+
"<g id=\"node1\" class=\"node\">\n",
48+
"<title>node_0</title>\n",
49+
"<path fill=\"lightblue\" stroke=\"black\" d=\"M42,-36C42,-36 12,-36 12,-36 6,-36 0,-30 0,-24 0,-24 0,-12 0,-12 0,-6 6,0 12,0 12,0 42,0 42,0 48,0 54,-6 54,-12 54,-12 54,-24 54,-24 54,-30 48,-36 42,-36\"/>\n",
50+
"<text xml:space=\"preserve\" text-anchor=\"middle\" x=\"27\" y=\"-12.95\" font-family=\"Times,serif\" font-size=\"14.00\">3</text>\n",
51+
"</g>\n",
52+
"<!-- node_1 -->\n",
53+
"<g id=\"node2\" class=\"node\">\n",
54+
"<title>node_1</title>\n",
55+
"<path fill=\"lightblue\" stroke=\"black\" d=\"M132,-36C132,-36 102,-36 102,-36 96,-36 90,-30 90,-24 90,-24 90,-12 90,-12 90,-6 96,0 102,0 102,0 132,0 132,0 138,0 144,-6 144,-12 144,-12 144,-24 144,-24 144,-30 138,-36 132,-36\"/>\n",
56+
"<text xml:space=\"preserve\" text-anchor=\"middle\" x=\"117\" y=\"-12.95\" font-family=\"Times,serif\" font-size=\"14.00\">4</text>\n",
57+
"</g>\n",
58+
"<!-- node_0&#45;&gt;node_1 -->\n",
59+
"<g id=\"edge1\" class=\"edge\">\n",
60+
"<title>node_0&#45;&gt;node_1</title>\n",
61+
"<path fill=\"none\" stroke=\"black\" d=\"M54.4,-18C61.89,-18 70.18,-18 78.2,-18\"/>\n",
62+
"<polygon fill=\"black\" stroke=\"black\" points=\"78.1,-21.5 88.1,-18 78.1,-14.5 78.1,-21.5\"/>\n",
63+
"</g>\n",
64+
"<!-- node_2 -->\n",
65+
"<g id=\"node3\" class=\"node\">\n",
66+
"<title>node_2</title>\n",
67+
"<path fill=\"lightblue\" stroke=\"black\" d=\"M222,-36C222,-36 192,-36 192,-36 186,-36 180,-30 180,-24 180,-24 180,-12 180,-12 180,-6 186,0 192,0 192,0 222,0 222,0 228,0 234,-6 234,-12 234,-12 234,-24 234,-24 234,-30 228,-36 222,-36\"/>\n",
68+
"<text xml:space=\"preserve\" text-anchor=\"middle\" x=\"207\" y=\"-12.95\" font-family=\"Times,serif\" font-size=\"14.00\">5</text>\n",
69+
"</g>\n",
70+
"<!-- node_1&#45;&gt;node_2 -->\n",
71+
"<g id=\"edge2\" class=\"edge\">\n",
72+
"<title>node_1&#45;&gt;node_2</title>\n",
73+
"<path fill=\"none\" stroke=\"black\" d=\"M144.4,-18C151.89,-18 160.18,-18 168.2,-18\"/>\n",
74+
"<polygon fill=\"black\" stroke=\"black\" points=\"168.1,-21.5 178.1,-18 168.1,-14.5 168.1,-21.5\"/>\n",
75+
"</g>\n",
76+
"</g>\n",
77+
"</svg>\n"
78+
],
79+
"text/plain": [
80+
"ListNode([3, 4, 5])"
81+
]
82+
},
83+
"execution_count": 7,
84+
"metadata": {},
85+
"output_type": "execute_result"
86+
}
87+
],
88+
"source": [
89+
"head = ListNode.from_list(head_list)\n",
90+
"result = Solution().middle_node(head)\n",
91+
"result"
92+
]
93+
},
94+
{
95+
"cell_type": "code",
96+
"execution_count": 8,
97+
"id": "test",
98+
"metadata": {},
99+
"outputs": [],
100+
"source": [
101+
"expected = ListNode.from_list(expected_list)\n",
102+
"assert result == expected"
103+
]
104+
}
105+
],
106+
"metadata": {
107+
"kernelspec": {
108+
"display_name": "leetcode-py-py3.13",
109+
"language": "python",
110+
"name": "python3"
111+
},
112+
"language_info": {
113+
"codemirror_mode": {
114+
"name": "ipython",
115+
"version": 3
116+
},
117+
"file_extension": ".py",
118+
"mimetype": "text/x-python",
119+
"name": "python",
120+
"nbconvert_exporter": "python3",
121+
"pygments_lexer": "ipython3",
122+
"version": "3.13.7"
123+
}
124+
},
125+
"nbformat": 4,
126+
"nbformat_minor": 5
127+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from leetcode_py import ListNode
2+
3+
4+
class Solution:
5+
# Time: O(n)
6+
# Space: O(1)
7+
def middle_node(self, head: ListNode | None) -> ListNode | None:
8+
slow = fast = head
9+
while fast and fast.next:
10+
assert slow is not None
11+
slow = slow.next
12+
fast = fast.next.next
13+
return slow
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import pytest
2+
3+
from leetcode_py import ListNode
4+
from leetcode_py.test_utils import logged_test
5+
6+
from .solution import Solution
7+
8+
9+
class TestMiddleOfTheLinkedList:
10+
def setup_method(self):
11+
self.solution = Solution()
12+
13+
@pytest.mark.parametrize(
14+
"head_list, expected_list",
15+
[
16+
([1, 2, 3, 4, 5], [3, 4, 5]), # odd length
17+
([1, 2, 3, 4, 5, 6], [4, 5, 6]), # even length
18+
([1], [1]), # single node
19+
([1, 2], [2]), # two nodes
20+
([1, 2, 3], [2, 3]), # three nodes
21+
([1, 2, 3, 4], [3, 4]), # four nodes
22+
([10, 20, 30, 40, 50, 60, 70], [40, 50, 60, 70]), # larger odd
23+
([5, 15, 25, 35], [25, 35]), # larger even
24+
],
25+
)
26+
@logged_test
27+
def test_middle_node(self, head_list: list[int], expected_list: list[int]):
28+
head = ListNode.from_list(head_list)
29+
expected = ListNode.from_list(expected_list)
30+
result = self.solution.middle_node(head)
31+
assert result == expected

0 commit comments

Comments
 (0)