Skip to content

Commit 837b1ef

Browse files
authored
Merge pull request #48 from lufftw/feat/backtracking-exploration-docs-ontology-metadata
2 parents aefa90b + 835b63d commit 837b1ef

File tree

96 files changed

+2324
-5
lines changed

Some content is hidden

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

96 files changed

+2324
-5
lines changed

docs/SOLUTION_CONTRACT.md

Lines changed: 138 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,133 @@ SOLUTIONS = {
176176
}
177177
```
178178

179+
### A.7 Solution Comment Format
180+
181+
Solutions SHOULD include structured comments to explain the algorithm, approach, and key insights. This section defines the standard comment format.
182+
183+
#### A.7.1 File-Level Docstring
184+
185+
Every solution file SHOULD start with a docstring describing the problem:
186+
187+
```python
188+
"""
189+
Problem: Two Sum
190+
Link: https://leetcode.com/problems/two-sum/
191+
192+
Given an array of integers nums and an integer target, return indices
193+
of the two numbers such that they add up to target.
194+
195+
Constraints:
196+
- 2 <= nums.length <= 10^4
197+
- -10^9 <= nums[i] <= 10^9
198+
- -10^9 <= target <= 10^9
199+
- Only one valid answer exists.
200+
"""
201+
```
202+
203+
| Field | Required | Description |
204+
|-------|----------|-------------|
205+
| `Problem` || Problem title |
206+
| `Link` || LeetCode URL |
207+
| Description | Recommended | Brief problem statement |
208+
| `Constraints` | Recommended | Key constraints affecting algorithm choice |
209+
210+
#### A.7.2 Solution Block Comments
211+
212+
Each solution class SHOULD be preceded by a block comment explaining the approach.
213+
214+
**No blank line** between the comment block and the class definition:
215+
216+
```python
217+
# ============================================================================
218+
# Solution 1: Sliding Window (Optimized with Jump)
219+
# Time: O(n), Space: O(min(n, σ))
220+
# - Each character visited at most twice
221+
# - Uses last-seen-index array for O(1) duplicate detection
222+
# - Direct position jumping instead of incremental contraction
223+
# ============================================================================
224+
class SolutionSlidingWindow: # ← 緊接著,無空行
225+
...
226+
```
227+
228+
**Format:**
229+
230+
```
231+
# ============================================
232+
# Solution {N}: {Approach Name}
233+
# Time: O(?), Space: O(?)
234+
# - {Key insight or implementation detail}
235+
# - {Additional notes}
236+
# ============================================
237+
class ClassName: # ← No blank line before class/function
238+
```
239+
240+
| Component | Required | Description |
241+
|-----------|----------|-------------|
242+
| Solution number & name || e.g., `Solution 1: Sliding Window` |
243+
| Time/Space complexity || e.g., `Time: O(n), Space: O(n)` |
244+
| Bullet points | Recommended | Key insights, implementation details |
245+
| **No blank line** || Comment block directly followed by class/function |
246+
247+
**More examples:**
248+
249+
```python
250+
# ============================================
251+
# Solution 1: Single Pass
252+
# Time: O(max(m,n)), Space: O(max(m,n))
253+
# - Single pass through both lists
254+
# - Result list has at most max(m,n) + 1 nodes
255+
# ============================================
256+
class Solution:
257+
...
258+
```
259+
260+
```python
261+
# ============================================================================
262+
# Solution 2: Using Dictionary (More Flexible for Unicode)
263+
# Time: O(n), Space: O(min(n, σ))
264+
# - Same sliding window approach with dictionary instead of array
265+
# - More flexible for Unicode strings but slightly slower
266+
# ============================================================================
267+
class SolutionDict:
268+
...
269+
```
270+
271+
```python
272+
# ============================================================================
273+
# Solution 3: Using Set (Standard While-Loop Pattern)
274+
# Time: O(n), Space: O(min(n, σ))
275+
# - Uses set to track current window characters
276+
# - Demonstrates standard while-loop contraction pattern
277+
# ============================================================================
278+
class SolutionSet:
279+
...
280+
```
281+
282+
#### A.7.3 JUDGE_FUNC Comments (Optional)
283+
284+
When defining a `JUDGE_FUNC`, you MAY include a block comment explaining its purpose and complexity.
285+
286+
Same rule: **no blank line** between comment and function:
287+
288+
```python
289+
# ============================================
290+
# JUDGE_FUNC - Required for generator support
291+
# ============================================
292+
# Uses brute force O(m+n) merge to compute the correct answer,
293+
# then compares with the solution output.
294+
# ============================================
295+
def judge(actual, expected, input_data: str) -> bool: # ← 無空行
296+
...
297+
298+
JUDGE_FUNC = judge
299+
```
300+
301+
This is optional but recommended when:
302+
- The judge uses a different algorithm than the solution
303+
- The judge has notable complexity characteristics
304+
- Generator support requires custom validation
305+
179306
---
180307

181308
## B. SOLUTIONS Metadata Schema
@@ -629,6 +756,12 @@ When adding or modifying a solution, verify:
629756
"""
630757
Problem: {Problem Title}
631758
Link: https://leetcode.com/problems/{slug}/
759+
760+
{Brief problem description}
761+
762+
Constraints:
763+
- {constraint 1}
764+
- {constraint 2}
632765
"""
633766
from typing import List
634767
from _runner import get_solver
@@ -652,9 +785,12 @@ SOLUTIONS = {
652785
}
653786

654787
# ============================================
655-
# Solution class(es)
788+
# Solution 1: {Approach Name}
789+
# Time: O(?), Space: O(?)
790+
# - {Key insight or implementation detail}
791+
# - {Additional notes}
656792
# ============================================
657-
class Solution:
793+
class Solution: # ← No blank line after comment block
658794
def methodName(self, ...):
659795
...
660796

generators/0039_combination_sum.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# generators/0039_combination_sum.py
2+
"""
3+
Test Case Generator for Problem 0039 - Combination Sum
4+
5+
LeetCode Constraints:
6+
- 1 <= candidates.length <= 30
7+
- 2 <= candidates[i] <= 40
8+
- All elements of candidates are distinct
9+
- 1 <= target <= 40
10+
"""
11+
import random
12+
from typing import Iterator, Optional
13+
14+
15+
def generate(count: int = 10, seed: Optional[int] = None) -> Iterator[str]:
16+
"""
17+
Generate test case inputs for Combination Sum.
18+
19+
Args:
20+
count: Number of test cases to generate
21+
seed: Random seed for reproducibility
22+
23+
Yields:
24+
str: Test input in the format: candidates\\ntarget
25+
"""
26+
if seed is not None:
27+
random.seed(seed)
28+
29+
# Edge cases first
30+
edge_cases = [
31+
"2,3,6,7\n7", # Classic example
32+
"2,3,5\n8", # Multiple combinations
33+
"2\n1", # No solution
34+
"7,8,9\n7", # Single element solution
35+
]
36+
37+
for edge in edge_cases:
38+
yield edge
39+
count -= 1
40+
if count <= 0:
41+
return
42+
43+
# Random cases
44+
for _ in range(count):
45+
yield _generate_case()
46+
47+
48+
def _generate_case() -> str:
49+
"""Generate a single random test case."""
50+
# Random number of candidates (2-15 for reasonable test size)
51+
n = random.randint(2, 15)
52+
53+
# Generate distinct candidates in range [2, 40]
54+
candidates = random.sample(range(2, 41), min(n, 39))
55+
56+
# Generate target that is likely achievable
57+
min_candidate = min(candidates)
58+
target = random.randint(min_candidate, 40)
59+
60+
candidates_str = ','.join(map(str, candidates))
61+
return f"{candidates_str}\n{target}"
62+
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# generators/0040_combination_sum_ii.py
2+
"""
3+
Test Case Generator for Problem 0040 - Combination Sum II
4+
5+
LeetCode Constraints:
6+
- 1 <= candidates.length <= 100
7+
- 1 <= candidates[i] <= 50
8+
- 1 <= target <= 30
9+
"""
10+
import random
11+
from typing import Iterator, Optional
12+
13+
14+
def generate(count: int = 10, seed: Optional[int] = None) -> Iterator[str]:
15+
"""
16+
Generate test case inputs for Combination Sum II.
17+
18+
Args:
19+
count: Number of test cases to generate
20+
seed: Random seed for reproducibility
21+
22+
Yields:
23+
str: Test input in the format: candidates\\ntarget
24+
"""
25+
if seed is not None:
26+
random.seed(seed)
27+
28+
# Edge cases first
29+
edge_cases = [
30+
"10,1,2,7,6,1,5\n8", # Classic with duplicates
31+
"2,5,2,1,2\n5", # Multiple duplicates
32+
"1,1,1,1,1\n3", # All same
33+
"2\n1", # No solution
34+
]
35+
36+
for edge in edge_cases:
37+
yield edge
38+
count -= 1
39+
if count <= 0:
40+
return
41+
42+
# Random cases
43+
for _ in range(count):
44+
yield _generate_case()
45+
46+
47+
def _generate_case() -> str:
48+
"""Generate a single random test case with possible duplicates."""
49+
# Random number of candidates (2-20 for reasonable test size)
50+
n = random.randint(2, 20)
51+
52+
# Generate candidates with possible duplicates
53+
candidates = [random.randint(1, 50) for _ in range(n)]
54+
55+
# Generate target in valid range
56+
target = random.randint(1, 30)
57+
58+
candidates_str = ','.join(map(str, candidates))
59+
return f"{candidates_str}\n{target}"
60+

generators/0046_permutations.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# generators/0046_permutations.py
2+
"""
3+
Test Case Generator for Problem 0046 - Permutations
4+
5+
LeetCode Constraints:
6+
- 1 <= nums.length <= 6
7+
- -10 <= nums[i] <= 10
8+
- All the integers of nums are unique
9+
"""
10+
import random
11+
from typing import Iterator, Optional
12+
13+
14+
def generate(count: int = 10, seed: Optional[int] = None) -> Iterator[str]:
15+
"""
16+
Generate test case inputs for Permutations.
17+
18+
Args:
19+
count: Number of test cases to generate
20+
seed: Random seed for reproducibility
21+
22+
Yields:
23+
str: Test input in the format: nums (comma-separated)
24+
"""
25+
if seed is not None:
26+
random.seed(seed)
27+
28+
# Edge cases first
29+
edge_cases = [
30+
"1", # Single element
31+
"1,2", # Two elements
32+
"1,2,3", # Classic example
33+
"0,-1,1", # With negatives
34+
"1,2,3,4,5,6", # Maximum length
35+
]
36+
37+
for edge in edge_cases:
38+
yield edge
39+
count -= 1
40+
if count <= 0:
41+
return
42+
43+
# Random cases
44+
for _ in range(count):
45+
yield _generate_case()
46+
47+
48+
def _generate_case() -> str:
49+
"""Generate a single random test case with distinct integers."""
50+
# Random length 1-6
51+
n = random.randint(1, 6)
52+
53+
# Generate distinct integers in range [-10, 10]
54+
nums = random.sample(range(-10, 11), n)
55+
56+
return ','.join(map(str, nums))
57+

0 commit comments

Comments
 (0)