From 6448c7c446e13207f437af02fcda7f095c6866c3 Mon Sep 17 00:00:00 2001 From: Wisaroot Lertthaweedech Date: Sun, 31 Aug 2025 16:11:29 +0700 Subject: [PATCH 1/2] feat: generalize cookiecutter --- .../02-cookiecutter-template-improvement.md | 266 ++++++++++++++++++ .amazonq/plans/03-regenerate-all-problems.md | 228 +++++++++++++++ .amazonq/plans/cookiecutter-template-plan.md | 2 +- .amazonq/rules/problem-creation.md | 4 +- .templates/leetcode/cookiecutter.json | 72 +++-- .templates/leetcode/examples/README.md | 134 +++++---- .templates/leetcode/examples/basic.json5 | 112 ++++---- .templates/leetcode/examples/design.json5 | 81 ++++++ .../leetcode/examples/linked_list.json5 | 116 ++++---- .templates/leetcode/examples/matrix.json5 | 110 ++++---- .templates/leetcode/examples/string.json5 | 61 ---- .templates/leetcode/examples/tree.json5 | 121 ++++---- .../json/container_with_most_water.json | 62 ++-- .templates/leetcode/json/insert_interval.json | 86 +++--- .../leetcode/json/invert_binary_tree.json | 60 ++-- .templates/leetcode/json/lru_cache.json | 59 ++-- .../leetcode/json/reverse_linked_list_ii.json | 67 +++-- .templates/leetcode/json/spiral_matrix.json | 82 ++---- .../{{cookiecutter.problem_name}}/README.md | 24 +- .../playground.ipynb | 21 +- .../{{cookiecutter.problem_name}}/solution.py | 16 +- .../{{cookiecutter.problem_name}}/tests.py | 53 ++-- Makefile | 2 +- leetcode/container_with_most_water/README.md | 8 +- .../container_with_most_water/example1.png | Bin 29310 -> 0 bytes .../playground.ipynb | 26 +- leetcode/container_with_most_water/tests.py | 14 +- leetcode/insert_interval/README.md | 18 +- leetcode/insert_interval/playground.ipynb | 26 +- leetcode/insert_interval/tests.py | 7 +- leetcode/invert_binary_tree/README.md | 7 +- leetcode/invert_binary_tree/playground.ipynb | 240 +--------------- leetcode/invert_binary_tree/tests.py | 23 +- leetcode/lru_cache/README.md | 35 ++- leetcode/lru_cache/playground.ipynb | 38 +-- leetcode/lru_cache/tests.py | 19 +- leetcode/reverse_linked_list_ii/README.md | 9 +- .../reverse_linked_list_ii/playground.ipynb | 45 +-- leetcode/reverse_linked_list_ii/tests.py | 17 +- leetcode/spiral_matrix/README.md | 21 +- leetcode/spiral_matrix/playground.ipynb | 26 +- leetcode/spiral_matrix/tests.py | 33 +-- leetcode_py/test_utils.py | 39 ++- leetcode_py/tools/generator.py | 10 +- tests/tools/test_generator.py | 22 +- 45 files changed, 1389 insertions(+), 1133 deletions(-) create mode 100644 .amazonq/plans/02-cookiecutter-template-improvement.md create mode 100644 .amazonq/plans/03-regenerate-all-problems.md create mode 100644 .templates/leetcode/examples/design.json5 delete mode 100644 .templates/leetcode/examples/string.json5 delete mode 100644 leetcode/container_with_most_water/example1.png diff --git a/.amazonq/plans/02-cookiecutter-template-improvement.md b/.amazonq/plans/02-cookiecutter-template-improvement.md new file mode 100644 index 0000000..acc78a5 --- /dev/null +++ b/.amazonq/plans/02-cookiecutter-template-improvement.md @@ -0,0 +1,266 @@ +# Plan: Improve Cookiecutter Template for LeetCode Problems + +## Overview + +Improve the cookiecutter template to be more general and cover all LeetCode question types, including special cases like LRU Cache that use custom class names and multiple methods. + +## Current Issues Identified + +1. **Hard-coded class name**: Template assumes `Solution` class but some problems use custom classes (e.g., `LRUCache`) +2. **Single method assumption**: Template assumes one method but some problems have multiple methods (`__init__`, `get`, `put`) +3. **Complex test setup**: Current template doesn't handle operation-based testing for design problems +4. **Import handling**: Need better solution import structure +5. **Template parameter explosion**: Too many derived parameters that could be simplified + +## Target Structure + +``` +.templates/leetcode/ +├── {{cookiecutter.problem_name}}/ +│ ├── __init__.py +│ ├── solution.py +│ ├── tests.py +│ ├── README.md +│ └── playground.ipynb +└── cookiecutter.json +``` + +## Phase 1: Analyze Problem Types + +### 1.1 Universal Template Variables + +- `solution_imports`: Required imports for solution.py (empty, TreeNode, ListNode, etc.) +- `test_imports`: All import lines for tests.py (pytest, loguru, TreeNode, test_utils, solution class) +- `solution_class_name`: Dynamic class name (Solution, LRUCache, etc.) +- `readme_description`: Problem description for README (supports HTML including images, preserves code snippets like `x`, `y`, `some_params`) +- `readme_examples`: Examples for README (supports HTML including images, typically uses code blocks for input/output) +- `readme_constraints`: Constraints for README +- `readme_additional`: Additional README sections +- `solution_methods`: List of methods with parameters/return types +- `test_methods`: List of test methods with parametrize and body +- `test_helper_methods`: List of test helper methods (setup_method, teardown_method, utility methods, etc.) + +## Phase 2: Create New cookiecutter.json + +### 2.1 Complete Template Variables Example + +````json +{ + "problem_name": "two_sum", + "solution_class_name": "Solution", + "problem_number": "1", + "problem_title": "Two Sum", + "difficulty": "Easy", + "topics": "Array, Hash Table", + "tags": ["grind-75"], + + "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`.\n\n\"Array\n\nYou may assume that each input would have exactly one solution, and you may not use the same element twice.", + "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": "\"Binary\n\n```\nInput: root = [4,2,7,1,3,6,9]\nOutput: [4,7,2,9,6,3,1]\n```\n**Explanation:** The tree is inverted as shown in the image above." + } + ], + "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.", + "readme_additional": "", + + "solution_imports": "", + "solution_methods": [ + { + "name": "two_sum", + "parameters": "nums: list[int], target: int", + "return_type": "list[int]", + "dummy_return": "[]" + } + ], + + "test_imports": "import pytest\nfrom loguru import logger\nfrom leetcode_py.test_utils import logged_test\nfrom .solution import Solution", + "test_helper_methods": [ + { + "name": "setup_method", + "parameters": "", + "body": "self.solution = Solution()" + } + ], + "test_methods": [ + { + "name": "test_two_sum", + "parametrize": "nums, target, expected", + "test_cases": "[([2, 7, 11, 15], 9, [0, 1]), ([3, 2, 4], 6, [1, 2])]", + "body": "result = self.solution.two_sum(nums, target)\nassert result == expected" + } + ], + + "playground_imports": "from solution import Solution", + "playground_test_case": "# Example test case\nnums = [2, 7, 11, 15]\ntarget = 9\nexpected = [0, 1]", + "playground_execution": "result = Solution().two_sum(nums, target)\nresult", + "playground_assertion": "assert result == expected" +} +```` + +## Phase 3: Update Template Files + +### 3.1 solution.py Template + +```python +{{cookiecutter.solution_imports}} + +class {{cookiecutter.solution_class_name}}: + {% for method in cookiecutter.solution_methods %} + # Time: O(?) + # Space: O(?) + def {{method.name}}(self, {{method.parameters}}) -> {{method.return_type}}: + # TODO: Implement {{method.name}} + return {{method.dummy_return}} + + {% endfor %} +``` + +### 3.2 tests.py Template + +```python +{{cookiecutter.test_imports}} + +class Test{{cookiecutter.solution_class_name}}: + {% for method in cookiecutter.test_helper_methods %} + def {{method.name}}(self{% if method.parameters %}, {{method.parameters}}{% endif %}): + {{method.body}} + + {% endfor %} + + {% for method in cookiecutter.test_methods %} + @pytest.mark.parametrize("{{method.parametrize}}", {{method.test_cases}}) + @logged_test + def {{method.name}}(self, {{method.parametrize}}): + {{method.body}} + + {% endfor %} +``` + +### 3.3 README.md Template + +```markdown +# {{cookiecutter.problem_title}} + +**Difficulty:** {{cookiecutter.difficulty}} +**Topics:** {{cookiecutter.topics}} +**Tags:** {{cookiecutter.tags | join(', ')}} +{% if cookiecutter.problem_number %} +**LeetCode:** [Problem {{cookiecutter.problem_number}}](https://leetcode.com/problems/{{cookiecutter.problem_name.replace('_', "-")}}/description/) +{% endif %} + +## Problem Description + +{{cookiecutter.readme_description}} + +## Examples + +{% for example in cookiecutter.readme_examples %} + +### Example {{loop.index}}: + +{{example.content}} +{% endfor %} + +## Constraints + +{{cookiecutter.readme_constraints}} + +{% if cookiecutter.readme_additional %} +{{cookiecutter.readme_additional}} +{% endif %} +``` + +### 3.4 playground.ipynb Template + +```json +{ + "cells": [ + { + "cell_type": "code", + "id": "imports", + "source": ["{{cookiecutter.playground_imports}}"] + }, + { + "cell_type": "code", + "id": "setup", + "source": ["{{cookiecutter.playground_test_case}}"] + }, + { + "cell_type": "code", + "id": "execute", + "source": ["{{cookiecutter.playground_execution}}"] + }, + { + "cell_type": "code", + "id": "test", + "source": ["{{cookiecutter.playground_assertion}}"] + } + ] +} +``` + +## Phase 4: Simplify Parameter Generation + +### 4.1 Reduce Template Complexity + +- Remove derived parameters like `param_names`, `input_description`, etc. +- Generate these dynamically in the template using Jinja2 filters +- Focus on core data: methods, test_cases, problem metadata + +### 4.2 Smart Defaults + +- Auto-generate method names from problem names +- Auto-generate class names from problem names +- Default to "basic" problem type unless specified + +## Phase 5: Testing & Validation + +### 5.1 Test with Existing Problems + +- Generate all current problems using new template +- Compare output with existing generated files +- Ensure no regression in functionality + +### 5.2 Test Special Cases + +- LRU Cache (design problem) +- Tree problems (TreeNode imports) +- Linked list problems (ListNode imports) +- Matrix problems (2D arrays) + +## Phase 6: Integration + +### 6.1 Update Generation Scripts + +- Modify `gen.py` to work with new template structure +- Update Makefile commands +- Ensure backward compatibility with existing JSON files + +### 6.2 Documentation + +- Update problem creation guide +- Create examples for each problem type +- Document new template variables + +## Success Criteria + +1. ✅ Single cookiecutter template handles all problem types +2. ✅ Reduced template complexity (fewer derived parameters) +3. ✅ Support for design problems with multiple methods +4. ✅ Proper imports for tree/linked list problems +5. ✅ Clean, maintainable template structure +6. ✅ All existing problems can be regenerated without issues +7. ✅ New problem types can be easily added + +## Implementation Order + +1. Create new `cookiecutter.json` structure +2. Update template files with conditional logic +3. Test with basic problems (Two Sum) +4. Test with design problems (LRU Cache) +5. Test with tree/linked list problems +6. Validate all existing problems +7. Update generation scripts and documentation diff --git a/.amazonq/plans/03-regenerate-all-problems.md b/.amazonq/plans/03-regenerate-all-problems.md new file mode 100644 index 0000000..e993f26 --- /dev/null +++ b/.amazonq/plans/03-regenerate-all-problems.md @@ -0,0 +1,228 @@ +# Plan: Regenerate All Problems with Fresh LeetCode Data + +## Overview + +Scrape fresh data from LeetCode for existing problems and generate new JSON files using the new universal cookiecutter template, ensuring all generated code passes linting. + +## Current State Analysis + +- Old JSON files: `.templates/leetcode/old/template/json/*.json` (for problem names only) +- Scraper: `.templates/leetcode/scrape.py` (existing) +- New template: `.templates/leetcode/cookiecutter.json` + templates +- Target: `.templates/leetcode/json/*.json` (new format with fresh data) +- Generated problems: `leetcode/*/` + +## Phase 1: Extract Problem Names + +### 1.1 Get Problem Names from Old JSON + +```bash +ls .templates/leetcode/old/template/json/ +``` + +Expected problems: + +- container_with_most_water.json +- insert_interval.json +- invert_binary_tree.json +- lru_cache.json +- reverse_linked_list_ii.json +- spiral_matrix.json + +### 1.2 Extract Problem Numbers/Slugs + +From old JSON files, extract: + +- Problem numbers (for scraping by number) +- Problem names/slugs (for scraping by slug) + +## Phase 2: Create Fresh Scraping Script + +### 2.1 Use Existing Scraper + +Following the problem creation rules: + +```bash +# Fetch by number +poetry run python .templates/leetcode/scrape.py -n 1 + +# Fetch by slug +poetry run python .templates/leetcode/scrape.py -s "two-sum" +``` + +### 2.2 Scraping Script: `scrape_all_problems.py` + +✅ **Created** - Uses existing scraper to fetch fresh data for all problems + +## Phase 3: Execute Fresh Scraping + +### 3.1 Run Scraping Script + +```bash +cd .templates/leetcode +python scrape_all_problems.py +``` + +### 3.2 Transform JSON to New Template Format + +The scraper creates JSON in new template format automatically. + +### 3.3 Verify New JSON Files + +```bash +ls .templates/leetcode/json/ +# Should show all freshly scraped JSON files +``` + +## Phase 4: Test Generation Pipeline + +### 4.1 Test Single Problem Generation + +```bash +make p-gen PROBLEM=container_with_most_water FORCE=1 +``` + +### 4.2 Verify Generated Structure + +```bash +ls leetcode/container_with_most_water/ +# Should show: __init__.py, solution.py, tests.py, README.md, playground.ipynb +``` + +### 4.3 Test Linting on Single Problem + +```bash +make lint +# Should pass without errors +``` + +## Phase 5: Full Regeneration + +### 5.1 Update Makefile (if needed) + +Verify `gen-all-problems` target works with new template: + +```makefile +gen-all-problems: + @echo "This will DELETE all existing problems and regenerate from JSON templates." + @read -p "Are you sure? (y/N): " confirm && [ "$$confirm" = "y" ] || exit 1 + @echo "Deleting existing problems..." + @rm -rf leetcode/*/ + @echo "Generating all problems..." + @for json_file in .templates/leetcode/json/*.json; do \ + problem=$$(basename "$$json_file" .json); \ + echo "Generating: $$problem"; \ + poetry run python .templates/leetcode/gen.py "$$json_file" --force; \ + done +``` + +### 5.2 Run Full Regeneration + +```bash +make gen-all-problems FORCE=1 +``` + +### 5.3 Verify All Problems Generated + +```bash +ls leetcode/ +# Should show all problem directories +``` + +## Phase 6: Validation & Iteration + +### 6.1 Run Linting on All Problems + +```bash +make lint +``` + +### 6.2 Fix Issues (Iterative Process) + +**If linting fails:** + +1. **Identify Issue Type:** + - Template formatting issues → Fix template files + - JSON data issues → Re-scrape or manually fix JSON + - Import issues → Fix template imports + +2. **Fix and Regenerate:** + + ```bash + # Fix issue in template or JSON + make gen-all-problems FORCE=1 + make lint + ``` + +3. **Repeat until clean:** + - Continue iteration until `make lint` passes + - Ensure reproducible generation + +### 6.3 Common Issues & Fixes + +**Template Issues:** + +- Indentation problems → Fix Jinja2 `indent` filters in templates +- Missing imports → Update template import generation +- Method signatures → Fix solution_methods in JSON + +**JSON Issues:** + +- Missing required fields → Re-scrape with updated scraper +- Incorrect data types → Fix scraper output format +- Test case format → Update scraper test case generation + +## Phase 7: Validation Testing + +### 7.1 Test Individual Problems + +```bash +make p-test PROBLEM=container_with_most_water +make p-test PROBLEM=lru_cache +make p-test PROBLEM=invert_binary_tree +``` + +### 7.2 Run Full Test Suite + +```bash +make test +``` + +### 7.3 Verify Notebooks Work + +- Check playground.ipynb files can be opened +- Verify cell content is properly formatted + +## Success Criteria + +1. ✅ All old JSON files migrated to new format +2. ✅ `make gen-all-problems` works with new template +3. ✅ All generated problems pass `make lint` +4. ✅ All generated problems pass `make test` +5. ✅ Generation is reproducible (no manual fixes needed) +6. ✅ All problem types work (basic, design, tree, linked list) + +## Implementation Order + +1. **Create scraping script** - Get fresh data from LeetCode +2. **Run fresh scraping** - Generate new JSON files +3. **Test single problem** - Verify pipeline works +4. **Fix template issues** - Ensure clean generation +5. **Run full regeneration** - Generate all problems +6. **Iterate on linting** - Fix issues until clean +7. **Final validation** - Test all problems work + +## Rollback Plan + +If issues arise: + +1. Keep old template in `.templates/leetcode/old/` +2. Can revert to old generation method +3. New template is additive, doesn't break existing workflow + +## Notes + +- Focus on reproducible generation without manual intervention +- Prioritize linting compliance over perfect formatting +- Document any template limitations discovered during migration +- Ensure backward compatibility with existing JSON structure diff --git a/.amazonq/plans/cookiecutter-template-plan.md b/.amazonq/plans/cookiecutter-template-plan.md index 8e18a7c..ae762c2 100644 --- a/.amazonq/plans/cookiecutter-template-plan.md +++ b/.amazonq/plans/cookiecutter-template-plan.md @@ -157,7 +157,7 @@ "constraints": "Formatted constraints", "parameters": "typed_params: list[int]", "return_type": "TreeNode | None", - "imports": "from leetcode_py.tree_node import TreeNode", + "imports": "from leetcode_py import TreeNode", "test_cases": [{"args": [...], "expected": ...}] } ``` diff --git a/.amazonq/rules/problem-creation.md b/.amazonq/rules/problem-creation.md index 9407ef3..0cc55af 100644 --- a/.amazonq/rules/problem-creation.md +++ b/.amazonq/rules/problem-creation.md @@ -77,13 +77,13 @@ Required fields for `.templates/leetcode/json/{problem_name}.json`: ### Tree Problems -- Add `"imports": "from leetcode_py.tree_node import TreeNode"` +- Add `"imports": "from leetcode_py import TreeNode"` - Use `TreeNode | None` for nullable tree parameters - Test setup: `root = TreeNode.from_list(root_list)` ### Linked List Problems -- Add `"imports": "from leetcode_py.list_node import ListNode"` +- Add `"imports": "from leetcode_py import ListNode"` - Use `ListNode | None` for nullable list parameters - Test setup: `head = ListNode.from_list(head_list)` diff --git a/.templates/leetcode/cookiecutter.json b/.templates/leetcode/cookiecutter.json index e44999d..bf9c13a 100644 --- a/.templates/leetcode/cookiecutter.json +++ b/.templates/leetcode/cookiecutter.json @@ -1,41 +1,59 @@ { "problem_name": "two_sum", - "class_name": "TwoSum", - "method_name": "two_sum", + "solution_class_name": "Solution", "problem_number": "1", "problem_title": "Two Sum", "difficulty": "Easy", "topics": "Array, Hash Table", "_tags": { "list": ["grind-75"] }, - "problem_description": "Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target.", - "_examples": { + + "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": { "list": [ - { "input": "nums = [2,7,11,15], target = 9", "output": "[0,1]" }, - { "input": "nums = [3,2,4], target = 6", "output": "[1,2]" }, - { "input": "nums = [3,3], target = 6", "output": "[0,1]" } + { + "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]." + } ] }, - "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.", - "parameters": "nums: list[int], target: int", - "return_type": "list[int]", - "dummy_return": "[]", - "imports": "", - "test_setup": "", - "test_logging": "", - "_test_cases": { + "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.", + "readme_additional": "", + + "solution_imports": "", + "_solution_methods": { "list": [ - { "args": [[2, 7, 11, 15], 9], "expected": [0, 1] }, - { "args": [[3, 2, 4], 6], "expected": [1, 2] }, - { "args": [[3, 3], 6], "expected": [0, 1] } + { + "name": "two_sum", + "parameters": "nums: list[int], target: int", + "return_type": "list[int]", + "dummy_return": "[]" + } ] }, - "param_names": "nums, target, expected", - "param_names_with_types": "nums: list[int], target: int, expected: list[int]", - "input_description": "nums={nums}, target={target}", - "input_params": "nums, target", - "expected_param": "expected", - "method_args": "nums, target", - "test_input_setup": "nums = [2, 7, 11, 15]\ntarget = 9", - "expected_output_setup": "expected = [0, 1]", - "assertion_code": "assert result == expected" + + "test_imports": "import pytest\nfrom loguru import logger\nfrom leetcode_py.test_utils import logged_test\nfrom .solution import Solution", + "_test_helper_methods": { + "list": [ + { + "name": "setup_method", + "parameters": "", + "body": "self.solution = Solution()" + } + ] + }, + "_test_methods": { + "list": [ + { + "name": "test_two_sum", + "parametrize": "nums, target, expected", + "parametrize_typed": "nums: list[int], target: int, expected: list[int]", + "test_cases": "[([2, 7, 11, 15], 9, [0, 1]), ([3, 2, 4], 6, [1, 2])]", + "body": "result = self.solution.two_sum(nums, target)\nassert result == expected" + } + ] + }, + + "playground_imports": "from solution import Solution", + "playground_test_case": "# Example test case\nnums = [2, 7, 11, 15]\ntarget = 9\nexpected = [0, 1]", + "playground_execution": "result = Solution().two_sum(nums, target)\nresult", + "playground_assertion": "assert result == expected" } diff --git a/.templates/leetcode/examples/README.md b/.templates/leetcode/examples/README.md index 0f59d7c..2678b3a 100644 --- a/.templates/leetcode/examples/README.md +++ b/.templates/leetcode/examples/README.md @@ -1,71 +1,109 @@ -# LeetCode Template Examples +# LeetCode Problem Template Examples -Reference templates for creating new LeetCode problems. **Copy from these examples** - don't create from scratch. +This directory contains comprehensive JSON5 template examples for different types of LeetCode problems. These examples serve as references when creating new problems using the universal cookiecutter template. -## Usage +## Template Types -1. **Choose the right template** based on problem type -2. **Copy the entire structure** to `.templates/leetcode/json/{problem_name}.json` -3. **Update all fields** with your problem's data -4. **Generate**: `make p-gen PROBLEM=your_problem` +### 1. `basic.json5` - Basic Algorithm Problems -## Templates +**Use for:** Array, string, number, hash table problems +**Examples:** Container With Most Water, Two Sum, Valid Palindrome +**Key features:** -### `basic.json5` +- Simple `Solution` class with single method +- Standard test parametrization +- Basic playground setup -- **Use for**: Array, string, number, hash table problems -- **Examples**: Two Sum, Valid Anagram, Contains Duplicate -- **Features**: Simple parameters, direct assertions +### 2. `tree.json5` - Binary Tree Problems -### `tree.json5` +**Use for:** Binary tree, BST, tree traversal problems +**Examples:** Invert Binary Tree, Maximum Depth, Serialize Tree +**Key features:** -- **Use for**: Binary tree problems -- **Examples**: Invert Binary Tree, Maximum Depth, Same Tree -- **Features**: TreeNode import, array-to-tree conversion, tree logging +- `TreeNode` imports and conversions +- `TreeNode.from_list()` and `TreeNode.to_list()` in tests +- Tree visualization support -### `linked_list.json5` +### 3. `linked_list.json5` - Linked List Problems -- **Use for**: Linked list problems -- **Examples**: Reverse Linked List, Merge Two Lists, Cycle Detection -- **Features**: ListNode import, array-to-list conversion, list logging +**Use for:** Singly/doubly linked list problems +**Examples:** Reverse Linked List, Merge Lists, Detect Cycle +**Key features:** -### `string.json5` +- `ListNode` imports and conversions +- `ListNode.from_list()` and `ListNode.to_list()` in tests +- Arrow visualization support -- **Use for**: String manipulation problems -- **Examples**: Valid Palindrome, Longest Substring, Anagrams -- **Features**: String parameters, boolean/string returns +### 4. `design.json5` - Data Structure Design Problems -### `matrix.json5` +**Use for:** Design problems requiring custom classes +**Examples:** LRU Cache, Implement Trie, Design HashMap +**Key features:** -- **Use for**: 2D array/matrix problems -- **Examples**: Rotate Image, Spiral Matrix, Set Matrix Zeroes -- **Features**: Matrix parameters, in-place operation testing +- Custom class names (not `Solution`) +- Multiple methods including `__init__` +- Complex operation sequence testing +- Type annotations for complex test logic -## Key Fields +### 5. `matrix.json5` - 2D Array/Matrix Problems -### Required Core Fields +**Use for:** Matrix manipulation, 2D array problems +**Examples:** Spiral Matrix, Rotate Image, Search 2D Matrix +**Key features:** -- `problem_name`, `class_name`, `method_name` -- `problem_number`, `problem_title`, `difficulty`, `topics` -- `problem_description`, `examples`, `constraints` -- `parameters`, `return_type`, `dummy_return` +- 2D array type annotations (`list[list[int]]`) +- Visual examples with images +- Matrix-specific test cases -### Test Configuration +## Usage Guidelines -- `test_cases`: Array of `{args, expected}` objects -- `param_names`: Parameter names for test methods -- `test_setup`: Code to convert test data (e.g., arrays to TreeNode) -- `assertion_code`: How to compare result with expected +### Problem Type Detection -### Notebook Setup +1. **Basic**: Single algorithm, simple input/output +2. **Tree**: Mentions "tree", "node", uses tree terminology +3. **Linked List**: Mentions "linked list", "node", list operations +4. **Design**: "Design", "Implement", multiple operations +5. **Matrix**: "matrix", "2D array", "grid", visual layout -- `test_input_setup`: Code for notebook input cell -- `expected_output_setup`: Code for notebook expected cell -- `imports`: Required imports (TreeNode, ListNode, etc.) +### Key Template Fields -## Rules +#### Required Fields -1. **Copy structure exactly** - all fields are required -2. **Use modern Python syntax**: `list[int]`, `TreeNode | None` -3. **Match existing patterns** - see current JSON files for reference -4. **Test thoroughly** - run `make lint` and `make p-test` after generation +- `problem_name`: snake_case identifier +- `solution_class_name`: "Solution" or custom class name +- `problem_number`: LeetCode number as string +- `problem_title`: Exact LeetCode title +- `difficulty`: "Easy", "Medium", or "Hard" +- `topics`: Comma-separated topic string +- `solution_methods`: Array of method definitions + +#### Important Patterns + +- **Type Hints**: Use modern syntax (`list[int]`, `dict[str, int]`, `Type | None`) +- **Method Names**: Always snake_case +- **Test Cases**: String representation of Python data structures +- **Imports**: Include necessary helper classes (TreeNode, ListNode) + +### Template Selection Process + +1. Identify problem type from description/title +2. Choose appropriate template from examples +3. Customize fields for specific problem +4. Ensure imports match problem requirements +5. Verify test setup matches data structures used + +## Validation + +All templates are validated against: + +- Cookiecutter template compatibility +- Linting requirements (black, isort, ruff, mypy) +- Test framework integration +- Notebook JSON format compliance + +## Notes + +- JSON5 format allows comments for documentation +- All examples are based on working, tested templates +- Templates are designed for the universal cookiecutter system +- Examples include both simple and complex problem patterns diff --git a/.templates/leetcode/examples/basic.json5 b/.templates/leetcode/examples/basic.json5 index 4ff8099..a1caf73 100644 --- a/.templates/leetcode/examples/basic.json5 +++ b/.templates/leetcode/examples/basic.json5 @@ -1,61 +1,73 @@ { - // Basic problem template for array/string/number problems - // Copy this structure when creating new basic problems + // Basic problem template - for array, string, number problems + // Example: Container With Most Water, Spiral Matrix - // REQUIRED: Core identifiers - "problem_name": "two_sum", - "class_name": "TwoSum", - "method_name": "two_sum", + // === PROBLEM IDENTIFICATION === + "problem_name": "container_with_most_water", // snake_case: used for directory/file names + "solution_class_name": "Solution", // Always "Solution" for basic problems + "problem_number": "11", // LeetCode problem number as string + "problem_title": "Container With Most Water", // Exact title from LeetCode + "difficulty": "Medium", // Easy, Medium, Hard + "topics": "Array, Two Pointers, Greedy", // Comma-separated topics from LeetCode + "tags": ["grind-75"], // Optional: common problem set tags - // REQUIRED: Problem metadata - "problem_number": "1", // OPTIONAL: omit if no LeetCode number - "problem_title": "Two Sum", - "difficulty": "Easy", - "topics": "Array, Hash Table", + // === README CONTENT === + // IMPORTANT: Preserve rich HTML content from LeetCode including: + // - Code snippets with backticks: `code` + // - Bold text: **bold** or bold + // - Italic text: *italic* or italic + // - Images: tags with proper src and styling + // - HTML formatting:

,
,