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
227 changes: 218 additions & 9 deletions .amazonq/rules/problem-creation.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,224 @@ Required fields for `leetcode_py/cli/resources/leetcode/json/problems/{problem_n
- `playground_assertion`: Use single quotes for string literals
- Double quotes in JSON + cookiecutter + Jupyter notebook = triple escaping issues

**Reference the complete template example:**

See `leetcode_py/cli/resources/leetcode/examples/example.json5` for a comprehensive template with:

- All field definitions and variations
- Comments explaining each field
- Examples for different problem types (basic, tree, linked list, design, trie)
- Proper JSON escaping rules for playground fields
- Multiple solution class patterns
**IMPORTANT: Create actual JSON files, not JSON5**

The template below uses JSON5 format with comments for documentation purposes only. When creating the actual `.json` file, you must:

1. **Remove all comments** (lines starting with `//`)
2. **Use proper JSON syntax** with quoted property names
3. **Save as `.json` file** (not `.json5`)

**Template with comments (JSON5 format for reference only):**

````json5
{
// ============================================================================
// COMPREHENSIVE LEETCODE TEMPLATE EXAMPLE
// ============================================================================
// This example demonstrates ALL template patterns using valid_anagram as base
// with comprehensive comments showing variations for different problem types.
//
// REFERENCE PROBLEMS (see .templates/leetcode/json/ for complete examples):
// 1. valid_anagram - Basic: string parameters, boolean return
// 2. invert_binary_tree - Tree: TreeNode imports/parameters
// 3. merge_two_sorted_lists - LinkedList: ListNode imports/parameters
// 4. lru_cache - Design: custom class, multiple methods, operations
// 5. implement_trie_prefix_tree - Trie: DictTree inheritance
// ============================================================================

// === PROBLEM IDENTIFICATION ===
problem_name: "valid_anagram", // snake_case: used for directory/file names
solution_class_name: "Solution", // "Solution" for basic problems
// "LRUCache" for design problems
// "Trie(DictTree[str])" for inheritance
problem_number: "242", // LeetCode problem number as string
problem_title: "Valid Anagram", // Exact title from LeetCode
difficulty: "Easy", // Easy, Medium, Hard
topics: "Hash Table, String, Sorting", // Comma-separated topics from LeetCode
_tags: { list: ["grind-75"] }, // Optional: common problem set tags
// Use _tags wrapper for cookiecutter lists

// === README CONTENT ===
// IMPORTANT: Preserve rich HTML content from LeetCode including:
// - Code snippets with backticks: `code`
// - Bold text: **bold** or <strong>bold</strong>
// - Italic text: *italic* or <em>italic</em>
// - Images: ![Example](https://assets.leetcode.com/uploads/...)
// - HTML formatting: <p>, <br>, <ul>, <li>, etc.
// - Mathematical expressions and special characters
readme_description: "Given two strings `s` and `t`, return `true` if `t` is an anagram of `s`, and `false` otherwise.",

_readme_examples: {
// Use _readme_examples wrapper for cookiecutter lists
list: [
{ content: '```\nInput: s = "anagram", t = "nagaram"\nOutput: true\n```' },
{ content: '```\nInput: s = "rat", t = "car"\nOutput: false\n```' },
// For tree problems: Include images
// { "content": "![Example 1](https://assets.leetcode.com/uploads/2021/02/19/tree1.jpg)\n\n```\nInput: root = [4,2,7,1,3,6,9]\nOutput: [4,7,2,9,6,3,1]\n```" }
],
},

readme_constraints: "- 1 <= s.length, t.length <= 5 * 10^4\n- s and t consist of lowercase English letters.",
readme_additional: "**Follow up:** What if the inputs contain Unicode characters? How would you adapt your solution to such a case?",

// === HELPER FUNCTIONS ===
// New template system uses helper functions for cleaner test organization
helpers_imports: "", // Empty for basic problems
// "from leetcode_py import TreeNode" for tree problems
// "from leetcode_py import ListNode" for linked list problems
helpers_content: "", // Additional helper content if needed
helpers_run_name: "is_anagram", // Function name matching main method
helpers_run_signature: "(solution_class: type, s: str, t: str)",
// For tree: "(solution_class: type, root_list: list[int | None])"
// For linked list: "(solution_class: type, list1_vals: list[int], list2_vals: list[int])"
// For design: "(solution_class: type, operations: list[str], inputs: list[list[int]])"
helpers_run_body: " implementation = solution_class()\n return implementation.is_anagram(s, t)",
// For tree: " root = TreeNode[int].from_list(root_list)\n implementation = solution_class()\n return implementation.invert_tree(root)"
// For design: " cache = None\n results: list[int | None] = []\n # ... operation loop ...\n return results, cache"
helpers_assert_name: "is_anagram", // Function name matching main method
helpers_assert_signature: "(result: bool, expected: bool) -> bool",
// For tree: "(result: TreeNode[int] | None, expected_list: list[int | None]) -> bool"
// For design: "(result: list[int | None], expected: list[int | None]) -> bool"
helpers_assert_body: " assert result == expected\n return True",
// For tree: " expected = TreeNode[int].from_list(expected_list)\n assert result == expected\n return True"

// === SOLUTION TEMPLATE ===
solution_imports: "", // Empty for basic problems
// "from leetcode_py import TreeNode" for tree problems
// "from leetcode_py import ListNode" for linked list problems
// "from leetcode_py.data_structures import DictTree, RecursiveDict" for trie problems
solution_contents: "", // Additional content before class definition
solution_class_content: "", // Content inside class definition (usually empty)

// === TEST CONFIGURATION ===
test_imports: "import pytest\nfrom leetcode_py import logged_test\nfrom .helpers import assert_is_anagram, run_is_anagram\nfrom .solution import Solution",
// For design: "from .solution import LRUCache" instead of Solution
test_content: "", // Additional test content
test_class_name: "ValidAnagram", // PascalCase: TestClassName for pytest class
test_class_content: " def setup_method(self):\n self.solution = Solution()",
// Empty for design problems: ""

// === SOLUTION METHODS ===
_solution_methods: {
// Use _solution_methods wrapper for cookiecutter lists
list: [
{
name: "is_anagram", // snake_case method name
signature: "(self, s: str, t: str) -> bool", // Full method signature with type hints
// For tree: "(self, root: TreeNode[int] | None) -> TreeNode[int] | None"
// For linked list: "(self, list1: ListNode[int] | None, list2: ListNode[int] | None) -> ListNode[int] | None"
body: " # TODO: Implement is_anagram\n return False",
// For design problems with __init__:
// { "name": "__init__", "signature": "(self, capacity: int) -> None", "body": " # TODO: Initialize\n pass" }
},
],
},

// === TEST HELPER METHODS ===
_test_helper_methods: {
// Use _test_helper_methods wrapper for cookiecutter lists
list: [
{ name: "setup_method", parameters: "", body: "self.solution = Solution()" },
// Empty list for design problems: []
],
},

// === TEST METHODS ===
_test_methods: {
// Use _test_methods wrapper for cookiecutter lists
list: [
{
name: "test_is_anagram", // test_{method_name}
signature: "(self, s: str, t: str, expected: bool)", // Method signature with type hints
parametrize: "s, t, expected", // pytest parametrize parameters
// For tree: "root_list, expected_list"
// For design: "operations, inputs, expected"
test_cases: "[('anagram', 'nagaram', True), ('rat', 'car', False), ('listen', 'silent', True), ('hello', 'bello', False), ('', '', True), ('a', 'a', True), ('a', 'b', False), ('ab', 'ba', True), ('abc', 'bca', True), ('abc', 'def', False), ('aab', 'abb', False), ('aabbcc', 'abcabc', True), ('abcd', 'abcde', False), ('race', 'care', True), ('elbow', 'below', True), ('study', 'dusty', True), ('night', 'thing', True), ('stressed', 'desserts', True)]",
// For tree: "[([4, 2, 7, 1, 3, 6, 9], [4, 7, 2, 9, 6, 3, 1]), ([2, 1, 3], [2, 3, 1]), ([], [])]"
// For design: "[(['LRUCache', 'put', 'get'], [[2], [1, 1], [1]], [None, None, 1])]"
body: " result = run_is_anagram(Solution, s, t)\n assert_is_anagram(result, expected)",
// For tree: " result = run_invert_tree(Solution, root_list)\n assert_invert_tree(result, expected_list)"
// For design: " result, _ = run_lru_cache(LRUCache, operations, inputs)\n assert_lru_cache(result, expected)"
},
],
},

// === PLAYGROUND NOTEBOOK ===
// CRITICAL: Use single quotes for Python strings to avoid JSON escaping issues with Jupyter notebooks
// Double quotes in JSON + cookiecutter + Jupyter notebook = triple escaping issues
// ALWAYS use single quotes: s = 'hello', not s = "hello"
playground_imports: "from helpers import run_is_anagram, assert_is_anagram\nfrom solution import Solution",
// For tree: "from helpers import run_invert_tree, assert_invert_tree\nfrom solution import Solution\nfrom leetcode_py import TreeNode"
// For design: "from helpers import run_lru_cache, assert_lru_cache\nfrom solution import LRUCache"
playground_setup: "# Example test case\ns = 'anagram'\nt = 'nagaram'\nexpected = True",
// For tree: "# Example test case\nroot_list: list[int | None] = [4, 2, 7, 1, 3, 6, 9]\nexpected_list: list[int | None] = [4, 7, 2, 9, 6, 3, 1]"
// For design: "# Example test case\noperations = ['LRUCache', 'put', 'get']\ninputs = [[2], [1, 1], [1]]\nexpected = [None, None, 1]"
playground_run: "result = run_is_anagram(Solution, s, t)\nresult",
// For tree: "result = run_invert_tree(Solution, root_list)\nresult"
// For design: "result, cache = run_lru_cache(LRUCache, operations, inputs)\nprint(result)\ncache"
playground_assert: "assert_is_anagram(result, expected)",
// For tree: "assert_invert_tree(result, expected_list)"
// For design: "assert_lru_cache(result, expected)"

// ============================================================================
// PROBLEM TYPE VARIATIONS SUMMARY:
// ============================================================================
//
// BASIC PROBLEMS (valid_anagram):
// - solution_class_name: "Solution"
// - solution_imports: ""
// - Simple method signatures: "(self, s: str, t: str) -> bool"
// - Basic test cases: string/number parameters
// - Playground: single quotes for strings
//
// TREE PROBLEMS (invert_binary_tree):
// - solution_class_name: "Solution"
// - solution_imports: "from leetcode_py import TreeNode"
// - Tree method signatures: "(self, root: TreeNode[int] | None) -> TreeNode[int] | None"
// - Helper functions use TreeNode.from_list()
// - Test cases: list representations of trees
// - Playground: TreeNode imports and list conversions
//
// LINKED LIST PROBLEMS (merge_two_sorted_lists):
// - solution_class_name: "Solution"
// - solution_imports: "from leetcode_py import ListNode"
// - List method signatures: "(self, list1: ListNode[int] | None, list2: ListNode[int] | None) -> ListNode[int] | None"
// - Helper functions use ListNode.from_list()
// - Test cases: list representations of linked lists
// - Playground: ListNode imports and list conversions
//
// DESIGN PROBLEMS (lru_cache):
// - solution_class_name: "LRUCache" (custom class name)
// - Multiple methods including __init__
// - Operations-based testing: operations, inputs, expected arrays
// - Complex test body with operation loops
// - Helper functions return (results, instance) for debugging
// - Playground: print results, return instance
// - test_class_content: "" (no setup_method)
//
// INHERITANCE PROBLEMS (implement_trie_prefix_tree):
// - solution_class_name: "Trie(DictTree[str])" (with inheritance)
// - solution_imports: "from leetcode_py.data_structures import DictTree, RecursiveDict"
// - Custom class with inheritance from DictTree
// - Operations-based testing like design problems
// - Helper functions return (results, instance) for debugging
//
// MULTIPLE SOLUTIONS (invert_binary_tree, lru_cache):
// - Add parametrize for solution classes in test files:
// @pytest.mark.parametrize("solution_class", [Solution, SolutionDFS, SolutionBFS])
// @pytest.mark.parametrize("solution_class", [LRUCache, LRUCacheWithDoublyList])
// - Update test method signature to include solution_class parameter
// - Import all solution classes in test file
// ============================================================================
}
````

