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
140 changes: 138 additions & 2 deletions docs/SOLUTION_CONTRACT.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,133 @@ SOLUTIONS = {
}
```

### A.7 Solution Comment Format

Solutions SHOULD include structured comments to explain the algorithm, approach, and key insights. This section defines the standard comment format.

#### A.7.1 File-Level Docstring

Every solution file SHOULD start with a docstring describing the problem:

```python
"""
Problem: Two Sum
Link: https://leetcode.com/problems/two-sum/

Given an array of integers nums and an integer target, return indices
of the two numbers such that they add up to target.

Constraints:
- 2 <= nums.length <= 10^4
- -10^9 <= nums[i] <= 10^9
- -10^9 <= target <= 10^9
- Only one valid answer exists.
"""
```

| Field | Required | Description |
|-------|----------|-------------|
| `Problem` | ✅ | Problem title |
| `Link` | ✅ | LeetCode URL |
| Description | Recommended | Brief problem statement |
| `Constraints` | Recommended | Key constraints affecting algorithm choice |

#### A.7.2 Solution Block Comments

Each solution class SHOULD be preceded by a block comment explaining the approach.

**No blank line** between the comment block and the class definition:

```python
# ============================================================================
# Solution 1: Sliding Window (Optimized with Jump)
# Time: O(n), Space: O(min(n, σ))
# - Each character visited at most twice
# - Uses last-seen-index array for O(1) duplicate detection
# - Direct position jumping instead of incremental contraction
# ============================================================================
class SolutionSlidingWindow: # ← 緊接著,無空行
...
```

**Format:**

```
# ============================================
# Solution {N}: {Approach Name}
# Time: O(?), Space: O(?)
# - {Key insight or implementation detail}
# - {Additional notes}
# ============================================
class ClassName: # ← No blank line before class/function
```

| Component | Required | Description |
|-----------|----------|-------------|
| Solution number & name | ✅ | e.g., `Solution 1: Sliding Window` |
| Time/Space complexity | ✅ | e.g., `Time: O(n), Space: O(n)` |
| Bullet points | Recommended | Key insights, implementation details |
| **No blank line** | ✅ | Comment block directly followed by class/function |

**More examples:**

```python
# ============================================
# Solution 1: Single Pass
# Time: O(max(m,n)), Space: O(max(m,n))
# - Single pass through both lists
# - Result list has at most max(m,n) + 1 nodes
# ============================================
class Solution:
...
```

```python
# ============================================================================
# Solution 2: Using Dictionary (More Flexible for Unicode)
# Time: O(n), Space: O(min(n, σ))
# - Same sliding window approach with dictionary instead of array
# - More flexible for Unicode strings but slightly slower
# ============================================================================
class SolutionDict:
...
```

```python
# ============================================================================
# Solution 3: Using Set (Standard While-Loop Pattern)
# Time: O(n), Space: O(min(n, σ))
# - Uses set to track current window characters
# - Demonstrates standard while-loop contraction pattern
# ============================================================================
class SolutionSet:
...
```

#### A.7.3 JUDGE_FUNC Comments (Optional)

When defining a `JUDGE_FUNC`, you MAY include a block comment explaining its purpose and complexity.

Same rule: **no blank line** between comment and function:

```python
# ============================================
# JUDGE_FUNC - Required for generator support
# ============================================
# Uses brute force O(m+n) merge to compute the correct answer,
# then compares with the solution output.
# ============================================
def judge(actual, expected, input_data: str) -> bool: # ← 無空行
...

