Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions .amazonq/rules/problem-creation.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,17 @@ When user requests a problem by **number** or **name/slug**, the assistant will:

1. **Scrape** problem data using `.templates/leetcode/scrape.py`
2. **Transform** data into proper JSON template format
3. **Create** JSON file in `.templates/leetcode/json/{problem_name}.json`
4. **Update** Makefile with `PROBLEM ?= {problem_name}`
5. **Generate** problem structure using `make p-gen`
6. **Verify** with `make lint` - fix template issues in JSON if possible, or manually fix generated files if template limitations
7. **Iterate** if JSON fixes: re-run `make p-gen PROBLEM={problem_name} FORCE=1` and `make lint` until passes to ensure reproducibility
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
- Check scraped data for image URLs in the `raw_content` field
- Look for patterns: `https://assets.leetcode.com/uploads/...` or `<img alt="" src="..." />`
- Common patterns: `kthtree1.jpg`, `kthtree2.jpg`, `clone_graph.png`, `container.jpg`
- Images provide crucial visual context, especially for tree and graph problems
- Always verify images are included in `readme_examples` and accessible
4. **Create** JSON file in `.templates/leetcode/json/{problem_name}.json`
5. **Update** Makefile with `PROBLEM ?= {problem_name}`
6. **Generate** problem structure using `make p-gen`
7. **Verify** with `make lint` - fix template issues in JSON if possible, or manually fix generated files if template limitations
8. **Iterate** if JSON fixes: re-run `make p-gen PROBLEM={problem_name} FORCE=1` and `make lint` until passes to ensure reproducibility

## Scraping Commands

