Skip to content

Commit 19ef0ef

Browse files
committed
feat: dev
1 parent aeb4900 commit 19ef0ef

File tree

10 files changed

+261
-35
lines changed

10 files changed

+261
-35
lines changed

.amazonq/rules/problem-creation.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ When user requests a problem by **number** or **name/slug**, the assistant will:
99
3. **Create** JSON file in `.templates/leetcode/json/{problem_name}.json`
1010
4. **Update** Makefile with `PROBLEM ?= {problem_name}`
1111
5. **Generate** problem structure using `make p-gen`
12-
6. **Verify** with `make lint`
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
1314

1415
## Scraping Commands
1516

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
{
2+
"problem_name": "lru_cache",
3+
"class_name": "LRUCache",
4+
"method_name": "lru_cache",
5+
"problem_number": "146",
6+
"problem_title": "LRU Cache",
7+
"difficulty": "Medium",
8+
"topics": "Hash Table, Linked List, Design, Doubly-Linked List",
9+
"tags": ["grind-75", "top-interview"],
10+
"problem_description": "Design a data structure that follows the constraints of a Least Recently Used (LRU) cache.\n\nImplement the LRUCache class:\n\n- LRUCache(int capacity) Initialize the LRU cache with positive size capacity.\n- int get(int key) Return the value of the key if the key exists, otherwise return -1.\n- void put(int key, int value) Update the value of the key if the key exists. Otherwise, add the key-value pair to the cache. If the number of keys exceeds the capacity from this operation, evict the least recently used key.\n\nThe functions get and put must each run in O(1) average time complexity.",
11+
"examples": [
12+
{
13+
"input": "[\"LRUCache\", \"put\", \"put\", \"get\", \"put\", \"get\", \"put\", \"get\", \"get\", \"get\"]\n[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]",
14+
"output": "[null, null, null, 1, null, -1, null, -1, 3, 4]"
15+
}
16+
],
17+
"constraints": "- 1 <= capacity <= 3000\n- 0 <= key <= 10^4\n- 0 <= value <= 10^5\n- At most 2 * 10^5 calls will be made to get and put.",
18+
"parameters": "capacity: int",
19+
"return_type": "None",
20+
"dummy_return": "None",
21+
"imports": "",
22+
"test_cases": [
23+
{
24+
"args": [
25+
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"],
26+
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
27+
],
28+
"expected": [null, null, null, 1, null, -1, null, -1, 3, 4]
29+
}
30+
],
31+
"param_names": "operations, inputs, expected",
32+
"param_names_with_types": "operations: list[str], inputs: list[list[int]], expected: list[int | None]",
33+
"input_description": "operations={operations}, inputs={inputs}",
34+
"input_params": "operations, inputs",
35+
"expected_param": "expected",
36+
"method_args": "operations, inputs",
37+
"test_setup": "cache = None\nresult = []\nfor i, op in enumerate(operations):\n if op == \"LRUCache\":\n cache = LRUCache(inputs[i][0])\n result.append(None)\n elif op == \"get\":\n result.append(cache.get(inputs[i][0]))\n elif op == \"put\":\n cache.put(inputs[i][0], inputs[i][1])\n result.append(None)",
38+
"test_logging": "logger.info(f\"Testing LRU Cache with operations: {operations}\")\nlogger.info(f\"Inputs: {inputs}\")\nlogger.info(f\"Expected: {expected}\")\nlogger.info(f\"Result: {result}\")",
39+
"assertion_code": "assert result == expected",
40+
"test_input_setup": "operations = [\"LRUCache\", \"put\", \"put\", \"get\", \"put\", \"get\", \"put\", \"get\", \"get\", \"get\"]\ninputs = [[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]",
41+
"expected_output_setup": "expected = [None, None, None, 1, None, -1, None, -1, 3, 4]"
42+
}