JUDGE_FUNC = judge
```

This is optional but recommended when:
- The judge uses a different algorithm than the solution
- The judge has notable complexity characteristics
- Generator support requires custom validation

---

## B. SOLUTIONS Metadata Schema
Expand Down Expand Up @@ -629,6 +756,12 @@ When adding or modifying a solution, verify:
"""
Problem: {Problem Title}
Link: https://leetcode.com/problems/{slug}/

{Brief problem description}

Constraints:
- {constraint 1}
- {constraint 2}
"""
from typing import List
from _runner import get_solver
Expand All @@ -652,9 +785,12 @@ SOLUTIONS = {
}

# ============================================
# Solution class(es)
# Solution 1: {Approach Name}
# Time: O(?), Space: O(?)
# - {Key insight or implementation detail}
# - {Additional notes}
# ============================================
class Solution:
class Solution: # ← No blank line after comment block
def methodName(self, ...):
...

Expand Down
62 changes: 62 additions & 0 deletions generators/0039_combination_sum.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# generators/0039_combination_sum.py
"""
Test Case Generator for Problem 0039 - Combination Sum

LeetCode Constraints:
- 1 <= candidates.length <= 30
- 2 <= candidates[i] <= 40
- All elements of candidates are distinct
- 1 <= target <= 40
"""
import random
from typing import Iterator, Optional


def generate(count: int = 10, seed: Optional[int] = None) -> Iterator[str]:
"""
Generate test case inputs for Combination Sum.

Args:
count: Number of test cases to generate
seed: Random seed for reproducibility

Yields:
str: Test input in the format: candidates\\ntarget
"""
if seed is not None:
random.seed(seed)

# Edge cases first
edge_cases = [
"2,3,6,7\n7", # Classic example
"2,3,5\n8", # Multiple combinations
"2\n1", # No solution
"7,8,9\n7", # Single element solution
]

for edge in edge_cases:
yield edge
count -= 1
if count <= 0:
return

# Random cases
for _ in range(count):
yield _generate_case()


def _generate_case() -> str:
"""Generate a single random test case."""
# Random number of candidates (2-15 for reasonable test size)
n = random.randint(2, 15)

# Generate distinct candidates in range [2, 40]
candidates = random.sample(range(2, 41), min(n, 39))

# Generate target that is likely achievable
min_candidate = min(candidates)
target = random.randint(min_candidate, 40)

candidates_str = ','.join(map(str, candidates))
return f"{candidates_str}\n{target}"

60 changes: 60 additions & 0 deletions generators/0040_combination_sum_ii.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# generators/0040_combination_sum_ii.py
"""
Test Case Generator for Problem 0040 - Combination Sum II

LeetCode Constraints:
- 1 <= candidates.length <= 100
- 1 <= candidates[i] <= 50
- 1 <= target <= 30
"""
import random
from typing import Iterator, Optional


def generate(count: int = 10, seed: Optional[int] = None) -> Iterator[str]:
"""
Generate test case inputs for Combination Sum II.

Args:
count: Number of test cases to generate
seed: Random seed for reproducibility

Yields:
str: Test input in the format: candidates\\ntarget
"""
if seed is not None:
random.seed(seed)

# Edge cases first
edge_cases = [
"10,1,2,7,6,1,5\n8", # Classic with duplicates
"2,5,2,1,2\n5", # Multiple duplicates
"1,1,1,1,1\n3", # All same
"2\n1", # No solution
]

for edge in edge_cases:
yield edge
count -= 1
if count <= 0:
return

# Random cases
for _ in range(count):
yield _generate_case()


def _generate_case() -> str:
"""Generate a single random test case with possible duplicates."""
# Random number of candidates (2-20 for reasonable test size)
n = random.randint(2, 20)

# Generate candidates with possible duplicates
candidates = [random.randint(1, 50) for _ in range(n)]

# Generate target in valid range
target = random.randint(1, 30)

candidates_str = ','.join(map(str, candidates))
return f"{candidates_str}\n{target}"

57 changes: 57 additions & 0 deletions generators/0046_permutations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# generators/0046_permutations.py
"""
Test Case Generator for Problem 0046 - Permutations

LeetCode Constraints:
- 1 <= nums.length <= 6
- -10 <= nums[i] <= 10
- All the integers of nums are unique
"""
import random
from typing import Iterator, Optional


def generate(count: int = 10, seed: Optional[int] = None) -> Iterator[str]:
"""
Generate test case inputs for Permutations.

Args:
count: Number of test cases to generate
seed: Random seed for reproducibility

Yields:
str: Test input in the format: nums (comma-separated)
"""
if seed is not None:
random.seed(seed)

# Edge cases first
edge_cases = [
"1", # Single element
"1,2", # Two elements
"1,2,3", # Classic example
"0,-1,1", # With negatives
"1,2,3,4,5,6", # Maximum length
]

for edge in edge_cases:
yield edge
count -= 1
if count <= 0:
return

# Random cases
for _ in range(count):
yield _generate_case()


def _generate_case() -> str:
"""Generate a single random test case with distinct integers."""
# Random length 1-6
n = random.randint(1, 6)

# Generate distinct integers in range [-10, 10]
nums = random.sample(range(-10, 11), n)

return ','.join(map(str, nums))

Loading