Skip to content

Commit d73819b

Browse files
committed
feat: add Course Schedule
1 parent 197c64b commit d73819b

File tree

25 files changed

+895
-1
lines changed

25 files changed

+895
-1
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
{
2+
"problem_name": "binary_tree_level_order_traversal",
3+
"solution_class_name": "Solution",
4+
"problem_number": "102",
5+
"problem_title": "Binary Tree Level Order Traversal",
6+
"difficulty": "Medium",
7+
"topics": "Tree, Breadth-First Search, Binary Tree",
8+
"tags": ["grind-75"],
9+
"readme_description": "Given the `root` of a binary tree, return the level order traversal of its nodes' values. (i.e., from left to right, level by level).",
10+
"readme_examples": [
11+
{
12+
"content": "![Example 1](https://assets.leetcode.com/uploads/2021/02/19/tree1.jpg)\n\n```\nInput: root = [3,9,20,null,null,15,7]\nOutput: [[3],[9,20],[15,7]]\n```"
13+
},
14+
{ "content": "```\nInput: root = [1]\nOutput: [[1]]\n```" },
15+
{ "content": "```\nInput: root = []\nOutput: []\n```" }
16+
],
17+
"readme_constraints": "- The number of nodes in the tree is in the range [0, 2000]\n- -1000 <= Node.val <= 1000",
18+
"readme_additional": "",
19+
"solution_imports": "from leetcode_py import TreeNode",
20+
"solution_methods": [
21+
{
22+
"name": "level_order",
23+
"parameters": "root: TreeNode | None",
24+
"return_type": "list[list[int]]",
25+
"dummy_return": "[]"
26+
}
27+
],
28+
"test_imports": "import pytest\nfrom leetcode_py.test_utils import logged_test\nfrom leetcode_py import TreeNode\nfrom .solution import Solution",
29+
"test_class_name": "BinaryTreeLevelOrderTraversal",
30+
"test_helper_methods": [
31+
{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }
32+
],
33+
"test_methods": [
34+
{
35+
"name": "test_level_order",
36+
"parametrize": "root_list, expected",
37+
"parametrize_typed": "root_list: list[int | None], expected: list[list[int]]",
38+
"test_cases": "[([3, 9, 20, None, None, 15, 7], [[3], [9, 20], [15, 7]]), ([1], [[1]]), ([], []), ([1, 2, 3, 4, 5, 6, 7], [[1], [2, 3], [4, 5, 6, 7]]), ([1, 2, None, 3, None, 4, None, 5], [[1], [2], [3], [4], [5]])]",
39+
"body": "root = TreeNode.from_list(root_list) if root_list else None\nresult = self.solution.level_order(root)\nassert result == expected"
40+
}
41+
],
42+
"playground_imports": "from solution import Solution\nfrom leetcode_py import TreeNode",
43+
"playground_test_case": "# Example test case\nroot_list = [3, 9, 20, None, None, 15, 7]\nroot = TreeNode.from_list(root_list)\nexpected = [[3], [9, 20], [15, 7]]",
44+
"playground_execution": "result = Solution().level_order(root)\nresult",
45+
"playground_assertion": "assert result == expected"
46+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"problem_name": "course_schedule",
3+
"solution_class_name": "Solution",
4+
"problem_number": "207",
5+
"problem_title": "Course Schedule",
6+
"difficulty": "Medium",
7+
"topics": "Depth-First Search, Breadth-First Search, Graph, Topological Sort",
8+
"tags": ["grind-75"],
9+
"readme_description": "There are a total of `numCourses` courses you have to take, labeled from `0` to `numCourses - 1`. You are given an array `prerequisites` where `prerequisites[i] = [ai, bi]` indicates that you **must** take course `bi` first if you want to take course `ai`.\n\n- For example, the pair `[0, 1]`, indicates that to take course `0` you have to first take course `1`.\n\nReturn `true` if you can finish all courses. Otherwise, return `false`.",
10+
"readme_examples": [
11+
{
12+
"content": "```\nInput: numCourses = 2, prerequisites = [[1,0]]\nOutput: true\n```\n**Explanation:** There are a total of 2 courses to take. To take course 1 you should have finished course 0. So it is possible."
13+
},
14+
{
15+
"content": "```\nInput: numCourses = 2, prerequisites = [[1,0],[0,1]]\nOutput: false\n```\n**Explanation:** There are a total of 2 courses to take. To take course 1 you should have finished course 0, and to take course 0 you should also have finished course 1. So it is impossible."
16+
}
17+
],
18+
"readme_constraints": "- `1 <= numCourses <= 2000`\n- `0 <= prerequisites.length <= 5000`\n- `prerequisites[i].length == 2`\n- `0 <= ai, bi < numCourses`\n- All the pairs prerequisites[i] are **unique**.",
19+
"readme_additional": "",
20+
"solution_imports": "",
21+
"solution_methods": [
22+
{
23+
"name": "can_finish",
24+
"parameters": "num_courses: int, prerequisites: list[list[int]]",
25+
"return_type": "bool",
26+
"dummy_return": "False"
27+
}
28+
],
29+
"test_imports": "import pytest\nfrom leetcode_py.test_utils import logged_test\nfrom .solution import Solution",
30+
"test_class_name": "CourseSchedule",
31+
"test_helper_methods": [
32+
{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }
33+
],
34+
"test_methods": [
35+
{
36+
"name": "test_can_finish",
37+
"parametrize": "num_courses, prerequisites, expected",
38+
"parametrize_typed": "num_courses: int, prerequisites: list[list[int]], expected: bool",
39+
"test_cases": "[(2, [[1, 0]], True), (2, [[1, 0], [0, 1]], False), (1, [], True), (3, [[1, 0], [2, 1]], True), (4, [[1, 0], [2, 1], [3, 2], [1, 3]], False)]",
40+
"body": "result = self.solution.can_finish(num_courses, prerequisites)\nassert result == expected"
41+
}
42+
],
43+
"playground_imports": "from solution import Solution",
44+
"playground_test_case": "# Example test case\nnum_courses = 2\nprerequisites = [[1, 0]]\nexpected = True",
45+
"playground_execution": "result = Solution().can_finish(num_courses, prerequisites)\nresult",
46+
"playground_assertion": "assert result == expected"
47+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
{
2+
"problem_name": "longest_substring_without_repeating_characters",
3+
"solution_class_name": "Solution",
4+
"problem_number": "3",
5+
"problem_title": "Longest Substring Without Repeating Characters",
6+
"difficulty": "Medium",
7+
"topics": "Hash Table, String, Sliding Window",
8+
"tags": ["grind-75"],
9+
"readme_description": "Given a string `s`, find the length of the **longest** **substring** without duplicate characters.",
10+
"readme_examples": [
11+
{
12+
"content": "```\nInput: s = \"abcabcbb\"\nOutput: 3\n```\n**Explanation:** The answer is \"abc\", with the length of 3."
13+
},
14+
{
15+
"content": "```\nInput: s = \"bbbbb\"\nOutput: 1\n```\n**Explanation:** The answer is \"b\", with the length of 1."
16+
},
17+
{
18+
"content": "```\nInput: s = \"pwwkew\"\nOutput: 3\n```\n**Explanation:** The answer is \"wke\", with the length of 3.\nNotice that the answer must be a substring, \"pwke\" is a subsequence and not a substring."
19+
}
20+
],
21+
"readme_constraints": "- 0 <= s.length <= 5 * 10^4\n- s consists of English letters, digits, symbols and spaces.",
22+
"readme_additional": "",
23+
"solution_imports": "",
24+
"solution_methods": [
25+
{
26+
"name": "length_of_longest_substring",
27+
"parameters": "s: str",
28+
"return_type": "int",
29+
"dummy_return": "0"
30+
}
31+
],
32+
"test_imports": "import pytest\nfrom leetcode_py.test_utils import logged_test\nfrom .solution import Solution",
33+
"test_class_name": "LongestSubstringWithoutRepeatingCharacters",
34+
"test_helper_methods": [
35+
{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }
36+
],
37+
"test_methods": [
38+
{
39+
"name": "test_length_of_longest_substring",
40+
"parametrize": "s, expected",
41+
"parametrize_typed": "s: str, expected: int",
42+
"test_cases": "[('abcabcbb', 3), ('bbbbb', 1), ('pwwkew', 3), ('', 0), ('a', 1), ('au', 2), ('dvdf', 3)]",
43+
"body": "result = self.solution.length_of_longest_substring(s)\nassert result == expected"
44+
}
45+
],
46+
"playground_imports": "from solution import Solution",
47+
"playground_test_case": "# Example test case\ns = 'abcabcbb'\nexpected = 3",
48+
"playground_execution": "result = Solution().length_of_longest_substring(s)\nresult",
49+
"playground_assertion": "assert result == expected"
50+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
{
2+
"problem_name": "three_sum",
3+
"solution_class_name": "Solution",
4+
"problem_number": "15",
5+
"problem_title": "3Sum",
6+
"difficulty": "Medium",
7+
"topics": "Array, Two Pointers, Sorting",
8+
"tags": ["grind-75"],
9+
"readme_description": "Given an integer array `nums`, return all the triplets `[nums[i], nums[j], nums[k]]` such that `i != j`, `i != k`, and `j != k`, and `nums[i] + nums[j] + nums[k] == 0`.\n\nNotice that the solution set must not contain duplicate triplets.",
10+
"readme_examples": [
11+
{
12+
"content": "```\nInput: nums = [-1,0,1,2,-1,-4]\nOutput: [[-1,-1,2],[-1,0,1]]\n```\n**Explanation:** \nnums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0.\nnums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0.\nnums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0.\nThe distinct triplets are [-1,0,1] and [-1,-1,2].\nNotice that the order of the output and the order of the triplets does not matter."
13+
},
14+
{
15+
"content": "```\nInput: nums = [0,1,1]\nOutput: []\n```\n**Explanation:** The only possible triplet does not sum up to 0."
16+
},
17+
{
18+
"content": "```\nInput: nums = [0,0,0]\nOutput: [[0,0,0]]\n```\n**Explanation:** The only possible triplet sums up to 0."
19+
}
20+
],
21+
"readme_constraints": "- 3 <= nums.length <= 3000\n- -10^5 <= nums[i] <= 10^5",
22+
"readme_additional": "",
23+
"solution_imports": "",
24+
"solution_methods": [
25+
{
26+
"name": "three_sum",
27+
"parameters": "nums: 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": "ThreeSum",
34+
"test_helper_methods": [
35+
{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }
36+
],
37+
"test_methods": [
38+
{
39+
"name": "test_three_sum",
40+
"parametrize": "nums, expected",
41+
"parametrize_typed": "nums: list[int], expected: list[list[int]]",
42+
"test_cases": "[([-1, 0, 1, 2, -1, -4], [[-1, -1, 2], [-1, 0, 1]]), ([0, 1, 1], []), ([0, 0, 0], [[0, 0, 0]]), ([-1, 0, 1], [[-1, 0, 1]]), ([1, 2, -2, -1], []), ([-2, 0, 1, 1, 2], [[-2, 0, 2], [-2, 1, 1]])]",
43+
"body": "result = self.solution.three_sum(nums)\n# Sort both result and expected for comparison since order doesn't matter\nresult_sorted = [sorted(triplet) for triplet in result]\nexpected_sorted = [sorted(triplet) for triplet in expected]\nresult_sorted.sort()\nexpected_sorted.sort()\nassert result_sorted == expected_sorted"
44+
}
45+
],
46+
"playground_imports": "from solution import Solution",
47+
"playground_test_case": "# Example test case\nnums = [-1, 0, 1, 2, -1, -4]\nexpected = [[-1, -1, 2], [-1, 0, 1]]",
48+
"playground_execution": "result = Solution().three_sum(nums)\nresult",
49+
"playground_assertion": "# Sort for comparison since order doesn't matter\nresult_sorted = [sorted(triplet) for triplet in result]\nexpected_sorted = [sorted(triplet) for triplet in expected]\nresult_sorted.sort()\nexpected_sorted.sort()\nassert result_sorted == expected_sorted"
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 ?= zero_one_matrix
2+
PROBLEM ?= course_schedule
33
FORCE ?= 0
44
COMMA := ,
55

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Binary Tree Level Order Traversal
2+
3+
**Difficulty:** Medium
4+
**Topics:** Tree, Breadth-First Search, Binary Tree
5+
**Tags:** grind-75
6+
7+
**LeetCode:** [Problem 102](https://leetcode.com/problems/binary-tree-level-order-traversal/description/)
8+
9+
## Problem Description
10+
11+
Given the `root` of a binary tree, return the level order traversal of its nodes' values. (i.e., from left to right, level by level).
12+
13+
## Examples
14+
15+
### Example 1:
16+
17+
![Example 1](https://assets.leetcode.com/uploads/2021/02/19/tree1.jpg)
18+
19+
```
20+
Input: root = [3,9,20,null,null,15,7]
21+
Output: [[3],[9,20],[15,7]]
22+
```
23+
24+
### Example 2:
25+
26+
```
27+
Input: root = [1]
28+
Output: [[1]]
29+
```
30+
31+
### Example 3:
32+
33+
```
34+
Input: root = []
35+
Output: []
36+
```
37+
38+
## Constraints
39+
40+
- The number of nodes in the tree is in the range [0, 2000]
41+
- -1000 <= Node.val <= 1000

leetcode/binary_tree_level_order_traversal/__init__.py

Whitespace-only changes.
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
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\n",
11+
"\n",
12+
"from leetcode_py import TreeNode"
13+
]
14+
},
15+
{
16+
"cell_type": "code",
17+
"execution_count": null,
18+
"id": "setup",
19+
"metadata": {},
20+
"outputs": [],
21+
"source": [
22+
"# Example test case\n",
23+
"root_list = [3, 9, 20, None, None, 15, 7]\n",
24+
"root = TreeNode.from_list(root_list)\n",
25+
"expected = [[3], [9, 20], [15, 7]]"
26+
]
27+
},
28+
{
29+
"cell_type": "code",
30+
"execution_count": null,
31+
"id": "execute",
32+
"metadata": {},
33+
"outputs": [],
34+
"source": [
35+
"result = Solution().level_order(root)\n",
36+
"result"
37+
]
38+
},
39+
{
40+
"cell_type": "code",
41+
"execution_count": null,
42+
"id": "test",
43+
"metadata": {},
44+
"outputs": [],
45+
"source": [
46+
"assert result == expected"
47+
]
48+
}
49+
],
50+
"metadata": {
51+
"kernelspec": {
52+
"display_name": "leetcode-py-py3.13",
53+
"language": "python",
54+
"name": "python3"
55+
},
56+
"language_info": {
57+
"codemirror_mode": {
58+
"name": "ipython",
59+
"version": 3
60+
},
61+
"file_extension": ".py",
62+
"mimetype": "text/x-python",
63+
"name": "python",
64+
"nbconvert_exporter": "python3",
65+
"pygments_lexer": "ipython3",
66+
"version": "3.13.7"
67+
}
68+
},
69+
"nbformat": 4,
70+
"nbformat_minor": 5
71+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from collections import deque
2+
3+
from leetcode_py import TreeNode
4+
5+
6+
class Solution:
7+
# Time: O(n)
8+
# Space: O(w) where w is max width of tree
9+
def level_order(self, root: TreeNode | None) -> list[list[int]]:
10+
if not root:
11+
return []
12+
13+
result = []
14+
queue = deque([root])
15+
16+
while queue:
17+
level_size = len(queue)
18+
level = []
19+
20+
for _ in range(level_size):
21+
node = queue.popleft()
22+
level.append(node.val)
23+
24+
if node.left:
25+
queue.append(node.left)
26+
if node.right:
27+
queue.append(node.right)
28+
29+
result.append(level)
30+
31+
return result
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
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 TestBinaryTreeLevelOrderTraversal:
10+
def setup_method(self):
11+
self.solution = Solution()
12+
13+
@pytest.mark.parametrize(
14+
"root_list, expected",
15+
[
16+
([3, 9, 20, None, None, 15, 7], [[3], [9, 20], [15, 7]]),
17+
([1], [[1]]),
18+
([], []),
19+
([1, 2, 3, 4, 5, 6, 7], [[1], [2, 3], [4, 5, 6, 7]]),
20+
([1, 2, None, 3, None, 4, None, 5], [[1], [2], [3], [4], [5]]),
21+
# Edge cases
22+
([1, None, 2, None, 3], [[1], [2], [3]]), # Right skewed
23+
([1, 2, None, 3, None], [[1], [2], [3]]), # Left skewed
24+
([0], [[0]]), # Single zero node
25+
([-1, -2, -3], [[-1], [-2, -3]]), # Negative values
26+
([1, 2, 3, None, None, None, 4], [[1], [2, 3], [4]]), # Sparse tree
27+
(
28+
[5, 4, 8, 11, None, 13, 4, 7, 2, None, None, None, 1],
29+
[[5], [4, 8], [11, 13, 4], [7, 2, 1]],
30+
), # Complex tree
31+
([1, 2, 2, 3, 3, 3, 3], [[1], [2, 2], [3, 3, 3, 3]]), # Duplicate values
32+
([1, None, None], [[1]]), # Single node with null children
33+
],
34+
)
35+
@logged_test
36+
def test_level_order(self, root_list: list[int | None], expected: list[list[int]]):
37+
root = TreeNode.from_list(root_list) if root_list else None
38+
result = self.solution.level_order(root)
39+
assert result == expected

0 commit comments

Comments
 (0)