Skip to content

Commit 1e31975

Browse files
committed
feat: add Diameter of Binary Tree
1 parent a93e761 commit 1e31975

File tree

7 files changed

+310
-1
lines changed

7 files changed

+310
-1
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{
2+
"problem_name": "diameter_of_binary_tree",
3+
"solution_class_name": "Solution",
4+
"problem_number": "543",
5+
"problem_title": "Diameter of Binary Tree",
6+
"difficulty": "Easy",
7+
"topics": "Tree, Depth-First Search, Binary Tree",
8+
"tags": ["grind-75"],
9+
"readme_description": "Given the `root` of a binary tree, return the length of the **diameter** of the tree.\n\nThe **diameter** of a binary tree is the **length** of the longest path between any two nodes in a tree. This path may or may not pass through the `root`.\n\nThe **length** of a path between two nodes is represented by the number of edges between them.",
10+
"readme_examples": [
11+
{
12+
"content": "![Example 1](https://assets.leetcode.com/uploads/2021/03/06/diamtree.jpg)\n\n```\nInput: root = [1,2,3,4,5]\nOutput: 3\n```\n**Explanation:** 3 is the length of the path [4,2,1,3] or [5,2,1,3]."
13+
},
14+
{ "content": "```\nInput: root = [1,2]\nOutput: 1\n```" }
15+
],
16+
"readme_constraints": "- The number of nodes in the tree is in the range [1, 10^4].\n- -100 <= Node.val <= 100",
17+
"readme_additional": "",
18+
"solution_imports": "from leetcode_py import TreeNode",
19+
"solution_methods": [
20+
{
21+
"name": "diameter_of_binary_tree",
22+
"parameters": "root: TreeNode | None",
23+
"return_type": "int",
24+
"dummy_return": "0"
25+
}
26+
],
27+
"test_imports": "import pytest\nfrom leetcode_py.test_utils import logged_test\nfrom leetcode_py import TreeNode\nfrom .solution import Solution",
28+
"test_class_name": "DiameterOfBinaryTree",
29+
"test_helper_methods": [
30+
{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }
31+
],
32+
"test_methods": [
33+
{
34+
"name": "test_diameter_of_binary_tree",
35+
"parametrize": "root_list, expected",
36+
"parametrize_typed": "root_list: list[int | None], expected: int",
37+
"test_cases": "[([1, 2, 3, 4, 5], 3), ([1, 2], 1)]",
38+
"body": "root = TreeNode.from_list(root_list)\nresult = self.solution.diameter_of_binary_tree(root)\nassert result == expected"
39+
}
40+
],
41+
"playground_imports": "from solution import Solution\nfrom leetcode_py import TreeNode",
42+
"playground_test_case": "# Example test case\nroot_list: list[int | None] = [1, 2, 3, 4, 5]\nexpected = 3",
43+
"playground_execution": "root = TreeNode.from_list(root_list)\nresult = Solution().diameter_of_binary_tree(root)\nresult",
44+
"playground_assertion": "assert result == expected"
45+
}

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

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Diameter of Binary Tree
2+
3+
**Difficulty:** Easy
4+
**Topics:** Tree, Depth-First Search, Binary Tree
5+
**Tags:** grind-75
6+
7+
**LeetCode:** [Problem 543](https://leetcode.com/problems/diameter-of-binary-tree/description/)
8+
9+
## Problem Description
10+
11+
Given the `root` of a binary tree, return the length of the **diameter** of the tree.
12+
13+
The **diameter** of a binary tree is the **length** of the longest path between any two nodes in a tree. This path may or may not pass through the `root`.
14+
15+
The **length** of a path between two nodes is represented by the number of edges between them.
16+
17+
## Examples
18+
19+
### Example 1:
20+
21+
![Example 1](https://assets.leetcode.com/uploads/2021/03/06/diamtree.jpg)
22+
23+
```
24+
Input: root = [1,2,3,4,5]
25+
Output: 3
26+
```
27+
28+
**Explanation:** 3 is the length of the path [4,2,1,3] or [5,2,1,3].
29+
30+
### Example 2:
31+
32+
```
33+
Input: root = [1,2]
34+
Output: 1
35+
```
36+
37+
## Constraints
38+
39+
- The number of nodes in the tree is in the range [1, 10^4].
40+
- -100 <= Node.val <= 100

leetcode/diameter_of_binary_tree/__init__.py

Whitespace-only changes.
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": 1,
6+
"id": "imports",
7+
"metadata": {},
8+
"outputs": [],
9+
"source": [
10+
"from solution import Solution\n",
11+
"\n",
12+
"from leetcode_py import TreeNode"
13+
]
14+
},
15+
{
16+
"cell_type": "code",
17+
"execution_count": 2,
18+
"id": "setup",
19+
"metadata": {},
20+
"outputs": [],
21+
"source": [
22+
"# Example test case\n",
23+
"root_list: list[int | None] = [1, 2, 3, 4, 5]\n",
24+
"expected = 3"
25+
]
26+
},
27+
{
28+
"cell_type": "code",
29+
"execution_count": 3,
30+
"id": "execute",
31+
"metadata": {},
32+
"outputs": [
33+
{
34+
"data": {
35+
"text/plain": [
36+
"3"
37+
]
38+
},
39+
"execution_count": 3,
40+
"metadata": {},
41+
"output_type": "execute_result"
42+
}
43+
],
44+
"source": [
45+
"root = TreeNode.from_list(root_list)\n",
46+
"result = Solution().diameter_of_binary_tree(root)\n",
47+
"result"
48+
]
49+
},
50+
{
51+
"cell_type": "code",
52+
"execution_count": 5,
53+
"id": "248f3295",
54+
"metadata": {},
55+
"outputs": [
56+
{
57+
"data": {
58+
"text/html": [
59+
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
60+
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
61+
" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
62+
"<!-- Generated by graphviz version 13.1.2 (20250808.2320)\n",
63+
" -->\n",
64+
"<!-- Pages: 1 -->\n",
65+
"<svg width=\"170pt\" height=\"188pt\"\n",
66+
" viewBox=\"0.00 0.00 170.00 188.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
67+
"<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 184)\">\n",
68+
"<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-184 166,-184 166,4 -4,4\"/>\n",
69+
"<!-- 0 -->\n",
70+
"<g id=\"node1\" class=\"node\">\n",
71+
"<title>0</title>\n",
72+
"<ellipse fill=\"none\" stroke=\"black\" cx=\"99\" cy=\"-162\" rx=\"27\" ry=\"18\"/>\n",
73+
"<text xml:space=\"preserve\" text-anchor=\"middle\" x=\"99\" y=\"-156.95\" font-family=\"Times,serif\" font-size=\"14.00\">1</text>\n",
74+
"</g>\n",
75+
"<!-- 1 -->\n",
76+
"<g id=\"node2\" class=\"node\">\n",
77+
"<title>1</title>\n",
78+
"<ellipse fill=\"none\" stroke=\"black\" cx=\"63\" cy=\"-90\" rx=\"27\" ry=\"18\"/>\n",
79+
"<text xml:space=\"preserve\" text-anchor=\"middle\" x=\"63\" y=\"-84.95\" font-family=\"Times,serif\" font-size=\"14.00\">2</text>\n",
80+
"</g>\n",
81+
"<!-- 0&#45;&gt;1 -->\n",
82+
"<g id=\"edge1\" class=\"edge\">\n",
83+
"<title>0&#45;&gt;1</title>\n",
84+
"<path fill=\"none\" stroke=\"black\" d=\"M90.65,-144.76C86.42,-136.55 81.19,-126.37 76.42,-117.09\"/>\n",
85+
"<polygon fill=\"black\" stroke=\"black\" points=\"79.68,-115.79 72,-108.49 73.46,-118.99 79.68,-115.79\"/>\n",
86+
"</g>\n",
87+
"<!-- 4 -->\n",
88+
"<g id=\"node5\" class=\"node\">\n",
89+
"<title>4</title>\n",
90+
"<ellipse fill=\"none\" stroke=\"black\" cx=\"135\" cy=\"-90\" rx=\"27\" ry=\"18\"/>\n",
91+
"<text xml:space=\"preserve\" text-anchor=\"middle\" x=\"135\" y=\"-84.95\" font-family=\"Times,serif\" font-size=\"14.00\">3</text>\n",
92+
"</g>\n",
93+
"<!-- 0&#45;&gt;4 -->\n",
94+
"<g id=\"edge4\" class=\"edge\">\n",
95+
"<title>0&#45;&gt;4</title>\n",
96+
"<path fill=\"none\" stroke=\"black\" d=\"M107.35,-144.76C111.58,-136.55 116.81,-126.37 121.58,-117.09\"/>\n",
97+
"<polygon fill=\"black\" stroke=\"black\" points=\"124.54,-118.99 126,-108.49 118.32,-115.79 124.54,-118.99\"/>\n",
98+
"</g>\n",
99+
"<!-- 2 -->\n",
100+
"<g id=\"node3\" class=\"node\">\n",
101+
"<title>2</title>\n",
102+
"<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
103+
"<text xml:space=\"preserve\" text-anchor=\"middle\" x=\"27\" y=\"-12.95\" font-family=\"Times,serif\" font-size=\"14.00\">4</text>\n",
104+
"</g>\n",
105+
"<!-- 1&#45;&gt;2 -->\n",
106+
"<g id=\"edge2\" class=\"edge\">\n",
107+
"<title>1&#45;&gt;2</title>\n",
108+
"<path fill=\"none\" stroke=\"black\" d=\"M54.65,-72.76C50.42,-64.55 45.19,-54.37 40.42,-45.09\"/>\n",
109+
"<polygon fill=\"black\" stroke=\"black\" points=\"43.68,-43.79 36,-36.49 37.46,-46.99 43.68,-43.79\"/>\n",
110+
"</g>\n",
111+
"<!-- 3 -->\n",
112+
"<g id=\"node4\" class=\"node\">\n",
113+
"<title>3</title>\n",
114+
"<ellipse fill=\"none\" stroke=\"black\" cx=\"99\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
115+
"<text xml:space=\"preserve\" text-anchor=\"middle\" x=\"99\" y=\"-12.95\" font-family=\"Times,serif\" font-size=\"14.00\">5</text>\n",
116+
"</g>\n",
117+
"<!-- 1&#45;&gt;3 -->\n",
118+
"<g id=\"edge3\" class=\"edge\">\n",
119+
"<title>1&#45;&gt;3</title>\n",
120+
"<path fill=\"none\" stroke=\"black\" d=\"M71.35,-72.76C75.58,-64.55 80.81,-54.37 85.58,-45.09\"/>\n",
121+
"<polygon fill=\"black\" stroke=\"black\" points=\"88.54,-46.99 90,-36.49 82.32,-43.79 88.54,-46.99\"/>\n",
122+
"</g>\n",
123+
"</g>\n",
124+
"</svg>\n"
125+
],
126+
"text/plain": [
127+
"TreeNode([1, 2, 3, 4, 5])"
128+
]
129+
},
130+
"execution_count": 5,
131+
"metadata": {},
132+
"output_type": "execute_result"
133+
}
134+
],
135+
"source": [
136+
"root"
137+
]
138+
},
139+
{
140+
"cell_type": "code",
141+
"execution_count": 4,
142+
"id": "test",
143+
"metadata": {},
144+
"outputs": [],
145+
"source": [
146+
"assert result == expected"
147+
]
148+
}
149+
],
150+
"metadata": {
151+
"kernelspec": {
152+
"display_name": "leetcode-py-py3.13",
153+
"language": "python",
154+
"name": "python3"
155+
},
156+
"language_info": {
157+
"codemirror_mode": {
158+
"name": "ipython",
159+
"version": 3
160+
},
161+
"file_extension": ".py",
162+
"mimetype": "text/x-python",
163+
"name": "python",
164+
"nbconvert_exporter": "python",
165+
"pygments_lexer": "ipython3",
166+
"version": "3.13.7"
167+
}
168+
},
169+
"nbformat": 4,
170+
"nbformat_minor": 5
171+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from leetcode_py import TreeNode
2+
3+
4+
class Solution:
5+
# Time: O(n)
6+
# Space: O(h)
7+
def diameter_of_binary_tree(self, root: TreeNode | None) -> int:
8+
self.max_diameter = 0
9+
10+
def dfs(node: TreeNode | None) -> int:
11+
if not node:
12+
return 0
13+
14+
left = dfs(node.left)
15+
right = dfs(node.right)
16+
17+
self.max_diameter = max(self.max_diameter, left + right)
18+
19+
return max(left, right) + 1
20+
21+
dfs(root)
22+
return self.max_diameter
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 TreeNode
4+
from leetcode_py.test_utils import logged_test
5+
6+
from .solution import Solution
7+
8+
9+
class TestDiameterOfBinaryTree:
10+
def setup_method(self):
11+
self.solution = Solution()
12+
13+
@pytest.mark.parametrize(
14+
"root_list, expected",
15+
[
16+
([1, 2, 3, 4, 5], 3),
17+
([1, 2], 1),
18+
([1], 0),
19+
([], 0),
20+
([1, 2, 3, 4, 5, None, None, 6, 7], 4),
21+
([1, None, 2, None, 3, None, 4], 3),
22+
([1, 2, None, 3, None, 4], 3),
23+
([1, 2, 3], 2),
24+
([1, 2, 3, 4, None, None, 5], 4),
25+
],
26+
)
27+
@logged_test
28+
def test_diameter_of_binary_tree(self, root_list: list[int | None], expected: int):
29+
root = TreeNode.from_list(root_list)
30+
result = self.solution.diameter_of_binary_tree(root)
31+
assert result == expected

0 commit comments

Comments
 (0)