**IMPORTANT: When creating the actual .json file, convert the above JSON5 to valid JSON by:**

1. **Remove all comments** (lines starting with `//`)
2. **Keep all quoted property names** (already done above)
3. **Save as `.json` file** (not `.json5`)

## Naming Conventions

Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
PYTHON_VERSION = 3.13
PROBLEM ?= design_add_and_search_words_data_structure
PROBLEM ?= valid_sudoku
FORCE ?= 0
COMMA := ,

Expand Down Expand Up @@ -100,4 +100,4 @@ gen-all-problems:
@echo "Deleting existing problems..."
@rm -rf leetcode/*/
@echo "Generating all problems..."
poetry run lcpy gen -t grind-75 -o leetcode $(if $(filter 1,$(FORCE)),--force)
poetry run lcpy gen --all -o leetcode $(if $(filter 1,$(FORCE)),--force)
59 changes: 59 additions & 0 deletions leetcode/pacific_atlantic_water_flow/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Pacific Atlantic Water Flow

**Difficulty:** Medium
**Topics:** Array, Depth-First Search, Breadth-First Search, Matrix
**Tags:** grind

**LeetCode:** [Problem 417](https://leetcode.com/problems/pacific-atlantic-water-flow/description/)

## Problem Description

There is an `m x n` rectangular island that borders both the **Pacific Ocean** and **Atlantic Ocean**. The **Pacific Ocean** touches the island's left and top edges, and the **Atlantic Ocean** touches the island's right and bottom edges.

The island is partitioned into a grid of square cells. You are given an `m x n` integer matrix `heights` where `heights[r][c]` represents the **height above sea level** of the cell at coordinate `(r, c)`.

The island receives a lot of rain, and the rain water can flow to neighboring cells directly north, south, east, and west if the neighboring cell's height is **less than or equal to** the current cell's height. Water can flow from any cell adjacent to an ocean into the ocean.

Return _a **2D list** of grid coordinates_ `result` _where_ `result[i] = [ri, ci]` _denotes that rain water can flow from cell_ `(ri, ci)` _to **both** the Pacific and Atlantic oceans_.

## Examples

### Example 1:

![Example 1](https://assets.leetcode.com/uploads/2021/06/08/waterflow-grid.jpg)

```
Input: heights = [[1,2,2,3,5],[3,2,3,4,4],[2,4,5,3,1],[6,7,1,4,5],[5,1,1,2,4]]
Output: [[0,4],[1,3],[1,4],[2,2],[3,0],[3,1],[4,0]]
Explanation: The following cells can flow to the Pacific and Atlantic oceans, as shown below:
[0,4]: [0,4] -> Pacific Ocean
[0,4] -> Atlantic Ocean
[1,3]: [1,3] -> [0,3] -> Pacific Ocean
[1,3] -> [1,4] -> Atlantic Ocean
[1,4]: [1,4] -> [1,3] -> [0,3] -> Pacific Ocean
[1,4] -> Atlantic Ocean
[2,2]: [2,2] -> [1,2] -> [0,2] -> Pacific Ocean
[2,2] -> [2,3] -> [2,4] -> Atlantic Ocean
[3,0]: [3,0] -> Pacific Ocean
[3,0] -> [4,0] -> Atlantic Ocean
[3,1]: [3,1] -> [3,0] -> Pacific Ocean
[3,1] -> [4,1] -> Atlantic Ocean
[4,0]: [4,0] -> Pacific Ocean
[4,0] -> Atlantic Ocean
Note that there are other possible paths for these cells to flow to the Pacific and Atlantic oceans.
```

### Example 2:

```
Input: heights = [[1]]
Output: [[0,0]]
Explanation: The water can flow from the only cell to the Pacific and Atlantic oceans.
```

## Constraints

- `m == heights.length`
- `n == heights[r].length`
- `1 <= m, n <= 200`
- `0 <= heights[r][c] <= 10^5`
Empty file.
8 changes: 8 additions & 0 deletions leetcode/pacific_atlantic_water_flow/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
def run_pacific_atlantic(solution_class: type, heights: list[list[int]]):
implementation = solution_class()
return implementation.pacific_atlantic(heights)


def assert_pacific_atlantic(result: list[list[int]], expected: list[list[int]]) -> bool:
assert sorted(result) == sorted(expected)
return True
29 changes: 29 additions & 0 deletions leetcode/pacific_atlantic_water_flow/playground.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# ---
# jupyter:
# jupytext:
# text_representation:
# extension: .py
# format_name: percent
# format_version: '1.3'
# jupytext_version: 1.17.3
# kernelspec:
# display_name: leetcode-py-py3.13
# language: python
# name: python3
# ---

# %%
from helpers import assert_pacific_atlantic, run_pacific_atlantic
from solution import Solution

# %%
# Example test case
heights = [[1, 2, 2, 3, 5], [3, 2, 3, 4, 4], [2, 4, 5, 3, 1], [6, 7, 1, 4, 5], [5, 1, 1, 2, 4]]
expected = [[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]]

# %%
result = run_pacific_atlantic(Solution, heights)
result

# %%
assert_pacific_atlantic(result, expected)
37 changes: 37 additions & 0 deletions leetcode/pacific_atlantic_water_flow/solution.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
class Solution:

# Time: O(m * n)
# Space: O(m * n)
def pacific_atlantic(self, heights: list[list[int]]) -> list[list[int]]:
if not heights or not heights[0]:
return []

m, n = len(heights), len(heights[0])
pacific: set[tuple[int, int]] = set()
atlantic: set[tuple[int, int]] = set()

def dfs(r: int, c: int, visited: set) -> None:
visited.add((r, c))
for dr, dc in [(0, 1), (0, -1), (1, 0), (-1, 0)]:
nr, nc = r + dr, c + dc
if (
0 <= nr < m
and 0 <= nc < n
and (nr, nc) not in visited
and heights[nr][nc] >= heights[r][c]
):
dfs(nr, nc, visited)

# DFS from Pacific borders (top and left)
for i in range(m):
dfs(i, 0, pacific)
for j in range(n):
dfs(0, j, pacific)

# DFS from Atlantic borders (bottom and right)
for i in range(m):
dfs(i, n - 1, atlantic)
for j in range(n):
dfs(m - 1, j, atlantic)

return [[r, c] for r, c in pacific & atlantic]
Loading