Expand Down Expand Up @@ -46,7 +52,7 @@ Required fields for `.templates/leetcode/json/{problem_name}.json`:
"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`.",
"readme_examples": [
{
"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]."
"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]."
}
],
"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.",
Expand Down
47 changes: 47 additions & 0 deletions .templates/leetcode/json/binary_search.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"problem_name": "binary_search",
"solution_class_name": "Solution",
"problem_number": "704",
"problem_title": "Binary Search",
"difficulty": "Easy",
"topics": "Array, Binary Search",
"tags": ["grind-75"],
"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.",
"readme_examples": [
{
"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"
},
{
"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"
}
],
"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.",
"readme_additional": "",
"solution_imports": "",
"solution_methods": [
{
"name": "search",
"parameters": "nums: list[int], target: int",
"return_type": "int",
"dummy_return": "-1"
}
],
"test_imports": "import pytest\nfrom leetcode_py.test_utils import logged_test\nfrom .solution import Solution",
"test_class_name": "BinarySearch",
"test_helper_methods": [
{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }
],
"test_methods": [
{
"name": "test_search",
"parametrize": "nums, target, expected",
"parametrize_typed": "nums: list[int], target: int, expected: int",
"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)]",
"body": "result = self.solution.search(nums, target)\nassert result == expected"
}
],
"playground_imports": "from solution import Solution",
"playground_test_case": "# Example test case\nnums = [-1, 0, 3, 5, 9, 12]\ntarget = 9\nexpected = 4",
"playground_execution": "result = Solution().search(nums, target)\nresult",
"playground_assertion": "assert result == expected"
}
47 changes: 47 additions & 0 deletions .templates/leetcode/json/k_closest_points_to_origin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"problem_name": "k_closest_points_to_origin",
"solution_class_name": "Solution",
"problem_number": "973",
"problem_title": "K Closest Points to Origin",
"difficulty": "Medium",
"topics": "Array, Math, Divide and Conquer, Geometry, Sorting, Heap (Priority Queue), Quickselect",
"tags": ["grind-75"],
"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).",
"readme_examples": [
{
"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]]."
},
{
"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."
}
],
"readme_constraints": "- `1 <= k <= points.length <= 10^4`\n- `-10^4 <= xi, yi <= 10^4`",
"readme_additional": "",
"solution_imports": "",
"solution_methods": [
{
"name": "k_closest",
"parameters": "points: list[list[int]], k: int",
"return_type": "list[list[int]]",
"dummy_return": "[]"
}
],
"test_imports": "import pytest\nfrom leetcode_py.test_utils import logged_test\nfrom .solution import Solution",
"test_class_name": "KClosestPointsToOrigin",
"test_helper_methods": [
{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }
],
"test_methods": [
{
"name": "test_k_closest",
"parametrize": "points, k, expected",
"parametrize_typed": "points: list[list[int]], k: int, expected: list[list[int]]",
"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]])]",
"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"
}
],
"playground_imports": "from solution import Solution",
"playground_test_case": "# Example test case\npoints = [[1, 3], [-2, 2]]\nk = 1\nexpected = [[-2, 2]]",
"playground_execution": "result = Solution().k_closest(points, k)\nresult",
"playground_assertion": "assert sorted(result) == sorted(expected)"
}
47 changes: 47 additions & 0 deletions .templates/leetcode/json/kth_smallest_element_in_a_bst.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"problem_name": "kth_smallest_element_in_a_bst",
"solution_class_name": "Solution",
"problem_number": "230",
"problem_title": "Kth Smallest Element in a BST",
"difficulty": "Medium",
"topics": "Tree, Depth-First Search, Binary Search Tree, Binary Tree",
"tags": ["grind-75"],
"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.",
"readme_examples": [
{
"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```"
},
{
"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```"
}
],
"readme_constraints": "- The number of nodes in the tree is `n`.\n- `1 <= k <= n <= 10^4`\n- `0 <= Node.val <= 10^4`",
"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?",
"solution_imports": "from leetcode_py import TreeNode",
"solution_methods": [
{
"name": "kth_smallest",
"parameters": "root: TreeNode | None, k: int",
"return_type": "int",
"dummy_return": "0"
}
],
"test_imports": "import pytest\nfrom leetcode_py.test_utils import logged_test\nfrom leetcode_py import TreeNode\nfrom .solution import Solution",
"test_class_name": "KthSmallestElementInABst",
"test_helper_methods": [
{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }
],
"test_methods": [
{
"name": "test_kth_smallest",
"parametrize": "root_list, k, expected",
"parametrize_typed": "root_list: list[int | None], k: int, expected: int",
"test_cases": "[([3, 1, 4, None, 2], 1, 1), ([5, 3, 6, 2, 4, None, None, 1], 3, 3), ([1], 1, 1)]",
"body": "root = TreeNode.from_list(root_list)\nresult = self.solution.kth_smallest(root, k)\nassert result == expected"
}
],
"playground_imports": "from solution import Solution\nfrom leetcode_py import TreeNode",
"playground_test_case": "# Example test case\nroot_list = [3, 1, 4, None, 2]\nk = 1\nexpected = 1",
"playground_execution": "root = TreeNode.from_list(root_list)\nresult = Solution().kth_smallest(root, k)\nresult",
"playground_assertion": "assert result == expected"
}
55 changes: 55 additions & 0 deletions .templates/leetcode/json/linked_list_cycle.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"problem_name": "linked_list_cycle",
"solution_class_name": "Solution",
"problem_number": "141",
"problem_title": "Linked List Cycle",
"difficulty": "Easy",
"topics": "Hash Table, Linked List, Two Pointers",
"tags": ["grind-75"],
"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`.",
"readme_examples": [
{
"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)."
},
{
"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."
},
{
"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."
}
],
"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.",
"readme_additional": "**Follow up:** Can you solve it using `O(1)` (i.e. constant) memory?",
"solution_imports": "from leetcode_py import ListNode",
"solution_methods": [
{
"name": "has_cycle",
"parameters": "head: ListNode[int] | None",
"return_type": "bool",
"dummy_return": "False"
}
],
"test_imports": "import pytest\nfrom leetcode_py import ListNode\nfrom leetcode_py.test_utils import logged_test\nfrom .solution import Solution",
"test_class_name": "LinkedListCycle",
"test_helper_methods": [
{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" },
{
"name": "create_cycle_list",
"parameters": "values: list[int], pos: int",
"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"
}
],
"test_methods": [
{
"name": "test_has_cycle",
"parametrize": "values, pos, expected",
"parametrize_typed": "values: list[int], pos: int, expected: bool",
"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)]",
"body": "head = self.create_cycle_list(values, pos)\nresult = self.solution.has_cycle(head)\nassert result == expected"
}
],
"playground_imports": "from solution import Solution",
"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",
"playground_execution": "head = TestLinkedListCycle().create_cycle_list(values, pos)\nresult = Solution().has_cycle(head)\nresult",
"playground_assertion": "assert result == expected"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"problem_name": "lowest_common_ancestor_of_a_binary_search_tree",
"solution_class_name": "Solution",
"problem_number": "235",
"problem_title": "Lowest Common Ancestor of a Binary Search Tree",
"difficulty": "Medium",
"topics": "Tree, Depth-First Search, Binary Search Tree, Binary Tree",
"tags": ["grind-75"],
"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**).\"",
"readme_examples": [
{
"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."
},
{
"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."
},
{ "content": "```\nInput: root = [2,1], p = 2, q = 1\nOutput: 2\n```" }
],
"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.",
"readme_additional": "",
"solution_imports": "from leetcode_py import TreeNode",
"solution_methods": [
{
"name": "lowest_common_ancestor",
"parameters": "root: TreeNode[int] | None, p: TreeNode[int], q: TreeNode[int]",
"return_type": "TreeNode[int] | None",
"dummy_return": "None"
}
],
"test_imports": "import pytest\nfrom leetcode_py import TreeNode\nfrom leetcode_py.test_utils import logged_test\nfrom .solution import Solution",
"test_class_name": "LowestCommonAncestorOfABinarySearchTree",
"test_helper_methods": [
{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" },
{
"name": "_find_node",
"parameters": "root: TreeNode[int], val: int",
"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)"
}
],
"test_methods": [
{
"name": "test_lowest_common_ancestor",
"parametrize": "root_list, p_val, q_val, expected_val",
"parametrize_typed": "root_list: list[int | None], p_val: int, q_val: int, expected_val: int",
"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)]",
"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"
}
],
"playground_imports": "from leetcode_py import TreeNode\nfrom solution import Solution",
"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",
"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",
"playground_assertion": "assert result and result.val == expected_val"
}
Loading
Loading