Skip to content

Commit 6f871f4

Browse files
wislerttclaude
andcommitted
feat: add 5 more leetcode problems
co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 8909af2 commit 6f871f4

36 files changed

Lines changed: 1296 additions & 0 deletions
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Count Good Nodes in Binary Tree
2+
3+
**Difficulty:** Medium
4+
**Topics:** Tree, Depth-First Search, Breadth-First Search, Binary Tree
5+
**Tags:** neetcode-150
6+
7+
**LeetCode:** [Problem 1448](https://leetcode.com/problems/count-good-nodes-in-binary-tree/description/)
8+
9+
## Problem Description
10+
11+
Given a binary tree `root`, a node _X_ in the tree is named **good** if in the path from root to _X_ there are no nodes with a value _greater than_ X.
12+
13+
Return the number of **good** nodes in the binary tree.
14+
15+
## Examples
16+
17+
### Example 1:
18+
19+
![Example 1](https://assets.leetcode.com/uploads/2020/04/02/test_sample_1.png)
20+
21+
```
22+
Input: root = [3,1,4,3,null,1,5]
23+
Output: 4
24+
Explanation: Nodes in blue are good.
25+
Root Node (3) is always a good node.
26+
Node 4 -> (3,4) is the maximum value in the path starting from the root.
27+
Node 5 -> (3,4,5) is the maximum value in the path.
28+
Node 3 -> (3,1,3) is the maximum value in the path.
29+
```
30+
31+
### Example 2:
32+
33+
![Example 2](https://assets.leetcode.com/uploads/2020/04/02/test_sample_2.png)
34+
35+
```
36+
Input: root = [3,3,null,4,2]
37+
Output: 3
38+
Explanation: Node 2 -> (3,3,2) is not good, because "3" is higher than it.
39+
```
40+
41+
### Example 3:
42+
43+
```
44+
Input: root = [1]
45+
Output: 1
46+
Explanation: Root is considered as good.
47+
```
48+
49+
## Constraints
50+
51+
- The number of nodes in the binary tree is in the range `[1, 10^5]`.
52+
- Each node's value is between `[-10^4, 10^4]`.

leetcode/count_good_nodes_in_binary_tree/__init__.py

Whitespace-only changes.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from leetcode_py import TreeNode
2+
3+
4+
def run_good_nodes(solution_class: type, root_list: list[int | None]):
5+
implementation = solution_class()
6+
root = TreeNode.from_list(root_list) if root_list else None
7+
return implementation.good_nodes(root)
8+
9+
10+
def assert_good_nodes(result: int, expected: int) -> bool:
11+
assert result == expected
12+
return True
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# ---
2+
# jupyter:
3+
# jupytext:
4+
# text_representation:
5+
# extension: .py
6+
# format_name: percent
7+
# format_version: '1.3'
8+
# jupytext_version: 1.19.4
9+
# kernelspec:
10+
# display_name: leetcode-py-py3.13
11+
# language: python
12+
# name: python3
13+
# ---
14+
15+
# %%
16+
from helpers import assert_good_nodes, run_good_nodes
17+
from solution import Solution
18+
19+
# %%
20+
# Example test case
21+
root_list: list[int | None] = [3, 1, 4, 3, None, 1, 5]
22+
expected = 4
23+
24+
# %%
25+
result = run_good_nodes(Solution, root_list)
26+
result
27+
28+
# %%
29+
assert_good_nodes(result, expected)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from leetcode_py import TreeNode
2+
3+
4+
class Solution:
5+
# Time: O(n)
6+
# Space: O(h) - recursion stack, h = tree height
7+
def good_nodes(self, root: TreeNode[int] | None) -> int:
8+
if root is None:
9+
return 0
10+
11+
def dfs(node: TreeNode[int], max_so_far: int) -> int:
12+
good = 1 if node.val >= max_so_far else 0
13+
next_max = max(max_so_far, node.val)
14+
total = good
15+
if node.left is not None:
16+
total += dfs(node.left, next_max)
17+
if node.right is not None:
18+
total += dfs(node.right, next_max)
19+
return total
20+
21+
return dfs(root, root.val)
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import pytest
2+
3+
from leetcode_py import logged_test
4+
5+
from .helpers import assert_good_nodes, run_good_nodes
6+
from .solution import Solution
7+
8+
9+
class TestCountGoodNodesInBinaryTree:
10+
def setup_method(self):
11+
self.solution = Solution()
12+
13+
@logged_test
14+
@pytest.mark.parametrize(
15+
"root_list, expected",
16+
[
17+
([3, 1, 4, 3, None, 1, 5], 4),
18+
([3, 3, None, 4, 2], 3),
19+
([1], 1),
20+
([], 0),
21+
([5], 1),
22+
([2, 1], 1),
23+
([2, 3], 2),
24+
([1, 2, 3], 3),
25+
([3, 2, 1], 1),
26+
([-1, -2, -3], 1),
27+
([-3, -1, -4], 2),
28+
([1, 2, 3, 4, 5, 6, 7], 7),
29+
([7, 6, 5, 4, 3, 2, 1], 1),
30+
([10, 5, 15], 2),
31+
([10, 10, 10], 3),
32+
([4, 2, 6, 1, 3, 5, 7], 3),
33+
([1, 1, 1, 1, None, 1, 1], 6),
34+
],
35+
)
36+
def test_good_nodes(self, root_list: list[int | None], expected: int):
37+
result = run_good_nodes(Solution, root_list)
38+
assert_good_nodes(result, expected)

leetcode/detect_squares/README.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Detect Squares
2+
3+
**Difficulty:** Medium
4+
**Topics:** Array, Hash Table, Design, Counting, Data Stream
5+
**Tags:** neetcode-150
6+
7+
**LeetCode:** [Problem 2013](https://leetcode.com/problems/detect-squares/description/)
8+
9+
## Problem Description
10+
11+
You are given a stream of points on the X-Y plane. Design an algorithm that:
12+
13+
- **Adds** new points from the stream into a data structure. **Duplicate** points are allowed and should be treated as different points.
14+
- Given a query point, **counts** the number of ways to choose three points from the data structure such that the three points and the query point form an **axis-aligned square** with **positive area**.
15+
16+
An **axis-aligned square** is a square whose edges are all the same length and are either parallel or perpendicular to the x-axis and y-axis.
17+
18+
Implement the `DetectSquares` class:
19+
20+
- `DetectSquares()` Initializes the object with an empty data structure.
21+
- `void add(int[] point)` Adds a new point `point = [x, y]` to the data structure.
22+
- `int count(int[] point)` Counts the number of ways to form **axis-aligned squares** with point `point = [x, y]` as described above.
23+
24+
## Examples
25+
26+
### Example 1:
27+
28+
![Example 1](https://assets.leetcode.com/uploads/2021/09/01/image.png)
29+
30+
```
31+
Input
32+
["DetectSquares", "add", "add", "add", "count", "count", "add", "count"]
33+
[[], [[3, 10]], [[11, 2]], [[3, 2]], [[11, 10]], [[14, 8]], [[11, 2]], [[11, 10]]]
34+
Output
35+
[null, null, null, null, 1, 0, null, 2]
36+
37+
Explanation
38+
DetectSquares detectSquares = new DetectSquares();
39+
detectSquares.add([3, 10]);
40+
detectSquares.add([11, 2]);
41+
detectSquares.add([3, 2]);
42+
detectSquares.count([11, 10]); // return 1.
43+
detectSquares.count([14, 8]); // return 0.
44+
detectSquares.add([11, 2]); // Adding duplicate points is allowed.
45+
detectSquares.count([11, 10]); // return 2.
46+
```
47+
48+
## Constraints
49+
50+
- `point.length == 2`
51+
- 0 <= x, y <= 1000
52+
- At most `3000` calls in total will be made to `add` and `count`.

leetcode/detect_squares/__init__.py

Whitespace-only changes.

leetcode/detect_squares/helpers.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from typing import Any
2+
3+
4+
def run_detect_squares(solution_class: type, operations: list[str], inputs: list[Any]):
5+
squares: Any = None
6+
results: list[Any] = []
7+
8+
for op, args in zip(operations, inputs, strict=False):
9+
if op == "DetectSquares":
10+
squares = solution_class()
11+
results.append(None)
12+
elif op == "add":
13+
assert squares is not None
14+
squares.add(args[0])
15+
results.append(None)
16+
elif op == "count":
17+
assert squares is not None
18+
results.append(squares.count(args[0]))
19+
20+
return results
21+
22+
23+
def assert_detect_squares(result: list[Any], expected: list[Any]) -> bool:
24+
assert result == expected
25+
return True
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# ---
2+
# jupyter:
3+
# jupytext:
4+
# text_representation:
5+
# extension: .py
6+
# format_name: percent
7+
# format_version: '1.3'
8+
# jupytext_version: 1.19.4
9+
# kernelspec:
10+
# display_name: leetcode-py-py3.13
11+
# language: python
12+
# name: python3
13+
# ---
14+
15+
# %%
16+
from helpers import assert_detect_squares, run_detect_squares
17+
from solution import DetectSquares
18+
19+
# %%
20+
# Example test case
21+
operations = ["DetectSquares", "add", "add", "add", "count", "count", "add", "count"]
22+
inputs = [[], [[3, 10]], [[11, 2]], [[3, 2]], [[11, 10]], [[14, 8]], [[11, 2]], [[11, 10]]]
23+
expected = [None, None, None, None, 1, 0, None, 2]
24+
25+
# %%
26+
result = run_detect_squares(DetectSquares, operations, inputs)
27+
result
28+
29+
# %%
30+
assert_detect_squares(result, expected)

0 commit comments

Comments
 (0)