Skip to content

Commit 3e18fdb

Browse files
authored
feat: add more problems (#19)
1 parent 297a91c commit 3e18fdb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+2368
-16
lines changed

.amazonq/rules/problem-creation.md

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,17 @@ When user requests a problem by **number** or **name/slug**, the assistant will:
66

77
1. **Scrape** problem data using `.templates/leetcode/scrape.py`
88
2. **Transform** data into proper JSON template format
9-
3. **Create** JSON file in `.templates/leetcode/json/{problem_name}.json`
10-
4. **Update** Makefile with `PROBLEM ?= {problem_name}`
11-
5. **Generate** problem structure using `make p-gen`
12-
6. **Verify** with `make lint` - fix template issues in JSON if possible, or manually fix generated files if template limitations
13-
7. **Iterate** if JSON fixes: re-run `make p-gen PROBLEM={problem_name} FORCE=1` and `make lint` until passes to ensure reproducibility
9+
3. **CRITICAL: Include images** - Extract image URLs from scraped data and add to readme_examples with format: `![Example N](image_url)\n\n` before code blocks
10+
- Check scraped data for image URLs in the `raw_content` field
11+
- Look for patterns: `https://assets.leetcode.com/uploads/...` or `<img alt="" src="..." />`
12+
- Common patterns: `kthtree1.jpg`, `kthtree2.jpg`, `clone_graph.png`, `container.jpg`
13+
- Images provide crucial visual context, especially for tree and graph problems
14+
- Always verify images are included in `readme_examples` and accessible
15+
4. **Create** JSON file in `.templates/leetcode/json/{problem_name}.json`
16+
5. **Update** Makefile with `PROBLEM ?= {problem_name}`
17+
6. **Generate** problem structure using `make p-gen`
18+
7. **Verify** with `make lint` - fix template issues in JSON if possible, or manually fix generated files if template limitations
19+
8. **Iterate** if JSON fixes: re-run `make p-gen PROBLEM={problem_name} FORCE=1` and `make lint` until passes to ensure reproducibility
1420

1521
## Scraping Commands
1622

@@ -46,7 +52,7 @@ Required fields for `.templates/leetcode/json/{problem_name}.json`:
4652
"readme_description": "Given an array of integers `nums` and an integer `target`, return indices of the two numbers such that they add up to `target`.",
4753
"readme_examples": [
4854
{
49-
"content": "```\nInput: nums = [2,7,11,15], target = 9\nOutput: [0,1]\n```\n**Explanation:** Because nums[0] + nums[1] == 9, we return [0, 1]."
55+
"content": "![Example 1](https://example.com/image1.jpg)\n\n```\nInput: nums = [2,7,11,15], target = 9\nOutput: [0,1]\n```\n**Explanation:** Because nums[0] + nums[1] == 9, we return [0, 1]."
5056
}
5157
],
5258
"readme_constraints": "- 2 <= nums.length <= 10^4\n- -10^9 <= nums[i] <= 10^9\n- -10^9 <= target <= 10^9\n- Only one valid answer exists.",
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"problem_name": "binary_search",
3+
"solution_class_name": "Solution",
4+
"problem_number": "704",
5+
"problem_title": "Binary Search",
6+
"difficulty": "Easy",
7+
"topics": "Array, Binary Search",
8+
"tags": ["grind-75"],
9+
"readme_description": "Given an array of integers `nums` which is sorted in ascending order, and an integer `target`, write a function to search `target` in `nums`. If `target` exists, then return its index. Otherwise, return `-1`.\n\nYou must write an algorithm with `O(log n)` runtime complexity.",
10+
"readme_examples": [
11+
{
12+
"content": "```\nInput: nums = [-1,0,3,5,9,12], target = 9\nOutput: 4\n```\n**Explanation:** 9 exists in nums and its index is 4"
13+
},
14+
{
15+
"content": "```\nInput: nums = [-1,0,3,5,9,12], target = 2\nOutput: -1\n```\n**Explanation:** 2 does not exist in nums so return -1"
16+
}
17+
],
18+
"readme_constraints": "- `1 <= nums.length <= 10^4`\n- `-10^4 < nums[i], target < 10^4`\n- All the integers in `nums` are **unique**.\n- `nums` is sorted in ascending order.",
19+
"readme_additional": "",
20+
"solution_imports": "",
21+
"solution_methods": [
22+
{
23+
"name": "search",
24+
"parameters": "nums: list[int], target: int",
25+
"return_type": "int",
26+
"dummy_return": "-1"
27+
}
28+
],
29+
"test_imports": "import pytest\nfrom leetcode_py.test_utils import logged_test\nfrom .solution import Solution",
30+
"test_class_name": "BinarySearch",
31+
"test_helper_methods": [
32+
{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }
33+
],
34+
"test_methods": [
35+
{
36+
"name": "test_search",
37+
"parametrize": "nums, target, expected",
38+
"parametrize_typed": "nums: list[int], target: int, expected: int",
39+
"test_cases": "[([\u22121, 0, 3, 5, 9, 12], 9, 4), ([\u22121, 0, 3, 5, 9, 12], 2, \u22121), ([5], 5, 0), ([5], \u22125, \u22121), ([1, 3, 5, 7, 9], 1, 0), ([1, 3, 5, 7, 9], 9, 4), ([1, 3, 5, 7, 9], 4, \u22121)]",
40+
"body": "result = self.solution.search(nums, target)\nassert result == expected"
41+
}
42+
],
43+
"playground_imports": "from solution import Solution",
44+
"playground_test_case": "# Example test case\nnums = [-1, 0, 3, 5, 9, 12]\ntarget = 9\nexpected = 4",
45+
"playground_execution": "result = Solution().search(nums, target)\nresult",
46+
"playground_assertion": "assert result == expected"
47+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"problem_name": "k_closest_points_to_origin",
3+
"solution_class_name": "Solution",
4+
"problem_number": "973",
5+
"problem_title": "K Closest Points to Origin",
6+
"difficulty": "Medium",
7+
"topics": "Array, Math, Divide and Conquer, Geometry, Sorting, Heap (Priority Queue), Quickselect",
8+
"tags": ["grind-75"],
9+
"readme_description": "Given an array of `points` where `points[i] = [xi, yi]` represents a point on the **X-Y** plane and an integer `k`, return the `k` closest points to the origin `(0, 0)`.\n\nThe distance between two points on the **X-Y** plane is the Euclidean distance (i.e., `\u221a(x1 - x2)\u00b2 + (y1 - y2)\u00b2`).\n\nYou may return the answer in **any order**. The answer is **guaranteed** to be **unique** (except for the order that it is in).",
10+
"readme_examples": [
11+
{
12+
"content": "![Example 1](https://assets.leetcode.com/uploads/2021/03/03/closestplane1.jpg)\n\n```\nInput: points = [[1,3],[-2,2]], k = 1\nOutput: [[-2,2]]\n```\n**Explanation:** The distance between (1, 3) and the origin is sqrt(10). The distance between (-2, 2) and the origin is sqrt(8). Since sqrt(8) < sqrt(10), (-2, 2) is closer to the origin. We only want the closest k = 1 points from the origin, so the answer is just [[-2,2]]."
13+
},
14+
{
15+
"content": "```\nInput: points = [[3,3],[5,-1],[-2,4]], k = 2\nOutput: [[3,3],[-2,4]]\n```\n**Explanation:** The answer [[-2,4],[3,3]] would also be accepted."
16+
}
17+
],
18+
"readme_constraints": "- `1 <= k <= points.length <= 10^4`\n- `-10^4 <= xi, yi <= 10^4`",
19+
"readme_additional": "",
20+
"solution_imports": "",
21+
"solution_methods": [
22+
{
23+
"name": "k_closest",
24+
"parameters": "points: list[list[int]], k: int",
25+
"return_type": "list[list[int]]",
26+
"dummy_return": "[]"
27+
}
28+
],
29+
"test_imports": "import pytest\nfrom leetcode_py.test_utils import logged_test\nfrom .solution import Solution",
30+
"test_class_name": "KClosestPointsToOrigin",
31+
"test_helper_methods": [
32+
{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }
33+
],
34+
"test_methods": [
35+
{
36+
"name": "test_k_closest",
37+
"parametrize": "points, k, expected",
38+
"parametrize_typed": "points: list[list[int]], k: int, expected: list[list[int]]",
39+
"test_cases": "[([[1, 3], [-2, 2]], 1, [[-2, 2]]), ([[3, 3], [5, -1], [-2, 4]], 2, [[3, 3], [-2, 4]]), ([[0, 1], [1, 0]], 2, [[0, 1], [1, 0]]), ([[1, 1], [1, 1], [1, 1]], 2, [[1, 1], [1, 1]])]",
40+
"body": "result = self.solution.k_closest(points, k)\n# Sort both result and expected for comparison since order doesn't matter\nresult_sorted = sorted(result)\nexpected_sorted = sorted(expected)\nassert result_sorted == expected_sorted"
41+
}
42+
],
43+
"playground_imports": "from solution import Solution",
44+
"playground_test_case": "# Example test case\npoints = [[1, 3], [-2, 2]]\nk = 1\nexpected = [[-2, 2]]",
45+
"playground_execution": "result = Solution().k_closest(points, k)\nresult",
46+
"playground_assertion": "assert sorted(result) == sorted(expected)"
47+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"problem_name": "kth_smallest_element_in_a_bst",
3+
"solution_class_name": "Solution",
4+
"problem_number": "230",
5+
"problem_title": "Kth Smallest Element in a BST",
6+
"difficulty": "Medium",
7+
"topics": "Tree, Depth-First Search, Binary Search Tree, Binary Tree",
8+
"tags": ["grind-75"],
9+
"readme_description": "Given the `root` of a binary search tree, and an integer `k`, return the `k`th smallest value (1-indexed) of all the values of the nodes in the tree.",
10+
"readme_examples": [
11+
{
12+
"content": "![Example 1](https://assets.leetcode.com/uploads/2021/01/28/kthtree1.jpg)\n\n```\nInput: root = [3,1,4,null,2], k = 1\nOutput: 1\n```"
13+
},
14+
{
15+
"content": "![Example 2](https://assets.leetcode.com/uploads/2021/01/28/kthtree2.jpg)\n\n```\nInput: root = [5,3,6,2,4,null,null,1], k = 3\nOutput: 3\n```"
16+
}
17+
],
18+
"readme_constraints": "- The number of nodes in the tree is `n`.\n- `1 <= k <= n <= 10^4`\n- `0 <= Node.val <= 10^4`",
19+
"readme_additional": "**Follow up:** If the BST is modified often (i.e., we can do insert and delete operations) and you need to find the kth smallest frequently, how would you optimize?",
20+
"solution_imports": "from leetcode_py import TreeNode",
21+
"solution_methods": [
22+
{
23+
"name": "kth_smallest",
24+
"parameters": "root: TreeNode | None, k: int",
25+
"return_type": "int",
26+
"dummy_return": "0"
27+
}
28+
],
29+
"test_imports": "import pytest\nfrom leetcode_py.test_utils import logged_test\nfrom leetcode_py import TreeNode\nfrom .solution import Solution",
30+
"test_class_name": "KthSmallestElementInABst",
31+
"test_helper_methods": [
32+
{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }
33+
],
34+
"test_methods": [
35+
{
36+
"name": "test_kth_smallest",
37+
"parametrize": "root_list, k, expected",
38+
"parametrize_typed": "root_list: list[int | None], k: int, expected: int",
39+
"test_cases": "[([3, 1, 4, None, 2], 1, 1), ([5, 3, 6, 2, 4, None, None, 1], 3, 3), ([1], 1, 1)]",
40+
"body": "root = TreeNode.from_list(root_list)\nresult = self.solution.kth_smallest(root, k)\nassert result == expected"
41+
}
42+
],
43+
"playground_imports": "from solution import Solution\nfrom leetcode_py import TreeNode",
44+
"playground_test_case": "# Example test case\nroot_list = [3, 1, 4, None, 2]\nk = 1\nexpected = 1",
45+
"playground_execution": "root = TreeNode.from_list(root_list)\nresult = Solution().kth_smallest(root, k)\nresult",
46+
"playground_assertion": "assert result == expected"
47+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
{
2+
"problem_name": "linked_list_cycle",
3+
"solution_class_name": "Solution",
4+
"problem_number": "141",
5+
"problem_title": "Linked List Cycle",
6+
"difficulty": "Easy",
7+
"topics": "Hash Table, Linked List, Two Pointers",
8+
"tags": ["grind-75"],
9+
"readme_description": "Given `head`, the head of a linked list, determine if the linked list has a cycle in it.\n\nThere is a cycle in a linked list if there is some node in the list that can be reached again by continuously following the `next` pointer. Internally, `pos` is used to denote the index of the node that tail's `next` pointer is connected to. **Note that `pos` is not passed as a parameter**.\n\nReturn `true` *if there is a cycle in the linked list*. Otherwise, return `false`.",
10+
"readme_examples": [
11+
{
12+
"content": "![Example 1](https://assets.leetcode.com/uploads/2018/12/07/circularlinkedlist.png)\n\n```\nInput: head = [3,2,0,-4], pos = 1\nOutput: true\n```\n**Explanation:** There is a cycle in the linked list, where the tail connects to the 1st node (0-indexed)."
13+
},
14+
{
15+
"content": "![Example 2](https://assets.leetcode.com/uploads/2018/12/07/circularlinkedlist_test2.png)\n\n```\nInput: head = [1,2], pos = 0\nOutput: true\n```\n**Explanation:** There is a cycle in the linked list, where the tail connects to the 0th node."
16+
},
17+
{
18+
"content": "![Example 3](https://assets.leetcode.com/uploads/2018/12/07/circularlinkedlist_test3.png)\n\n```\nInput: head = [1], pos = -1\nOutput: false\n```\n**Explanation:** There is no cycle in the linked list."
19+
}
20+
],
21+
"readme_constraints": "- The number of the nodes in the list is in the range `[0, 10^4]`.\n- `-10^5 <= Node.val <= 10^5`\n- `pos` is `-1` or a **valid index** in the linked-list.",
22+
"readme_additional": "**Follow up:** Can you solve it using `O(1)` (i.e. constant) memory?",
23+
"solution_imports": "from leetcode_py import ListNode",
24+
"solution_methods": [
25+
{
26+
"name": "has_cycle",
27+
"parameters": "head: ListNode[int] | None",
28+
"return_type": "bool",
29+
"dummy_return": "False"
30+
}
31+
],
32+
"test_imports": "import pytest\nfrom leetcode_py import ListNode\nfrom leetcode_py.test_utils import logged_test\nfrom .solution import Solution",
33+
"test_class_name": "LinkedListCycle",
34+
"test_helper_methods": [
35+
{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" },
36+
{
37+
"name": "create_cycle_list",
38+
"parameters": "values: list[int], pos: int",
39+
"body": "if not values:\n return None\n\nnodes = []\nhead = ListNode(values[0])\nnodes.append(head)\ncurrent = head\n\nfor i in range(1, len(values)):\n current.next = ListNode(values[i])\n current = current.next\n nodes.append(current)\n\nif pos != -1 and pos < len(nodes):\n current.next = nodes[pos]\n\nreturn head"
40+
}
41+
],
42+
"test_methods": [
43+
{
44+
"name": "test_has_cycle",
45+
"parametrize": "values, pos, expected",
46+
"parametrize_typed": "values: list[int], pos: int, expected: bool",
47+
"test_cases": "[([3, 2, 0, -4], 1, True), ([1, 2], 0, True), ([1], -1, False), ([], -1, False), ([1, 2, 3], -1, False), ([1, 2, 3, 4, 5], 0, True), ([1, 2, 3, 4, 5], 2, True), ([1, 2, 3, 4, 5], 4, True), ([1], 0, True), ([1, 2], 1, True), ([1, 2, 3, 4, 5, 6, 7, 8], 3, True), ([1, 2, 3, 4, 5, 6, 7, 8], -1, False), ([1, 2], -1, False), ([5, 10], 0, True), ([5, 10], 1, True), ([0], -1, False), ([-1, -2, -3], 1, True), ([100, 200, 300], 0, True)]",
48+
"body": "head = self.create_cycle_list(values, pos)\nresult = self.solution.has_cycle(head)\nassert result == expected"
49+
}
50+
],
51+
"playground_imports": "from solution import Solution",
52+
"playground_test_case": "import os\nimport sys\nsys.path.append(os.path.join(os.getcwd(), \\\"..\\\"))\nfrom linked_list_cycle.tests import TestLinkedListCycle\n\n# Example test case\nvalues = [3, 2, 0, -4]\npos = 1\nexpected = True",
53+
"playground_execution": "head = TestLinkedListCycle().create_cycle_list(values, pos)\nresult = Solution().has_cycle(head)\nresult",
54+
"playground_assertion": "assert result == expected"
55+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
{
2+
"problem_name": "lowest_common_ancestor_of_a_binary_search_tree",
3+
"solution_class_name": "Solution",
4+
"problem_number": "235",
5+
"problem_title": "Lowest Common Ancestor of a Binary Search Tree",
6+
"difficulty": "Medium",
7+
"topics": "Tree, Depth-First Search, Binary Search Tree, Binary Tree",
8+
"tags": ["grind-75"],
9+
"readme_description": "Given a binary search tree (BST), find the lowest common ancestor (LCA) node of two given nodes in the BST.\n\nAccording to the definition of LCA on Wikipedia: \"The lowest common ancestor is defined between two nodes `p` and `q` as the lowest node in `T` that has both `p` and `q` as descendants (where we allow **a node to be a descendant of itself**).\"",
10+
"readme_examples": [
11+
{
12+
"content": "![Example 1](https://assets.leetcode.com/uploads/2018/12/14/binarysearchtree_improved.png)\n\n```\nInput: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8\nOutput: 6\n```\n**Explanation:** The LCA of nodes 2 and 8 is 6."
13+
},
14+
{
15+
"content": "![Example 2](https://assets.leetcode.com/uploads/2018/12/14/binarysearchtree_improved.png)\n\n```\nInput: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4\nOutput: 2\n```\n**Explanation:** The LCA of nodes 2 and 4 is 2, since a node can be a descendant of itself according to the LCA definition."
16+
},
17+
{ "content": "```\nInput: root = [2,1], p = 2, q = 1\nOutput: 2\n```" }
18+
],
19+
"readme_constraints": "- The number of nodes in the tree is in the range `[2, 10^5]`.\n- `-10^9 <= Node.val <= 10^9`\n- All `Node.val` are **unique**.\n- `p != q`\n- `p` and `q` will exist in the BST.",
20+
"readme_additional": "",
21+
"solution_imports": "from leetcode_py import TreeNode",
22+
"solution_methods": [
23+
{
24+
"name": "lowest_common_ancestor",
25+
"parameters": "root: TreeNode[int] | None, p: TreeNode[int], q: TreeNode[int]",
26+
"return_type": "TreeNode[int] | None",
27+
"dummy_return": "None"
28+
}
29+
],
30+
"test_imports": "import pytest\nfrom leetcode_py import TreeNode\nfrom leetcode_py.test_utils import logged_test\nfrom .solution import Solution",
31+
"test_class_name": "LowestCommonAncestorOfABinarySearchTree",
32+
"test_helper_methods": [
33+
{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" },
34+
{
35+
"name": "_find_node",
36+
"parameters": "root: TreeNode[int], val: int",
37+
"body": "if not root:\n return None\nif root.val == val:\n return root\nleft = self._find_node(root.left, val)\nif left:\n return left\nreturn self._find_node(root.right, val)"
38+
}
39+
],
40+
"test_methods": [
41+
{
42+
"name": "test_lowest_common_ancestor",
43+
"parametrize": "root_list, p_val, q_val, expected_val",
44+
"parametrize_typed": "root_list: list[int | None], p_val: int, q_val: int, expected_val: int",
45+
"test_cases": "[([6, 2, 8, 0, 4, 7, 9, None, None, 3, 5], 2, 8, 6), ([6, 2, 8, 0, 4, 7, 9, None, None, 3, 5], 2, 4, 2), ([2, 1], 2, 1, 2), ([2, 1], 1, 2, 2), ([6, 2, 8, 0, 4, 7, 9], 0, 4, 2), ([6, 2, 8, 0, 4, 7, 9], 7, 9, 8)]",
46+
"body": "root = TreeNode[int].from_list(root_list)\nassert root is not None\np = self._find_node(root, p_val)\nq = self._find_node(root, q_val)\nassert p is not None and q is not None\nresult = self.solution.lowest_common_ancestor(root, p, q)\nassert result is not None\nassert result.val == expected_val"
47+
}
48+
],
49+
"playground_imports": "from leetcode_py import TreeNode\nfrom solution import Solution",
50+
"playground_test_case": "# Example test case\nroot_list = [6, 2, 8, 0, 4, 7, 9, None, None, 3, 5]\np_val = 2\nq_val = 8\nexpected_val = 6",
51+
"playground_execution": "root = TreeNode[int].from_list(root_list)\np = find_node(root, p_val)\nq = find_node(root, q_val)\nresult = Solution().lowest_common_ancestor(root, p, q)\nresult.val if result else None",
52+
"playground_assertion": "assert result and result.val == expected_val"
53+
}

0 commit comments

Comments
 (0)