.templates/leetcode/scrape.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ def fetch(
3131
if number:
3232
problem = scraper.get_problem_by_number(number)
3333
else:
34+
if slug is None:
35+
typer.echo("Error: Slug cannot be None", err=True)
36+
raise typer.Exit(1)
3437
problem = scraper.get_problem_by_slug(slug)
3538

3639
if not problem:

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 ?= spiral_matrix
2+
PROBLEM ?= lru_cache
33
FORCE ?= 0
44

55
sync_submodules:

README.md

Lines changed: 17 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,32 @@
99

1010
Premium LeetCode practice repository with Python solutions, algorithm templates, data structure visualizations, and automated testing. Perfect for coding interview preparation, competitive programming, and mastering algorithms with Blind 75, Grind 75, and NeetCode 150 problems.
1111

12-
## 📋 Prerequisites
13-
14-
- Python 3.13+
15-
- make, git, Graphviz, poetry
16-
17-
## 🛠️ Installation
12+
## 🚀 Quick Start
1813

1914
```bash
2015
# Clone the repository
2116
git clone https://github.com/wisarootl/leetcode-py.git
2217
cd leetcode-py
2318

2419
# Install dependencies
25-
pip install -r requirements.txt
20+
poetry install
2621

27-
# Generate all problems
22+
# Generate all problems to start practicing (fresh start - wipes all solutions)
2823
make gen-all-problems
2924

30-
# Verify setup
25+
# Run existing problems
26+
make p-test PROBLEM=insert_interval
27+
make p-test PROBLEM=invert_binary_tree
28+
29+
# Run all tests
3130
make test
3231
```
3332

33+
## 📋 Prerequisites
34+
35+
- Python 3.13+
36+
- make, git, Graphviz, poetry
37+
3438
## 📁 Problem Structure
3539

3640
Each problem follows a consistent template:
@@ -91,20 +95,6 @@ _Interactive multi-cell playground for each problem_
9195
- **Full linting** - black, isort, ruff, mypy with nbqa for notebooks
9296
- **Modern Python** - PEP 585/604 syntax with full type hints
9397

94-
## 🚀 Quick Start
95-
96-
```bash
97-
# Generate all problems to start practicing
98-
make gen-all-problems
99-
100-
# Run existing problems
101-
make p-test PROBLEM=insert_interval
102-
make p-test PROBLEM=invert_binary_tree
103-
104-
# Run all tests
105-
make test
106-
```
107-
10898
## 🔄 Workflow Examples
10999

110100
**Practice existing problems**:
@@ -119,18 +109,12 @@ make p-test PROBLEM=two_sum
119109
**Add new problems**:
120110

121111
```bash
122-
# Copy problem description and solution placeholder from LeetCode
123-
# Then ask your LLM assistant:
124-
# "Create a new LeetCode problem for Valid Anagram"
125-
#
126-
# Behind the scenes, the LLM will:
127-
# 1. Create JSON template following .amazonq/rules/problem-creation.md
128-
# 2. Run `make p-gen PROBLEM=valid_anagram`
129-
# 3. Generate complete problem structure with tests
130-
# 4. You just implement the solution!
112+
# Ask your LLM assistant:
113+
# "Create LeetCode problem 146 (LRU Cache)"
114+
# The assistant handles everything automatically!
131115
```
132116

133-
_The LLM follows structured rules in `.amazonq/rules/problem-creation.md` to ensure consistent, high-quality problem generation using proven templates._
117+
_Behind the scenes: Assistant follows `.amazonq/rules/problem-creation.md` to scrape problem data, create JSON template, generate structure with `make p-gen`, and verify with `make lint`._
134118

135119
**Bulk operations**:
136120

leetcode/lru_cache/README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# 146. LRU Cache
2+
3+
**Difficulty:** Medium
4+
**Topics:** Hash Table, Linked List, Design, Doubly-Linked List
5+
**Tags:** grind-75, top-interview
6+
**LeetCode:** [Problem 146](https://leetcode.com/problems/lru-cache/description/)
7+
8+
## Problem Description
9+
10+
Design a data structure that follows the constraints of a Least Recently Used (LRU) cache.
11+
12+
Implement the LRUCache class:
13+
14+
- LRUCache(int capacity) Initialize the LRU cache with positive size capacity.
15+
- int get(int key) Return the value of the key if the key exists, otherwise return -1.
16+
- void put(int key, int value) Update the value of the key if the key exists. Otherwise, add the key-value pair to the cache. If the number of keys exceeds the capacity from this operation, evict the least recently used key.
17+
18+
The functions get and put must each run in O(1) average time complexity.
19+
20+
## Examples
21+
22+
### Example 1:
23+
24+
```
25+
Input: ["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
26+
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
27+
Output: [null, null, null, 1, null, -1, null, -1, 3, 4]
28+
```
29+
30+
## Constraints
31+
32+
- 1 <= capacity <= 3000
33+
- 0 <= key <= 10^4
34+
- 0 <= value <= 10^5
35+
- At most 2 \* 10^5 calls will be made to get and put.

leetcode/lru_cache/__init__.py

Whitespace-only changes.
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": 1,
6+
"id": "imports",
7+
"metadata": {},
8+
"outputs": [],
9+
"source": [
10+
"from solution import LRUCache"
11+
]
12+
},
13+
{
14+
"cell_type": "code",
15+
"execution_count": 2,
16+
"id": "setup",
17+
"metadata": {},
18+
"outputs": [],
19+
"source": [
20+
"operations = [\"LRUCache\", \"put\", \"put\", \"get\", \"put\", \"get\", \"put\", \"get\", \"get\", \"get\"]\n",
21+
"inputs = [[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]\n",
22+
"expected = [None, None, None, 1, None, -1, None, -1, 3, 4]"
23+
]
24+
},
25+
{
26+
"cell_type": "code",
27+
"execution_count": 3,
28+
"id": "execute",
29+
"metadata": {},
30+
"outputs": [
31+
{
32+
"data": {
33+
"text/plain": [
34+
"[None, None, None, 1, None, -1, None, -1, 3, 4]"
35+
]
36+
},
37+
"execution_count": 3,
38+
"metadata": {},
39+
"output_type": "execute_result"
40+
}
41+
],
42+
"source": [
43+
"cache: LRUCache | None = None\n",
44+
"result: list[int | None] = []\n",
45+
"for i, op in enumerate(operations):\n",
46+
" if op == \"LRUCache\":\n",
47+
" cache = LRUCache(inputs[i][0])\n",
48+
" result.append(None)\n",
49+
" elif op == \"get\" and cache is not None:\n",
50+
" result.append(cache.get(inputs[i][0]))\n",
51+
" elif op == \"put\" and cache is not None:\n",
52+
" cache.put(inputs[i][0], inputs[i][1])\n",
53+
" result.append(None)\n",
54+
"result"
55+
]
56+
},
57+
{
58+
"cell_type": "code",
59+
"execution_count": 4,
60+
"id": "test",
61+
"metadata": {},
62+
"outputs": [],
63+
"source": [
64+
"assert result == expected"
65+
]
66+
}
67+
],
68+
"metadata": {
69+
"kernelspec": {
70+
"display_name": "leetcode-py-py3.13",
71+
"language": "python",
72+
"name": "python3"
73+
},
74+
"language_info": {
75+
"codemirror_mode": {
76+
"name": "ipython",
77+
"version": 3
78+
},
79+
"file_extension": ".py",
80+
"mimetype": "text/x-python",
81+
"name": "python",
82+
"nbconvert_exporter": "python",
83+
"pygments_lexer": "ipython3",
84+
"version": "3.13.7"
85+
}
86+
},
87+
"nbformat": 4,
88+
"nbformat_minor": 5
89+
}

