Skip to content

Commit 9199d8c

Browse files
authored
feat: add more leetcode problems (#28)
1 parent 60123aa commit 9199d8c

37 files changed

+1611
-4
lines changed

.amazonq/rules/problem-creation.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,13 @@ When creating JSON properties that use PascalCase (solution_class_name, test_cla
136136
- Complex test setup with operation sequences
137137
- Import custom class in test_imports
138138

139+
### Dict-based Tree Problems (Trie, etc.)
140+
141+
- Add `"solution_imports": "from leetcode_py.data_structures import DictTree"`
142+
- Inherit from `DictTree[str]` for string-based trees like Trie
143+
- Provides automatic visualization capabilities
144+
- Use `dict[str, Any]` for internal tree structure
145+
139146
## Generation Commands
140147

141148
```bash
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
{
2+
"problem_name": "add_binary",
3+
"solution_class_name": "Solution",
4+
"problem_number": "67",
5+
"problem_title": "Add Binary",
6+
"difficulty": "Easy",
7+
"topics": "Math, String, Bit Manipulation, Simulation",
8+
"tags": ["grind-75"],
9+
"readme_description": "Given two binary strings `a` and `b`, return *their sum as a binary string*.",
10+
"readme_examples": [
11+
{ "content": "```\nInput: a = \"11\", b = \"1\"\nOutput: \"100\"\n```" },
12+
{ "content": "```\nInput: a = \"1010\", b = \"1011\"\nOutput: \"10101\"\n```" }
13+
],
14+
"readme_constraints": "- `1 <= a.length, b.length <= 10^4`\n- `a` and `b` consist only of `'0'` or `'1'` characters.\n- Each string does not contain leading zeros except for the zero itself.",
15+
"readme_additional": "",
16+
"solution_imports": "",
17+
"solution_methods": [
18+
{
19+
"name": "add_binary",
20+
"parameters": "a: str, b: str",
21+
"return_type": "str",
22+
"dummy_return": "\"\""
23+
}
24+
],
25+
"test_imports": "import pytest\nfrom leetcode_py.test_utils import logged_test\nfrom .solution import Solution",
26+
"test_class_name": "AddBinary",
27+
"test_helper_methods": [
28+
{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }
29+
],
30+
"test_methods": [
31+
{
32+
"name": "test_add_binary",
33+
"parametrize": "a, b, expected",
34+
"parametrize_typed": "a: str, b: str, expected: str",
35+
"test_cases": "[('11', '1', '100'), ('1010', '1011', '10101'), ('0', '0', '0'), ('1', '1', '10'), ('1111', '1111', '11110')]",
36+
"body": "result = self.solution.add_binary(a, b)\nassert result == expected"
37+
}
38+
],
39+
"playground_imports": "from solution import Solution",
40+
"playground_test_case": "# Example test case\na = '11'\nb = '1'\nexpected = '100'",
41+
"playground_execution": "result = Solution().add_binary(a, b)\nresult",
42+
"playground_assertion": "assert result == expected"
43+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{
2+
"problem_name": "implement_trie_prefix_tree",
3+
"solution_class_name": "Trie(DictTree[str])",
4+
"problem_number": "208",
5+
"problem_title": "Implement Trie (Prefix Tree)",
6+
"difficulty": "Medium",
7+
"topics": "Hash Table, String, Design, Trie",
8+
"tags": ["grind-75"],
9+
"readme_description": "A **trie** (pronounced as \"try\") or **prefix tree** is a tree data structure used to efficiently store and retrieve keys in a dataset of strings. There are various applications of this data structure, such as autocomplete and spellchecker.\n\nImplement the Trie class:\n\n- `Trie()` Initializes the trie object.\n- `void insert(String word)` Inserts the string `word` into the trie.\n- `boolean search(String word)` Returns `true` if the string `word` is in the trie (i.e., was inserted before), and `false` otherwise.\n- `boolean startsWith(String prefix)` Returns `true` if there is a previously inserted string `word` that has the prefix `prefix`, and `false` otherwise.",
10+
"readme_examples": [
11+
{
12+
"content": "```\nInput\n[\"Trie\", \"insert\", \"search\", \"search\", \"startsWith\", \"insert\", \"search\"]\n[[], [\"apple\"], [\"apple\"], [\"app\"], [\"app\"], [\"app\"], [\"app\"]]\nOutput\n[null, null, true, false, true, null, true]\n```\n\n**Explanation:**\n```python\ntrie = Trie()\ntrie.insert(\"apple\")\ntrie.search(\"apple\") # return True\ntrie.search(\"app\") # return False\ntrie.starts_with(\"app\") # return True\ntrie.insert(\"app\")\ntrie.search(\"app\") # return True\n```"
13+
}
14+
],
15+
"readme_constraints": "- `1 <= word.length, prefix.length <= 2000`\n- `word` and `prefix` consist only of lowercase English letters.\n- At most `3 * 10^4` calls **in total** will be made to `insert`, `search`, and `starts_with`.",
16+
"readme_additional": "",
17+
"solution_imports": "from leetcode_py.data_structures import DictTree",
18+
"solution_methods": [
19+
{ "name": "__init__", "parameters": "", "return_type": "None", "dummy_return": "" },
20+
{ "name": "insert", "parameters": "word: str", "return_type": "None", "dummy_return": "" },
21+
{ "name": "search", "parameters": "word: str", "return_type": "bool", "dummy_return": "False" },
22+
{
23+
"name": "starts_with",
24+
"parameters": "prefix: str",
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 Trie",
30+
"test_class_name": "ImplementTriePrefixTree",
31+
"test_helper_methods": [],
32+
"test_methods": [
33+
{
34+
"name": "test_trie_operations",
35+
"parametrize": "operations, inputs, expected",
36+
"parametrize_typed": "operations: list[str], inputs: list[list[str]], expected: list[bool | None]",
37+
"test_cases": "[(['Trie', 'insert', 'search', 'search', 'starts_with', 'insert', 'search'], [[], ['apple'], ['apple'], ['app'], ['app'], ['app'], ['app']], [None, None, True, False, True, None, True]), (['Trie', 'insert', 'insert', 'search', 'search', 'starts_with', 'starts_with'], [[], ['hello'], ['world'], ['hello'], ['hi'], ['hel'], ['wor']], [None, None, None, True, False, True, True]), (['Trie', 'insert', 'insert', 'search', 'search', 'starts_with', 'starts_with'], [[], ['a'], ['aa'], ['a'], ['aa'], ['a'], ['aa']], [None, None, None, True, True, True, True]), (['Trie', 'insert', 'search', 'starts_with', 'insert', 'search', 'starts_with'], [[], ['test'], ['testing'], ['test'], ['testing'], ['testing'], ['test']], [None, None, False, True, None, True, True]), (['Trie', 'search', 'starts_with'], [[], ['empty'], ['empty']], [None, False, False])]",
38+
"body": "trie: Trie | None = None\nresults: list[bool | None] = []\nfor i, op in enumerate(operations):\n if op == 'Trie':\n trie = Trie()\n results.append(None)\n elif op == 'insert' and trie is not None:\n trie.insert(inputs[i][0])\n results.append(None)\n elif op == 'search' and trie is not None:\n results.append(trie.search(inputs[i][0]))\n elif op == 'starts_with' and trie is not None:\n results.append(trie.starts_with(inputs[i][0]))\nassert results == expected"
39+
}
40+
],
41+
"playground_imports": "from solution import Trie",
42+
"playground_test_case": "# Example test case\noperations = ['Trie', 'insert', 'search', 'search', 'starts_with', 'insert', 'search']\ninputs = [[], ['apple'], ['apple'], ['app'], ['app'], ['app'], ['app']]\nexpected = [None, None, True, False, True, None, True]",
43+
"playground_execution": "trie = None\nresults: list[bool | None] = []\nfor i, op in enumerate(operations):\n if op == 'Trie':\n trie = Trie()\n results.append(None)\n elif op == 'insert' and trie is not None:\n trie.insert(inputs[i][0])\n results.append(None)\n elif op == 'search' and trie is not None:\n results.append(trie.search(inputs[i][0]))\n elif op == 'starts_with' and trie is not None:\n results.append(trie.starts_with(inputs[i][0]))\nresults",
44+
"playground_assertion": "assert results == expected"
45+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{
2+
"problem_name": "maximum_depth_of_binary_tree",
3+
"solution_class_name": "Solution",
4+
"problem_number": "104",
5+
"problem_title": "Maximum Depth of Binary Tree",
6+
"difficulty": "Easy",
7+
"topics": "Tree, Depth-First Search, Breadth-First Search, Binary Tree",
8+
"tags": ["grind-75"],
9+
"readme_description": "Given the `root` of a binary tree, return *its maximum depth*.\n\nA binary tree's **maximum depth** is the number of nodes along the longest path from the root node down to the farthest leaf node.",
10+
"readme_examples": [
11+
{
12+
"content": "![Example 1](https://assets.leetcode.com/uploads/2020/11/26/tmp-tree.jpg)\n\n```\nInput: root = [3,9,20,null,null,15,7]\nOutput: 3\n```"
13+
},
14+
{ "content": "```\nInput: root = [1,null,2]\nOutput: 2\n```" }
15+
],
16+
"readme_constraints": "- The number of nodes in the tree is in the range `[0, 10^4]`.\n- `-100 <= Node.val <= 100`",
17+
"readme_additional": "",
18+
"solution_imports": "from leetcode_py import TreeNode",
19+
"solution_methods": [
20+
{
21+
"name": "max_depth",
22+
"parameters": "root: TreeNode[int] | 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": "MaximumDepthOfBinaryTree",
29+
"test_helper_methods": [
30+
{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }
31+
],
32+
"test_methods": [
33+
{
34+
"name": "test_max_depth",
35+
"parametrize": "root_list, expected",
36+
"parametrize_typed": "root_list: list[int | None], expected: int",
37+
"test_cases": "[([3, 9, 20, None, None, 15, 7], 3), ([1, None, 2], 2), ([], 0)]",
38+
"body": "root = TreeNode.from_list(root_list)\nresult = self.solution.max_depth(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 = [3, 9, 20, None, None, 15, 7]\nexpected = 3",
43+
"playground_execution": "root = TreeNode.from_list(root_list)\nresult = Solution().max_depth(root)\nresult",
44+
"playground_assertion": "assert result == expected"
45+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
{
2+
"problem_name": "product_of_array_except_self",
3+
"solution_class_name": "Solution",
4+
"problem_number": "238",
5+
"problem_title": "Product of Array Except Self",
6+
"difficulty": "Medium",
7+
"topics": "Array, Prefix Sum",
8+
"tags": ["grind-75"],
9+
"readme_description": "Given an integer array `nums`, return an array `answer` such that `answer[i]` is equal to the product of all the elements of `nums` except `nums[i]`.\n\nThe product of any prefix or suffix of `nums` is guaranteed to fit in a 32-bit integer.\n\nYou must write an algorithm that runs in O(n) time and without using the division operation.",
10+
"readme_examples": [
11+
{ "content": "```\nInput: nums = [1,2,3,4]\nOutput: [24,12,8,6]\n```" },
12+
{ "content": "```\nInput: nums = [-1,1,0,-3,3]\nOutput: [0,0,9,0,0]\n```" }
13+
],
14+
"readme_constraints": "- 2 <= nums.length <= 10^5\n- -30 <= nums[i] <= 30\n- The input is generated such that answer[i] is guaranteed to fit in a 32-bit integer.",
15+
"readme_additional": "**Follow up:** Can you solve the problem in O(1) extra space complexity? (The output array does not count as extra space for space complexity analysis.)",
16+
"solution_imports": "",
17+
"solution_methods": [
18+
{
19+
"name": "product_except_self",
20+
"parameters": "nums: list[int]",
21+
"return_type": "list[int]",
22+
"dummy_return": "[]"
23+
}
24+
],
25+
"test_imports": "import pytest\nfrom leetcode_py.test_utils import logged_test\nfrom .solution import Solution",
26+
"test_class_name": "ProductOfArrayExceptSelf",
27+
"test_helper_methods": [
28+
{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }
29+
],
30+
"test_methods": [
31+
{
32+
"name": "test_product_except_self",
33+
"parametrize": "nums, expected",
34+
"parametrize_typed": "nums: list[int], expected: list[int]",
35+
"test_cases": "[([1, 2, 3, 4], [24, 12, 8, 6]), ([-1, 1, 0, -3, 3], [0, 0, 9, 0, 0]), ([2, 3, 4, 5], [60, 40, 30, 24])]",
36+
"body": "result = self.solution.product_except_self(nums)\nassert result == expected"
37+
}
38+
],
39+
"playground_imports": "from solution import Solution",
40+
"playground_test_case": "# Example test case\nnums = [1, 2, 3, 4]\nexpected = [24, 12, 8, 6]",
41+
"playground_execution": "result = Solution().product_except_self(nums)\nresult",
42+
"playground_assertion": "assert result == expected"
43+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
{
2+
"problem_name": "string_to_integer_atoi",
3+
"solution_class_name": "Solution",
4+
"problem_number": "8",
5+
"problem_title": "String to Integer (atoi)",
6+
"difficulty": "Medium",
7+
"topics": "String",
8+
"tags": ["grind-75"],
9+
"readme_description": "Implement the `my_atoi(string s)` function, which converts a string to a 32-bit signed integer.\n\nThe algorithm for `my_atoi(string s)` is as follows:\n\n1. **Whitespace**: Ignore any leading whitespace (` `).\n2. **Signedness**: Determine the sign by checking if the next character is `-` or `+`, assuming positivity if neither present.\n3. **Conversion**: Read the integer by skipping leading zeros until a non-digit character is encountered or the end of the string is reached. If no digits were read, then the result is 0.\n4. **Rounding**: If the integer is out of the 32-bit signed integer range `[-2^31, 2^31 - 1]`, then round the integer to remain in the range. Specifically, integers less than `-2^31` should be rounded to `-2^31`, and integers greater than `2^31 - 1` should be rounded to `2^31 - 1`.\n\nReturn the integer as the final result.",
10+
"readme_examples": [
11+
{
12+
"content": "```\nInput: s = \"42\"\nOutput: 42\n```\n**Explanation:**\n```\nThe underlined characters are what is read in and the caret is the current reader position.\nStep 1: \"42\" (no characters read because there is no leading whitespace)\n ^\nStep 2: \"42\" (no characters read because there is neither a '-' nor '+')\n ^\nStep 3: \"42\" (\"42\" is read in)\n ^\n```"
13+
},
14+
{
15+
"content": "```\nInput: s = \" -042\"\nOutput: -42\n```\n**Explanation:**\n```\nStep 1: \" -042\" (leading whitespace is read and ignored)\n ^\nStep 2: \" -042\" ('-' is read, so the result should be negative)\n ^\nStep 3: \" -042\" (\"042\" is read in, leading zeros ignored in the result)\n ^\n```"
16+
},
17+
{
18+
"content": "```\nInput: s = \"1337c0d3\"\nOutput: 1337\n```\n**Explanation:**\n```\nStep 1: \"1337c0d3\" (no characters read because there is no leading whitespace)\n ^\nStep 2: \"1337c0d3\" (no characters read because there is neither a '-' nor '+')\n ^\nStep 3: \"1337c0d3\" (\"1337\" is read in; reading stops because the next character is a non-digit)\n ^\n```"
19+
},
20+
{
21+
"content": "```\nInput: s = \"0-1\"\nOutput: 0\n```\n**Explanation:**\n```\nStep 1: \"0-1\" (no characters read because there is no leading whitespace)\n ^\nStep 2: \"0-1\" (no characters read because there is neither a '-' nor '+')\n ^\nStep 3: \"0-1\" (\"0\" is read in; reading stops because the next character is a non-digit)\n ^\n```"
22+
},
23+
{
24+
"content": "```\nInput: s = \"words and 987\"\nOutput: 0\n```\n**Explanation:** Reading stops at the first non-digit character 'w'."
25+
}
26+
],
27+
"readme_constraints": "- `0 <= s.length <= 200`\n- `s` consists of English letters (lower-case and upper-case), digits (0-9), ` `, `+`, `-`, and `.`.",
28+
"readme_additional": "",
29+
"solution_imports": "",
30+
"solution_methods": [
31+
{ "name": "my_atoi", "parameters": "s: str", "return_type": "int", "dummy_return": "0" }
32+
],
33+
"test_imports": "import pytest\nfrom leetcode_py.test_utils import logged_test\nfrom .solution import Solution",
34+
"test_class_name": "StringToIntegerAtoi",
35+
"test_helper_methods": [
36+
{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }
37+
],
38+
"test_methods": [
39+
{
40+
"name": "test_my_atoi",
41+
"parametrize": "s, expected",
42+
"parametrize_typed": "s: str, expected: int",
43+
"test_cases": "[('42', 42), (' -042', -42), ('1337c0d3', 1337), ('0-1', 0), ('words and 987', 0), ('', 0), (' ', 0), ('+1', 1), ('-1', -1), ('2147483647', 2147483647), ('-2147483648', -2147483648), ('2147483648', 2147483647), ('-2147483649', -2147483648)]",
44+
"body": "result = self.solution.my_atoi(s)\nassert result == expected"
45+
}
46+
],
47+
"playground_imports": "from solution import Solution",
48+
"playground_test_case": "# Example test case\ns = '42'\nexpected = 42",
49+
"playground_execution": "result = Solution().my_atoi(s)\nresult",
50+
"playground_assertion": "assert result == expected"
51+
}

.templates/leetcode/{{cookiecutter.problem_name}}/solution.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ class {{cookiecutter.solution_class_name}}:
44
{%- for _, methods in cookiecutter._solution_methods | dictsort %}
55
{%- for method in methods %}
66
# Time: O(?)
7-
# Space: O(?)
7+
# Space: O(?){# TODO: add decorator // optional self. #}
88
def {{method.name}}(self, {{method.parameters}}) -> {{method.return_type}}:
9-
# TODO: Implement {{method.name}}
9+
# TODO: Implement {{method.name}}{# TODO: add body #}
1010
return {{method.dummy_return}}
1111

1212
{%- endfor %}

.templates/leetcode/{{cookiecutter.problem_name}}/tests.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
class Test{{cookiecutter.test_class_name}}:
55
{%- for _, helper_methods in cookiecutter._test_helper_methods | dictsort %}
6-
{%- for method in helper_methods %}
6+
{%- for method in helper_methods %}{# TODO: add decorator // optional self. #}
77
def {{method.name}}(self{% if method.parameters %}, {{method.parameters}}{% endif %}):
88
{{method.body | indent(8, first=False)}}
99

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

leetcode/add_binary/README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Add Binary
2+
3+
**Difficulty:** Easy
4+
**Topics:** Math, String, Bit Manipulation, Simulation
5+
**Tags:** grind-75
6+
7+
**LeetCode:** [Problem 67](https://leetcode.com/problems/add-binary/description/)
8+
9+
## Problem Description
10+
11+
Given two binary strings `a` and `b`, return _their sum as a binary string_.
12+
13+
## Examples
14+
15+
### Example 1:
16+
17+
```
18+
Input: a = "11", b = "1"
19+
Output: "100"
20+
```
21+
22+
### Example 2:
23+
24+
```
25+
Input: a = "1010", b = "1011"
26+
Output: "10101"
27+
```
28+
29+
## Constraints
30+
31+
- `1 <= a.length, b.length <= 10^4`
32+
- `a` and `b` consist only of `'0'` or `'1'` characters.
33+
- Each string does not contain leading zeros except for the zero itself.

0 commit comments

Comments
 (0)