leetcode/lru_cache/solution.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from collections import OrderedDict
2+
3+
4+
class LRUCache:
5+
# Space: O(capacity)
6+
def __init__(self, capacity: int):
7+
self.capacity = capacity
8+
self.cache: OrderedDict[int, int] = OrderedDict()
9+
10+
# Time: O(1)
11+
# Space: O(1)
12+
def get(self, key: int) -> int:
13+
if key not in self.cache:
14+
return -1
15+
16+
# Move to end (most recent)
17+
self.cache.move_to_end(key)
18+
return self.cache[key]
19+
20+
# Time: O(1)
21+
# Space: O(1)
22+
def put(self, key: int, value: int) -> None:
23+
if key in self.cache:
24+
# Update existing and move to end
25+
self.cache[key] = value
26+
self.cache.move_to_end(key)
27+
else:
28+
# Add new
29+
if len(self.cache) >= self.capacity:
30+
# Remove LRU (first item)
31+
self.cache.popitem(last=False)
32+
33+
self.cache[key] = value

leetcode/lru_cache/tests.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import pytest
2+
from loguru import logger
3+
4+
from leetcode_py.test_utils import logged_test
5+
6+
from .solution import LRUCache
7+
8+
9+
class TestLRUCache:
10+
@pytest.mark.parametrize(
11+
"operations, inputs, expected",
12+
[
13+
(
14+
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"],
15+
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]],
16+
[None, None, None, 1, None, -1, None, -1, 3, 4],
17+
),
18+
],
19+
)
20+
@logged_test
21+
def test_lru_cache(self, operations: list[str], inputs: list[list[int]], expected: list[int | None]):
22+
logger.info(f"Testing LRU Cache with operations: {operations}")
23+
logger.info(f"Inputs: {inputs}")
24+
logger.info(f"Expected: {expected}")
25+
26+
cache: LRUCache | None = None
27+
result: list[int | None] = []
28+
for i, op in enumerate(operations):
29+
if op == "LRUCache":
30+
cache = LRUCache(inputs[i][0])
31+
result.append(None)
32+
elif op == "get" and cache is not None:
33+
result.append(cache.get(inputs[i][0]))
34+
elif op == "put" and cache is not None:
35+
cache.put(inputs[i][0], inputs[i][1])
36+
result.append(None)
37+
38+
logger.info(f"Result: {result}")
39+
assert result == expected

0 commit comments

Comments
 (0)