From f6667a80ecfb7d24ae4c16a37d4cc721e8140317 Mon Sep 17 00:00:00 2001
From: Wisaroot <66859294+wisarootl@users.noreply.github.com>
Date: Fri, 12 Sep 2025 23:27:54 +0700
Subject: [PATCH 01/58] test: add more test cases (#35)
---
.amazonq/rules/development-rules.md | 4 +-
.amazonq/rules/test-case-enhancement.md | 137 ++++++------------
.templates/leetcode/json/accounts_merge.json | 2 +-
.../leetcode/json/balanced_binary_tree.json | 2 +-
.../json/best_time_to_buy_and_sell_stock.json | 2 +-
.../json/binary_tree_right_side_view.json | 2 +-
.templates/leetcode/json/climbing_stairs.json | 2 +-
.templates/leetcode/json/coin_change.json | 2 +-
.templates/leetcode/json/combination_sum.json | 2 +-
.../json/container_with_most_water.json | 2 +-
.../leetcode/json/contains_duplicate.json | 2 +-
.templates/leetcode/json/course_schedule.json | 2 +-
.../json/diameter_of_binary_tree.json | 2 +-
.../evaluate_reverse_polish_notation.json | 2 +-
.../leetcode/json/first_bad_version.json | 2 +-
.templates/leetcode/json/flood_fill.json | 2 +-
.../json/implement_queue_using_stacks.json | 2 +-
.../json/implement_trie_prefix_tree.json | 4 +-
.templates/leetcode/json/insert_interval.json | 2 +-
.../leetcode/json/invert_binary_tree.json | 2 +-
.../json/k_closest_points_to_origin.json | 2 +-
.../json/kth_smallest_element_in_a_bst.json | 2 +-
.../leetcode/json/linked_list_cycle.json | 2 +-
...mmon_ancestor_of_a_binary_search_tree.json | 2 +-
...west_common_ancestor_of_a_binary_tree.json | 2 +-
.templates/leetcode/json/lru_cache.json | 2 +-
.../leetcode/json/majority_element.json | 2 +-
.../json/maximum_depth_of_binary_tree.json | 2 +-
.../maximum_profit_in_job_scheduling.json | 2 +-
.../leetcode/json/maximum_subarray.json | 2 +-
.templates/leetcode/json/merge_intervals.json | 2 +-
.../leetcode/json/merge_k_sorted_lists.json | 2 +-
.../leetcode/json/merge_two_sorted_lists.json | 2 +-
.../json/middle_of_the_linked_list.json | 2 +-
.templates/leetcode/json/min_stack.json | 2 +-
.../leetcode/json/minimum_height_trees.json | 2 +-
.../json/minimum_window_substring.json | 2 +-
.../leetcode/json/number_of_islands.json | 2 +-
.../json/partition_equal_subset_sum.json | 2 +-
.templates/leetcode/json/permutations.json | 2 +-
.../json/product_of_array_except_self.json | 2 +-
.../leetcode/json/reverse_linked_list.json | 2 +-
.../leetcode/json/reverse_linked_list_ii.json | 2 +-
.../json/search_in_rotated_sorted_array.json | 2 +-
...serialize_and_deserialize_binary_tree.json | 2 +-
.templates/leetcode/json/sort_colors.json | 2 +-
.templates/leetcode/json/spiral_matrix.json | 2 +-
.templates/leetcode/json/task_scheduler.json | 2 +-
.templates/leetcode/json/three_sum.json | 2 +-
.../leetcode/json/trapping_rain_water.json | 2 +-
.../leetcode/json/valid_palindrome.json | 2 +-
.../leetcode/json/valid_parentheses.json | 2 +-
.../json/validate_binary_search_tree.json | 2 +-
.templates/leetcode/json/word_break.json | 2 +-
.templates/leetcode/json/word_ladder.json | 2 +-
.templates/leetcode/json/zero_one_matrix.json | 2 +-
leetcode/accounts_merge/test_solution.py | 40 ++++-
.../balanced_binary_tree/test_solution.py | 7 +
.../test_solution.py | 7 +
.../test_solution.py | 16 +-
leetcode/climbing_stairs/test_solution.py | 20 ++-
leetcode/coin_change/test_solution.py | 6 +
leetcode/combination_sum/test_solution.py | 9 ++
.../test_solution.py | 16 +-
leetcode/contains_duplicate/test_solution.py | 15 +-
leetcode/course_schedule/test_solution.py | 7 +
.../diameter_of_binary_tree/test_solution.py | 15 +-
.../test_solution.py | 10 ++
leetcode/first_bad_version/test_solution.py | 5 +
leetcode/flood_fill/test_solution.py | 14 ++
.../test_solution.py | 37 +++++
.../test_solution.py | 87 +++++++++--
leetcode/insert_interval/test_solution.py | 7 +
leetcode/invert_binary_tree/test_solution.py | 16 +-
.../test_solution.py | 6 +
.../test_solution.py | 6 +
leetcode/linked_list_cycle/test_solution.py | 5 +
.../test_solution.py | 6 +
.../test_solution.py | 6 +
leetcode/lru_cache/test_solution.py | 50 +++++--
leetcode/majority_element/test_solution.py | 6 +
.../test_solution.py | 7 +
.../test_solution.py | 13 ++
leetcode/maximum_subarray/test_solution.py | 8 +
leetcode/merge_intervals/test_solution.py | 6 +
.../merge_k_sorted_lists/test_solution.py | 6 +
.../merge_two_sorted_lists/test_solution.py | 7 +
.../test_solution.py | 7 +
leetcode/min_stack/test_solution.py | 80 ++++++++++
.../minimum_height_trees/test_solution.py | 7 +
.../minimum_window_substring/test_solution.py | 6 +
leetcode/number_of_islands/test_solution.py | 12 ++
.../test_solution.py | 17 ++-
leetcode/permutations/test_solution.py | 36 +++++
.../test_solution.py | 8 +
leetcode/reverse_linked_list/test_solution.py | 5 +
.../reverse_linked_list_ii/test_solution.py | 6 +
.../test_solution.py | 6 +
.../test_solution.py | 8 +
leetcode/sort_colors/test_solution.py | 6 +
leetcode/spiral_matrix/test_solution.py | 7 +
leetcode/task_scheduler/test_solution.py | 15 +-
leetcode/three_sum/test_solution.py | 9 ++
leetcode/trapping_rain_water/test_solution.py | 8 +
leetcode/valid_palindrome/test_solution.py | 8 +
leetcode/valid_parentheses/test_solution.py | 10 ++
.../test_solution.py | 15 +-
leetcode/word_break/test_solution.py | 8 +
leetcode/word_ladder/test_solution.py | 111 ++++++++++++++
leetcode/zero_one_matrix/test_solution.py | 9 ++
poetry.lock | 78 +++++-----
111 files changed, 960 insertions(+), 239 deletions(-)
diff --git a/.amazonq/rules/development-rules.md b/.amazonq/rules/development-rules.md
index 671ffc8..aae1892 100644
--- a/.amazonq/rules/development-rules.md
+++ b/.amazonq/rules/development-rules.md
@@ -24,5 +24,7 @@ Each problem has:
- `README.md` - Problem description
- `solution.py` - Implementation with TODO placeholder
-- `tests.py` - Parametrized pytest tests
+- `test_solution.py` - Parametrized pytest tests
+- `helpers.py` - Test helper functions
+- `playground.ipynb` - Interactive Jupyter notebook
- `__init__.py` - Empty package file
diff --git a/.amazonq/rules/test-case-enhancement.md b/.amazonq/rules/test-case-enhancement.md
index 7a65e36..11b5019 100644
--- a/.amazonq/rules/test-case-enhancement.md
+++ b/.amazonq/rules/test-case-enhancement.md
@@ -1,107 +1,63 @@
# Test Case Enhancement Rules
-## Assistant Workflow for Adding Comprehensive Test Cases
+## Simple Enhancement Workflow
-When user requests to enhance test cases for a problem, the assistant will:
+When user requests test case enhancement:
-### 1. Problem Resolution (Priority Order)
+### 1. Problem Resolution
-- **FIRST**: Try to resolve from context - check active file path or user-provided problem name
-- **SECOND**: If context resolution fails, THEN run `poetry run python .templates/check_test_cases.py --threshold=10 --max=1` to auto-detect 1 problem with <10 test cases
-- **LAST**: If both above fail, ask user to explicitly specify problem name
+- Use active file context or user-provided problem name
+- If unclear, run: `poetry run python .templates/check_test_cases.py --threshold=10 --max=1`
-### 2. Test Case Generation
+### 2. Enhancement Process
-- Read `leetcode/{problem_name}/README.md` for problem understanding
-- Analyze existing test cases in `leetcode/{problem_name}/tests.py`
-- Generate comprehensive test cases covering:
- - **Edge cases**: Empty inputs, single elements, boundary values
- - **Corner cases**: Maximum/minimum constraints, special patterns
- - **Normal cases**: Typical scenarios with varied complexity
- - **Error cases**: Invalid inputs (if applicable)
-
-### 3. Initial Validation
-
-- Run `make p-test PROBLEM={problem_name}` to verify current implementation
-- **If errors found**:
- - DO NOT update implementation automatically
- - Only update test cases if they're incorrect
- - If implementation seems wrong, ASK USER first before modifying
-
-### 4. JSON Template Update
-
-- Update corresponding `.templates/leetcode/json/{problem_name}.json`
-- Add new test cases to `test_cases` field in proper format
-- Maintain existing test structure and naming conventions
-
-### 5. Backup and Regeneration Process
-
-- **Backup**: Move `leetcode/{problem_name}/` to `.cache/leetcode/{problem_name}/`
-- **Regenerate**: Run `make p-gen PROBLEM={problem_name} FORCE=1`
-- **Lint check**: Run `make p-lint PROBLEM={problem_name}`
-- **Iterate**: If lint fails, update JSON and regenerate until passes
+```bash
+# Simple 4-step process:
+# 1. Update JSON template with more test cases (12-15 total)
+# 2. Backup original
+mv leetcode/{problem_name} .cache/leetcode/{problem_name}
+# 3. Regenerate with enhanced tests
+make p-gen PROBLEM={problem_name} FORCE=1 && make p-lint PROBLEM={problem_name}
+# 4. Restore original solution, keep enhanced tests
+cp .cache/leetcode/{problem_name}/solution.py leetcode/{problem_name}/solution.py
+```
-### 6. Solution Preservation
+### 3. Verification
-- Copy `solution.py` from backup to newly generated structure
-- Run `make p-test PROBLEM={problem_name}` to verify tests pass
-- **If tests fail**: Go back to step 4, update JSON, and iterate until passes
+- Run `make p-test PROBLEM={problem_name}`
+- Fix any incorrect expected values in test cases
+- Update JSON template with corrections
-### 7. Cleanup and Restore
+### 4. Restore Backup
-- **CRITICAL**: Remove entire newly generated `leetcode/{problem_name}/` directory
-- **CRITICAL**: Restore original structure from `.cache/leetcode/{problem_name}/` backup
-- **CRITICAL**: Only THEN copy enhanced `test_solution.py` from generated files to restored structure
-- **CRITICAL**: Preserve existing solution class parametrization - if original test had multiple solution classes, restore them
-- Verify final state with `make p-test PROBLEM={problem_name}`
-- Clean up backup directory after successful verification
+```bash
+# Copy enhanced test_solution.py to backup
+cp leetcode/{problem_name}/test_solution.py .cache/leetcode/{problem_name}/
+# Restore all original files (preserves user edits)
+rm -rf leetcode/{problem_name}
+mv .cache/leetcode/{problem_name} leetcode/{problem_name}
+```
-## Test Case Quality Standards
+## Test Case Standards
### Coverage Requirements
-- **Minimum 10 test cases** per problem
-- **Edge cases**: 20-30% of total test cases
-- **Normal cases**: 50-60% of total test cases
-- **Corner cases**: 20-30% of total test cases
+- **Minimum 12 test cases** per problem
+- **Edge cases**: Empty inputs, single elements, boundary values
+- **Corner cases**: Maximum/minimum constraints, duplicates, sorted arrays
+- **Normal cases**: Mixed scenarios with varied complexity
-### Test Case Categories
+### JSON Format
-#### Edge Cases
-
-- Empty inputs: `[]`, `""`, `None`
-- Single element: `[1]`, `"a"`
-- Boundary values: `[0]`, `[1]`, `[-1]`
-- Maximum/minimum constraints from problem description
-
-#### Corner Cases
-
-- Duplicate elements: `[1,1,1]`
-- Sorted/reverse sorted arrays: `[1,2,3]`, `[3,2,1]`
-- All same elements: `[5,5,5,5]`
-- Alternating patterns: `[1,0,1,0]`
-
-#### Normal Cases
-
-- Mixed positive/negative numbers
-- Various array sizes within constraints
-- Different data patterns and structures
-- Representative problem scenarios
-
-### JSON Format Requirements
-
-- Use single quotes for Python strings in test cases
+- Use single quotes for Python strings: `'hello'` not `"hello"`
- Follow existing parametrize format
-- Maintain type hints in parametrize_typed
-- Ensure test_cases string is valid Python list syntax
-- **NEVER include custom solution classes** in test_imports - only import the main solution class specified in solution_class_name
-- **PRESERVE existing solution class parametrization** - if original test had multiple solution classes, restore them after JSON regeneration
+- Ensure valid Python list syntax in test_cases field
-## Commands Reference
+## Quick Commands
```bash
-# Find problems needing more test cases
-poetry run python .templates/check_test_cases.py --threshold=10 --max=1
+# Find problems needing enhancement
+poetry run python .templates/check_test_cases.py --threshold=10
# Test specific problem
make p-test PROBLEM={problem_name}
@@ -109,21 +65,14 @@ make p-test PROBLEM={problem_name}
# Generate from JSON template
make p-gen PROBLEM={problem_name} FORCE=1
-# Lint specific problem
+# Lint check
make p-lint PROBLEM={problem_name}
```
-## Error Handling
-
-- **Implementation errors**: Ask user before modifying solution code
-- **Test failures**: Update JSON template and regenerate
-- **Lint failures**: Fix JSON format and iterate
-- **Backup failures**: Ensure `.cache/leetcode/` directory exists
-
## Success Criteria
- All tests pass with enhanced test cases
-- Minimum 10 comprehensive test cases per problem
-- Original solution code preserved and working
+- Minimum 12 comprehensive test cases per problem
+- Original solution code preserved
+- **Enhanced test cases in final test_solution.py**
- JSON template updated for future regeneration
-- Clean final state with no temporary files
diff --git a/.templates/leetcode/json/accounts_merge.json b/.templates/leetcode/json/accounts_merge.json
index 436e531..bcbddb6 100644
--- a/.templates/leetcode/json/accounts_merge.json
+++ b/.templates/leetcode/json/accounts_merge.json
@@ -40,7 +40,7 @@
"name": "test_accounts_merge",
"signature": "(self, accounts: list[list[str]], expected: list[list[str]])",
"parametrize": "accounts, expected",
- "test_cases": "[([[\"John\", \"johnsmith@mail.com\", \"john_newyork@mail.com\"], [\"John\", \"johnsmith@mail.com\", \"john00@mail.com\"], [\"Mary\", \"mary@mail.com\"], [\"John\", \"johnnybravo@mail.com\"]], [[\"John\", \"john00@mail.com\", \"john_newyork@mail.com\", \"johnsmith@mail.com\"], [\"Mary\", \"mary@mail.com\"], [\"John\", \"johnnybravo@mail.com\"]]), ([[\"Gabe\", \"Gabe0@m.co\", \"Gabe3@m.co\", \"Gabe1@m.co\"], [\"Kevin\", \"Kevin3@m.co\", \"Kevin5@m.co\", \"Kevin0@m.co\"], [\"Ethan\", \"Ethan5@m.co\", \"Ethan4@m.co\", \"Ethan0@m.co\"], [\"Hanzo\", \"Hanzo3@m.co\", \"Hanzo1@m.co\", \"Hanzo0@m.co\"], [\"Fern\", \"Fern5@m.co\", \"Fern1@m.co\", \"Fern0@m.co\"]], [[\"Ethan\", \"Ethan0@m.co\", \"Ethan4@m.co\", \"Ethan5@m.co\"], [\"Gabe\", \"Gabe0@m.co\", \"Gabe1@m.co\", \"Gabe3@m.co\"], [\"Hanzo\", \"Hanzo0@m.co\", \"Hanzo1@m.co\", \"Hanzo3@m.co\"], [\"Kevin\", \"Kevin0@m.co\", \"Kevin3@m.co\", \"Kevin5@m.co\"], [\"Fern\", \"Fern0@m.co\", \"Fern1@m.co\", \"Fern5@m.co\"]]), ([[\"John\", \"john@mail.com\"]], [[\"John\", \"john@mail.com\"]]), ([[\"John\"]], [[\"John\"]]), ([[\"John\", \"john1@mail.com\"], [\"John\", \"john2@mail.com\"], [\"John\", \"john3@mail.com\"]], [[\"John\", \"john1@mail.com\"], [\"John\", \"john2@mail.com\"], [\"John\", \"john3@mail.com\"]]), ([[\"John\", \"a@mail.com\", \"b@mail.com\"], [\"John\", \"b@mail.com\", \"c@mail.com\"], [\"John\", \"d@mail.com\"]], [[\"John\", \"a@mail.com\", \"b@mail.com\", \"c@mail.com\"], [\"John\", \"d@mail.com\"]]), ([[\"Alice\", \"alice@mail.com\", \"alice1@mail.com\"], [\"Alice\", \"alice2@mail.com\", \"alice3@mail.com\"], [\"Alice\", \"alice1@mail.com\", \"alice2@mail.com\"]], [[\"Alice\", \"alice1@mail.com\", \"alice2@mail.com\", \"alice3@mail.com\", \"alice@mail.com\"]]), ([[\"John\", \"shared@mail.com\"], [\"Jane\", \"shared@mail.com\"]], [[\"John\", \"shared@mail.com\"]])]",
+ "test_cases": "[([[\"John\", \"johnsmith@mail.com\", \"john_newyork@mail.com\"], [\"John\", \"johnsmith@mail.com\", \"john00@mail.com\"], [\"Mary\", \"mary@mail.com\"], [\"John\", \"johnnybravo@mail.com\"]], [[\"John\", \"john00@mail.com\", \"john_newyork@mail.com\", \"johnsmith@mail.com\"], [\"Mary\", \"mary@mail.com\"], [\"John\", \"johnnybravo@mail.com\"]]), ([[\"Gabe\", \"Gabe0@m.co\", \"Gabe3@m.co\", \"Gabe1@m.co\"], [\"Kevin\", \"Kevin3@m.co\", \"Kevin5@m.co\", \"Kevin0@m.co\"], [\"Ethan\", \"Ethan5@m.co\", \"Ethan4@m.co\", \"Ethan0@m.co\"], [\"Hanzo\", \"Hanzo3@m.co\", \"Hanzo1@m.co\", \"Hanzo0@m.co\"], [\"Fern\", \"Fern5@m.co\", \"Fern1@m.co\", \"Fern0@m.co\"]], [[\"Ethan\", \"Ethan0@m.co\", \"Ethan4@m.co\", \"Ethan5@m.co\"], [\"Gabe\", \"Gabe0@m.co\", \"Gabe1@m.co\", \"Gabe3@m.co\"], [\"Hanzo\", \"Hanzo0@m.co\", \"Hanzo1@m.co\", \"Hanzo3@m.co\"], [\"Kevin\", \"Kevin0@m.co\", \"Kevin3@m.co\", \"Kevin5@m.co\"], [\"Fern\", \"Fern0@m.co\", \"Fern1@m.co\", \"Fern5@m.co\"]]), ([[\"John\", \"john@mail.com\"]], [[\"John\", \"john@mail.com\"]]), ([[\"John\", \"john1@mail.com\"], [\"John\", \"john2@mail.com\"], [\"John\", \"john3@mail.com\"]], [[\"John\", \"john1@mail.com\"], [\"John\", \"john2@mail.com\"], [\"John\", \"john3@mail.com\"]]), ([[\"John\", \"a@mail.com\", \"b@mail.com\"], [\"John\", \"b@mail.com\", \"c@mail.com\"], [\"John\", \"d@mail.com\"]], [[\"John\", \"a@mail.com\", \"b@mail.com\", \"c@mail.com\"], [\"John\", \"d@mail.com\"]]), ([[\"Alice\", \"alice@mail.com\", \"alice1@mail.com\"], [\"Alice\", \"alice2@mail.com\", \"alice3@mail.com\"], [\"Alice\", \"alice1@mail.com\", \"alice2@mail.com\"]], [[\"Alice\", \"alice1@mail.com\", \"alice2@mail.com\", \"alice3@mail.com\", \"alice@mail.com\"]]), ([[\"Bob\", \"bob@mail.com\"], [\"Bob\", \"bob@mail.com\"]], [[\"Bob\", \"bob@mail.com\"]]), ([[\"David\", \"david1@mail.com\", \"david2@mail.com\"], [\"David\", \"david3@mail.com\"], [\"David\", \"david2@mail.com\", \"david4@mail.com\"]], [[\"David\", \"david1@mail.com\", \"david2@mail.com\", \"david4@mail.com\"], [\"David\", \"david3@mail.com\"]]), ([[\"Alex\", \"alex@mail.com\"], [\"Alex\", \"alex@mail.com\", \"alex2@mail.com\"], [\"Alex\", \"alex3@mail.com\"]], [[\"Alex\", \"alex2@mail.com\", \"alex@mail.com\"], [\"Alex\", \"alex3@mail.com\"]]), ([[\"Tom\", \"tom1@mail.com\"], [\"Tom\", \"tom2@mail.com\"], [\"Tom\", \"tom3@mail.com\"], [\"Tom\", \"tom4@mail.com\"]], [[\"Tom\", \"tom1@mail.com\"], [\"Tom\", \"tom2@mail.com\"], [\"Tom\", \"tom3@mail.com\"], [\"Tom\", \"tom4@mail.com\"]]), ([[\"Sam\", \"sam@mail.com\", \"sam1@mail.com\", \"sam2@mail.com\"]], [[\"Sam\", \"sam@mail.com\", \"sam1@mail.com\", \"sam2@mail.com\"]])]",
"body": " result = run_accounts_merge(Solution, accounts)\n assert_accounts_merge(result, expected)"
}
],
diff --git a/.templates/leetcode/json/balanced_binary_tree.json b/.templates/leetcode/json/balanced_binary_tree.json
index 1d9955d..c413c49 100644
--- a/.templates/leetcode/json/balanced_binary_tree.json
+++ b/.templates/leetcode/json/balanced_binary_tree.json
@@ -53,7 +53,7 @@
"name": "test_is_balanced",
"signature": "(self, root_list: list[int | None], expected: bool)",
"parametrize": "root_list, expected",
- "test_cases": "[([3, 9, 20, None, None, 15, 7], True), ([1, 2, 2, 3, 3, None, None, 4, 4], False), ([], True), ([1], True), ([1, 2], True), ([1, None, 2], True), ([1, 2, 3, 4], True), ([1, 2, 2, 3, None, None, 3, 4, None, None, 4], False)]",
+ "test_cases": "[([3, 9, 20, None, None, 15, 7], True), ([1, 2, 2, 3, 3, None, None, 4, 4], False), ([], True), ([1], True), ([1, 2], True), ([1, None, 2], True), ([1, 2, 3, 4], True), ([1, 2, 2, 3, None, None, 3, 4, None, None, 4], False), ([1, 2, 3], True), ([1, 2, None, 3], False), ([1, None, 2, None, 3], False), ([1, 2, 3, 4, 5, 6, 7], True), ([1, 2, 3, None, None, 4, None, None, 5], False), ([5, 1, 4, None, None, 3, 6], True), ([1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, None, None, 5, 5], True)]",
"body": " result = run_is_balanced(Solution, root_list)\n assert_is_balanced(result, expected)"
}
]
diff --git a/.templates/leetcode/json/best_time_to_buy_and_sell_stock.json b/.templates/leetcode/json/best_time_to_buy_and_sell_stock.json
index 1cd4038..0c86cdb 100644
--- a/.templates/leetcode/json/best_time_to_buy_and_sell_stock.json
+++ b/.templates/leetcode/json/best_time_to_buy_and_sell_stock.json
@@ -52,7 +52,7 @@
"name": "test_max_profit",
"signature": "(self, prices: list[int], expected: int)",
"parametrize": "prices, expected",
- "test_cases": "[([7, 1, 5, 3, 6, 4], 5), ([7, 6, 4, 3, 1], 0), ([1, 2, 3, 4, 5], 4), ([5, 4, 3, 2, 1], 0), ([1], 0), ([2, 1], 0), ([1, 2], 1), ([3, 2, 6, 5, 0, 3], 4)]",
+ "test_cases": "[([7, 1, 5, 3, 6, 4], 5), ([7, 6, 4, 3, 1], 0), ([1, 2, 3, 4, 5], 4), ([5, 4, 3, 2, 1], 0), ([1], 0), ([2, 1], 0), ([1, 2], 1), ([3, 2, 6, 5, 0, 3], 4), ([2, 4, 1], 2), ([1, 5, 3, 6, 4], 5), ([10, 1, 5, 6, 7, 1], 6), ([6, 1, 3, 2, 4, 7], 6), ([1, 4, 2], 3), ([3, 3, 5, 0, 0, 3, 1, 4], 4), ([2, 1, 2, 1, 0, 1, 2], 2)]",
"body": " result = run_max_profit(Solution, prices)\n assert_max_profit(result, expected)"
}
]
diff --git a/.templates/leetcode/json/binary_tree_right_side_view.json b/.templates/leetcode/json/binary_tree_right_side_view.json
index 56eba70..2607777 100644
--- a/.templates/leetcode/json/binary_tree_right_side_view.json
+++ b/.templates/leetcode/json/binary_tree_right_side_view.json
@@ -54,7 +54,7 @@
"name": "test_right_side_view",
"signature": "(self, root_list: list[int | None], expected: list[int])",
"parametrize": "root_list, expected",
- "test_cases": "[([1, 2, 3, None, 5, None, 4], [1, 3, 4]), ([1, 2, 3, 4, None, None, None, 5], [1, 3, 4, 5]), ([1, None, 3], [1, 3]), ([], []), ([1], [1]), ([1, 2], [1, 2]), ([1, None, 2], [1, 2])]",
+ "test_cases": "[([1, 2, 3, None, 5, None, 4], [1, 3, 4]), ([1, 2, 3, 4, None, None, None, 5], [1, 3, 4, 5]), ([1, None, 3], [1, 3]), ([], []), ([1], [1]), ([1, 2], [1, 2]), ([1, None, 2], [1, 2]), ([1, 2, 3], [1, 3]), ([1, 2, None, 4], [1, 2, 4]), ([1, 2, 3, 4, 5, 6, 7], [1, 3, 7]), ([1, 2, 3, None, None, 4, 5], [1, 3, 5]), ([5, 4, 6, None, None, None, 7], [5, 6, 7]), ([1, 2, 3, 4, 5, None, None, 8], [1, 3, 5, 8]), ([10, 5, 15, None, 6, 12, 20], [10, 15, 20])]",
"body": " result = run_right_side_view(Solution, root_list)\n assert_right_side_view(result, expected)"
}
]
diff --git a/.templates/leetcode/json/climbing_stairs.json b/.templates/leetcode/json/climbing_stairs.json
index 8dcb90b..c5a1375 100644
--- a/.templates/leetcode/json/climbing_stairs.json
+++ b/.templates/leetcode/json/climbing_stairs.json
@@ -52,7 +52,7 @@
"name": "test_climb_stairs",
"signature": "(self, n: int, expected: int)",
"parametrize": "n, expected",
- "test_cases": "[(1, 1), (2, 2), (3, 3), (4, 5), (5, 8), (6, 13), (10, 89), (20, 10946), (45, 1836311903)]",
+ "test_cases": "[(1, 1), (2, 2), (3, 3), (4, 5), (5, 8), (6, 13), (7, 21), (8, 34), (9, 55), (10, 89), (15, 987), (20, 10946), (25, 121393), (30, 1346269), (35, 14930352), (40, 165580141), (45, 1836311903)]",
"body": " result = run_climb_stairs(Solution, n)\n assert_climb_stairs(result, expected)"
}
]
diff --git a/.templates/leetcode/json/coin_change.json b/.templates/leetcode/json/coin_change.json
index 7702878..480f745 100644
--- a/.templates/leetcode/json/coin_change.json
+++ b/.templates/leetcode/json/coin_change.json
@@ -51,7 +51,7 @@
"name": "test_coin_change",
"signature": "(self, coins: list[int], amount: int, expected: int)",
"parametrize": "coins, amount, expected",
- "test_cases": "[([1, 2, 5], 11, 3), ([2], 3, -1), ([1], 0, 0), ([1, 3, 4], 6, 2), ([2, 5, 10, 1], 27, 4), ([5], 3, -1), ([1], 1, 1), ([1, 2], 2, 1), ([186, 419, 83, 408], 6249, 20)]",
+ "test_cases": "[([1, 2, 5], 11, 3), ([2], 3, -1), ([1], 0, 0), ([1, 3, 4], 6, 2), ([2, 5, 10, 1], 27, 4), ([5], 3, -1), ([1], 1, 1), ([1, 2], 2, 1), ([186, 419, 83, 408], 6249, 20), ([1, 5, 10, 25], 30, 2), ([2, 3, 5], 9, 3), ([1, 4, 5], 8, 2), ([3, 5], 1, -1), ([1, 2, 5], 100, 20), ([7, 11], 14, 2)]",
"body": " result = run_coin_change(Solution, coins, amount)\n assert_coin_change(result, expected)"
}
]
diff --git a/.templates/leetcode/json/combination_sum.json b/.templates/leetcode/json/combination_sum.json
index d7f7e64..44610a1 100644
--- a/.templates/leetcode/json/combination_sum.json
+++ b/.templates/leetcode/json/combination_sum.json
@@ -53,7 +53,7 @@
"name": "test_combination_sum",
"signature": "(self, candidates: list[int], target: int, expected: list[list[int]])",
"parametrize": "candidates, target, expected",
- "test_cases": "[([2, 3, 6, 7], 7, [[2, 2, 3], [7]]), ([2, 3, 5], 8, [[2, 2, 2, 2], [2, 3, 3], [3, 5]]), ([2], 1, [])]",
+ "test_cases": "[([2, 3, 6, 7], 7, [[2, 2, 3], [7]]), ([2, 3, 5], 8, [[2, 2, 2, 2], [2, 3, 3], [3, 5]]), ([2], 1, []), ([2, 3], 1, []), ([3, 5], 3, [[3]]), ([2, 4], 6, [[2, 2, 2], [2, 4]]), ([5], 5, [[5]]), ([2, 3, 4], 6, [[2, 2, 2], [2, 4], [3, 3]]), ([4, 2, 8], 8, [[2, 2, 2, 2], [2, 2, 4], [4, 4], [8]]), ([3, 4, 5], 9, [[3, 3, 3], [4, 5]]), ([6, 3, 2], 6, [[2, 2, 2], [3, 3], [6]]), ([2, 7], 9, [[2, 7]])]",
"body": " result = run_combination_sum(Solution, candidates, target)\n assert_combination_sum(result, expected)"
}
]
diff --git a/.templates/leetcode/json/container_with_most_water.json b/.templates/leetcode/json/container_with_most_water.json
index 604d452..f07668b 100644
--- a/.templates/leetcode/json/container_with_most_water.json
+++ b/.templates/leetcode/json/container_with_most_water.json
@@ -50,7 +50,7 @@
"name": "test_max_area",
"signature": "(self, height: list[int], expected: int)",
"parametrize": "height, expected",
- "test_cases": "[([1,8,6,2,5,4,8,3,7], 49), ([1,1], 1), ([1,2,1], 2)]",
+ "test_cases": "[([1,8,6,2,5,4,8,3,7], 49), ([1,1], 1), ([1,2,1], 2), ([2,1], 1), ([1,2,4,3], 4), ([1,3,2,5,25,24,5], 24), ([2,3,4,5,18,17,6], 17), ([1,2,3,4,5], 6), ([5,4,3,2,1], 6), ([0,2], 0), ([3,9,3,4,7,2,12,6], 45), ([1,0,0,0,0,0,0,2,2], 8)]",
"body": " result = run_max_area(Solution, height)\n assert_max_area(result, expected)"
}
]
diff --git a/.templates/leetcode/json/contains_duplicate.json b/.templates/leetcode/json/contains_duplicate.json
index 8b540d0..0601beb 100644
--- a/.templates/leetcode/json/contains_duplicate.json
+++ b/.templates/leetcode/json/contains_duplicate.json
@@ -53,7 +53,7 @@
"name": "test_contains_duplicate",
"signature": "(self, nums: list[int], expected: bool)",
"parametrize": "nums, expected",
- "test_cases": "[([1, 2, 3, 1], True), ([1, 2, 3, 4], False), ([1, 1, 1, 3, 3, 4, 3, 2, 4, 2], True)]",
+ "test_cases": "[([1, 2, 3, 1], True), ([1, 2, 3, 4], False), ([1, 1, 1, 3, 3, 4, 3, 2, 4, 2], True), ([1], False), ([1, 1], True), ([0, 0], True), ([-1, -1], True), ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], False), ([10, 9, 8, 7, 6, 5, 4, 3, 2, 1], False), ([1, 2, 3, 4, 5, 1], True), ([-1000000000, 1000000000, -1000000000], True), ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0], True)]",
"body": " result = run_contains_duplicate(Solution, nums)\n assert_contains_duplicate(result, expected)"
}
]
diff --git a/.templates/leetcode/json/course_schedule.json b/.templates/leetcode/json/course_schedule.json
index f04589d..f02e646 100644
--- a/.templates/leetcode/json/course_schedule.json
+++ b/.templates/leetcode/json/course_schedule.json
@@ -52,7 +52,7 @@
"name": "test_can_finish",
"signature": "(self, num_courses: int, prerequisites: list[list[int]], expected: bool)",
"parametrize": "num_courses, prerequisites, expected",
- "test_cases": "[(2, [[1, 0]], True), (2, [[1, 0], [0, 1]], False), (1, [], True), (3, [[1, 0], [2, 1]], True), (4, [[1, 0], [2, 1], [3, 2], [1, 3]], False)]",
+ "test_cases": "[(2, [[1, 0]], True), (2, [[1, 0], [0, 1]], False), (1, [], True), (3, [[1, 0], [2, 1]], True), (4, [[1, 0], [2, 1], [3, 2], [1, 3]], False), (3, [[0, 1], [0, 2], [1, 2]], True), (4, [[0, 1], [1, 2], [2, 3], [3, 1]], False), (6, [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5]], True), (3, [[1, 0], [2, 0]], True), (5, [[0, 1], [1, 2], [2, 3], [3, 4], [4, 0]], False), (4, [[1, 0], [2, 0], [3, 1], [3, 2]], True), (5, [[1, 0], [2, 1], [3, 2], [4, 3], [0, 4]], False)]",
"body": " result = run_can_finish(Solution, num_courses, prerequisites)\n assert_can_finish(result, expected)"
}
]
diff --git a/.templates/leetcode/json/diameter_of_binary_tree.json b/.templates/leetcode/json/diameter_of_binary_tree.json
index 37ca4c0..0eec11f 100644
--- a/.templates/leetcode/json/diameter_of_binary_tree.json
+++ b/.templates/leetcode/json/diameter_of_binary_tree.json
@@ -50,7 +50,7 @@
"name": "test_diameter_of_binary_tree",
"signature": "(self, root_list: list[int | None], expected: int)",
"parametrize": "root_list, expected",
- "test_cases": "[([1, 2, 3, 4, 5], 3), ([1, 2], 1), ([], 0), ([1], 0), ([1, 2, 3], 2), ([1, None, 2], 1)]",
+ "test_cases": "[([1, 2, 3, 4, 5], 3), ([1, 2], 1), ([], 0), ([1], 0), ([1, 2, 3], 2), ([1, None, 2], 1), ([1, 2, 3, 4, 5, None, None, 6, 7], 4), ([4, 2, 6, 1, 3, 5, 7], 4), ([1, 2, None, 3, None, 4], 3), ([1, 2, 3, None, None, 4, 5, None, None, 6, 7], 4), ([10, 5, 15, 3, 7, 12, 20], 4), ([1, None, 2, None, 3, None, 4], 3)]",
"body": " result = run_diameter_of_binary_tree(Solution, root_list)\n assert_diameter_of_binary_tree(result, expected)"
}
]
diff --git a/.templates/leetcode/json/evaluate_reverse_polish_notation.json b/.templates/leetcode/json/evaluate_reverse_polish_notation.json
index 781c301..7d4e83d 100644
--- a/.templates/leetcode/json/evaluate_reverse_polish_notation.json
+++ b/.templates/leetcode/json/evaluate_reverse_polish_notation.json
@@ -55,7 +55,7 @@
"name": "test_eval_rpn",
"signature": "(self, tokens: list[str], expected: int)",
"parametrize": "tokens, expected",
- "test_cases": "[(['2', '1', '+', '3', '*'], 9), (['4', '13', '5', '/', '+'], 6), (['10', '6', '9', '3', '+', '-11', '*', '/', '*', '17', '+', '5', '+'], 22)]",
+ "test_cases": "[(['2', '1', '+', '3', '*'], 9), (['4', '13', '5', '/', '+'], 6), (['10', '6', '9', '3', '+', '-11', '*', '/', '*', '17', '+', '5', '+'], 22), (['3'], 3), (['15', '7', '1', '1', '+', '-', '/', '3', '*', '2', '1', '1', '+', '+', '-'], 5), (['2', '1', '+'], 3), (['2', '1', '-'], 1), (['3', '4', '*'], 12), (['8', '2', '/'], 4), (['5', '1', '2', '+', '4', '*', '+', '3', '-'], 14), (['-1', '2', '+'], 1), (['0', '3', '/'], 0), (['18', '6', '/', '3', '/'], 1)]",
"body": " result = run_eval_rpn(Solution, tokens)\n assert_eval_rpn(result, expected)"
}
]
diff --git a/.templates/leetcode/json/first_bad_version.json b/.templates/leetcode/json/first_bad_version.json
index 20b50af..0b30e0b 100644
--- a/.templates/leetcode/json/first_bad_version.json
+++ b/.templates/leetcode/json/first_bad_version.json
@@ -55,7 +55,7 @@
"name": "test_first_bad_version",
"signature": "(self, n: int, bad: int, expected: int)",
"parametrize": "n, bad, expected",
- "test_cases": "[(5, 4, 4), (1, 1, 1), (3, 1, 1), (10, 7, 7), (100, 50, 50), (2, 1, 1), (2, 2, 2), (1000, 1, 1), (1000, 999, 999), (1000, 500, 500)]",
+ "test_cases": "[(5, 4, 4), (1, 1, 1), (3, 1, 1), (10, 7, 7), (100, 50, 50), (2, 1, 1), (2, 2, 2), (1000, 1, 1), (1000, 999, 999), (1000, 500, 500), (20, 15, 15), (50, 25, 25), (8, 3, 3), (16, 9, 9), (200, 150, 150)]",
"body": " result = run_first_bad_version(Solution, n, bad)\n assert_first_bad_version(result, expected)"
}
]
diff --git a/.templates/leetcode/json/flood_fill.json b/.templates/leetcode/json/flood_fill.json
index 4c660d1..a889a3d 100644
--- a/.templates/leetcode/json/flood_fill.json
+++ b/.templates/leetcode/json/flood_fill.json
@@ -52,7 +52,7 @@
"name": "test_flood_fill",
"signature": "(self, image: list[list[int]], sr: int, sc: int, color: int, expected: list[list[int]])",
"parametrize": "image, sr, sc, color, expected",
- "test_cases": "[([[1, 1, 1], [1, 1, 0], [1, 0, 1]], 1, 1, 2, [[2, 2, 2], [2, 2, 0], [2, 0, 1]]), ([[0, 0, 0], [0, 0, 0]], 0, 0, 0, [[0, 0, 0], [0, 0, 0]]), ([[0, 0, 0], [0, 1, 1]], 1, 1, 1, [[0, 0, 0], [0, 1, 1]]), ([[1, 1, 1], [1, 1, 0], [1, 0, 1]], 1, 1, 1, [[1, 1, 1], [1, 1, 0], [1, 0, 1]])]",
+ "test_cases": "[([[1, 1, 1], [1, 1, 0], [1, 0, 1]], 1, 1, 2, [[2, 2, 2], [2, 2, 0], [2, 0, 1]]), ([[0, 0, 0], [0, 0, 0]], 0, 0, 0, [[0, 0, 0], [0, 0, 0]]), ([[0, 0, 0], [0, 1, 1]], 1, 1, 1, [[0, 0, 0], [0, 1, 1]]), ([[1, 1, 1], [1, 1, 0], [1, 0, 1]], 1, 1, 1, [[1, 1, 1], [1, 1, 0], [1, 0, 1]]), ([[1]], 0, 0, 2, [[2]]), ([[0, 1], [1, 0]], 0, 0, 3, [[3, 1], [1, 0]]), ([[1, 1], [1, 1]], 0, 0, 2, [[2, 2], [2, 2]]), ([[0, 1, 0], [1, 0, 1], [0, 1, 0]], 1, 1, 2, [[0, 1, 0], [1, 2, 1], [0, 1, 0]]), ([[2, 2, 2], [2, 2, 0], [2, 0, 1]], 0, 0, 3, [[3, 3, 3], [3, 3, 0], [3, 0, 1]]), ([[1, 0, 1], [0, 1, 0], [1, 0, 1]], 1, 1, 5, [[1, 0, 1], [0, 5, 0], [1, 0, 1]]), ([[0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0]], 1, 1, 2, [[0, 0, 0, 0], [0, 2, 2, 0], [0, 2, 2, 0], [0, 0, 0, 0]]), ([[1, 2, 3], [4, 5, 6], [7, 8, 9]], 1, 1, 0, [[1, 2, 3], [4, 0, 6], [7, 8, 9]])]",
"body": " result = run_flood_fill(Solution, image, sr, sc, color)\n assert_flood_fill(result, expected)"
}
]
diff --git a/.templates/leetcode/json/implement_queue_using_stacks.json b/.templates/leetcode/json/implement_queue_using_stacks.json
index a412491..f2adeb5 100644
--- a/.templates/leetcode/json/implement_queue_using_stacks.json
+++ b/.templates/leetcode/json/implement_queue_using_stacks.json
@@ -67,7 +67,7 @@
"name": "test_queue_operations",
"signature": "(self, operations: list[str], inputs: list[list[int]], expected: list[int | None | bool])",
"parametrize": "operations, inputs, expected",
- "test_cases": "[(['MyQueue', 'push', 'push', 'peek', 'pop', 'empty'], [[], [1], [2], [], [], []], [None, None, None, 1, 1, False]), (['MyQueue', 'empty', 'push', 'peek', 'pop', 'empty'], [[], [], [1], [], [], []], [None, True, None, 1, 1, True]), (['MyQueue', 'push', 'push', 'push', 'pop', 'pop', 'peek', 'pop', 'empty'], [[], [1], [2], [3], [], [], [], [], []], [None, None, None, None, 1, 2, 3, 3, True])]",
+ "test_cases": "[(['MyQueue', 'push', 'push', 'peek', 'pop', 'empty'], [[], [1], [2], [], [], []], [None, None, None, 1, 1, False]), (['MyQueue', 'empty', 'push', 'peek', 'pop', 'empty'], [[], [], [1], [], [], []], [None, True, None, 1, 1, True]), (['MyQueue', 'push', 'push', 'push', 'pop', 'pop', 'peek', 'pop', 'empty'], [[], [1], [2], [3], [], [], [], [], []], [None, None, None, None, 1, 2, 3, 3, True]), (['MyQueue', 'push', 'peek', 'pop'], [[], [5], [], []], [None, None, 5, 5]), (['MyQueue', 'push', 'push', 'pop', 'push', 'peek'], [[], [1], [2], [], [3], []], [None, None, None, 1, None, 2]), (['MyQueue', 'empty'], [[], []], [None, True]), (['MyQueue', 'push', 'push', 'push', 'push', 'pop', 'pop', 'pop', 'pop', 'empty'], [[], [1], [2], [3], [4], [], [], [], [], []], [None, None, None, None, None, 1, 2, 3, 4, True]), (['MyQueue', 'push', 'pop', 'push', 'pop', 'empty'], [[], [7], [], [8], [], []], [None, None, 7, None, 8, True]), (['MyQueue', 'push', 'push', 'peek', 'peek', 'pop', 'peek'], [[], [9], [8], [], [], [], []], [None, None, None, 9, 9, 9, 8]), (['MyQueue', 'push', 'push', 'push', 'push', 'push', 'pop', 'pop', 'pop', 'push', 'peek'], [[], [1], [2], [3], [4], [5], [], [], [], [6], []], [None, None, None, None, None, None, 1, 2, 3, None, 4]), (['MyQueue', 'push', 'empty', 'pop', 'empty', 'push', 'empty'], [[], [1], [], [], [], [2], []], [None, None, False, 1, True, None, False]), (['MyQueue', 'push', 'push', 'push', 'pop', 'push', 'pop', 'pop', 'push', 'pop'], [[], [1], [2], [3], [], [4], [], [], [5], []], [None, None, None, None, 1, None, 2, 3, None, 4])]",
"body": " result, _ = run_my_queue(MyQueue, operations, inputs)\n assert_my_queue(result, expected)"
}
]
diff --git a/.templates/leetcode/json/implement_trie_prefix_tree.json b/.templates/leetcode/json/implement_trie_prefix_tree.json
index dcc8fa0..c800080 100644
--- a/.templates/leetcode/json/implement_trie_prefix_tree.json
+++ b/.templates/leetcode/json/implement_trie_prefix_tree.json
@@ -20,7 +20,7 @@
"helpers_content": "",
"helpers_run_name": "trie_operations",
"helpers_run_signature": "(solution_class: type, operations: list[str], inputs: list[list[str]])",
- "helpers_run_body": " trie = None\n results: list[bool | None] = []\n for i, op in enumerate(operations):\n if op == 'Trie':\n trie = solution_class()\n results.append(None)\n elif op == 'insert' and trie is not None:\n trie.insert(inputs[i][0])\n results.append(None)\n elif op == 'search' and trie is not None:\n results.append(trie.search(inputs[i][0]))\n elif op == 'starts_with' and trie is not None:\n results.append(trie.starts_with(inputs[i][0]))\n return results, trie",
+ "helpers_run_body": " trie = None\n results: list[bool | None] = []\n for i, op in enumerate(operations):\n if op == 'Trie':\n trie = solution_class()\n results.append(None)\n elif op == 'insert' and trie is not None:\n trie.insert(inputs[i][0])\n results.append(None)\n elif op == 'search' and trie is not None:\n results.append(trie.search(inputs[i][0]))\n elif op == 'starts_with' and trie is not None:\n results.append(trie.starts_with(inputs[i][0]))\n elif op == 'startsWith' and trie is not None:\n results.append(trie.starts_with(inputs[i][0]))\n return results, trie",
"helpers_assert_name": "trie_operations",
"helpers_assert_signature": "(result: list[bool | None], expected: list[bool | None]) -> bool",
"helpers_assert_body": " assert result == expected\n return True",
@@ -62,7 +62,7 @@
"name": "test_trie_operations",
"signature": "(self, operations: list[str], inputs: list[list[str]], expected: list[bool | None])",
"parametrize": "operations, inputs, expected",
- "test_cases": "[(['Trie', 'insert', 'search', 'search', 'starts_with', 'insert', 'search'], [[], ['apple'], ['apple'], ['app'], ['app'], ['app'], ['app']], [None, None, True, False, True, None, True]), (['Trie', 'insert', 'insert', 'search', 'search', 'starts_with', 'starts_with'], [[], ['hello'], ['world'], ['hello'], ['hi'], ['hel'], ['wor']], [None, None, None, True, False, True, True]), (['Trie', 'insert', 'insert', 'search', 'search', 'starts_with', 'starts_with'], [[], ['a'], ['aa'], ['a'], ['aa'], ['a'], ['aa']], [None, None, None, True, True, True, True]), (['Trie', 'insert', 'search', 'starts_with', 'insert', 'search', 'starts_with'], [[], ['test'], ['testing'], ['test'], ['testing'], ['testing'], ['test']], [None, None, False, True, None, True, True]), (['Trie', 'search', 'starts_with'], [[], ['empty'], ['empty']], [None, False, False])]",
+ "test_cases": "[([\"Trie\", \"insert\", \"insert\", \"search\", \"search\", \"search\"], [[], [\"app\"], [\"apple\"], [\"app\"], [\"apple\"], [\"appl\"]], [None, None, None, True, True, False]), ([\"Trie\", \"insert\", \"insert\", \"insert\", \"search\", \"search\", \"search\"], [[], [\"cat\"], [\"car\"], [\"card\"], [\"cat\"], [\"car\"], [\"care\"]], [None, None, None, None, True, True, False]), ([\"Trie\", \"insert\", \"insert\", \"starts_with\", \"starts_with\", \"starts_with\"], [[], [\"test\"], [\"testing\"], [\"test\"], [\"testing\"], [\"te\"]], [None, None, None, True, True, True]), ([\"Trie\", \"insert\", \"search\", \"search\", \"insert\", \"search\", \"search\"], [[], [\"abc\"], [\"abc\"], [\"ab\"], [\"ab\"], [\"ab\"], [\"abc\"]], [None, None, True, False, None, True, True]), ([\"Trie\", \"insert\", \"search\", \"starts_with\"], [[], [\"a\"], [\"a\"], [\"a\"]], [None, None, True, True]), ([\"Trie\", \"search\", \"starts_with\"], [[], [\"empty\"], [\"empty\"]], [None, False, False]), ([\"Trie\", \"insert\", \"insert\", \"search\", \"search\", \"starts_with\", \"starts_with\"], [[], [\"word\"], [\"world\"], [\"word\"], [\"world\"], [\"wor\"], [\"wo\"]], [None, None, None, True, True, True, True]), ([\"Trie\", \"insert\", \"insert\", \"insert\", \"search\", \"search\", \"search\", \"starts_with\"], [[], [\"aa\"], [\"aaa\"], [\"aaaa\"], [\"aa\"], [\"aaa\"], [\"aaaa\"], [\"a\"]], [None, None, None, None, True, True, True, True]), ([\"Trie\", \"insert\", \"search\", \"search\", \"starts_with\", \"starts_with\"], [[], [\"hello\"], [\"hello\"], [\"hell\"], [\"hello\"], [\"hel\"]], [None, None, True, False, True, True]), ([\"Trie\", \"insert\", \"insert\", \"insert\", \"search\", \"search\", \"search\", \"starts_with\", \"starts_with\"], [[], [\"she\"], [\"sells\"], [\"sea\"], [\"she\"], [\"shells\"], [\"sea\"], [\"se\"], [\"s\"]], [None, None, None, None, True, False, True, True, True]), ([\"Trie\", \"insert\", \"insert\", \"search\", \"search\", \"starts_with\", \"starts_with\", \"starts_with\"], [[], [\"programming\"], [\"program\"], [\"programming\"], [\"program\"], [\"prog\"], [\"programming\"], [\"programm\"]], [None, None, None, True, True, True, True, True]), ([\"Trie\", \"insert\", \"search\", \"starts_with\", \"insert\", \"search\", \"starts_with\"], [[], [\"z\"], [\"z\"], [\"z\"], [\"zzz\"], [\"zzz\"], [\"zz\"]], [None, None, True, True, None, True, True])]",
"body": " result, _ = run_trie_operations(Trie, operations, inputs)\n assert_trie_operations(result, expected)"
}
]
diff --git a/.templates/leetcode/json/insert_interval.json b/.templates/leetcode/json/insert_interval.json
index 64e4a18..44280d1 100644
--- a/.templates/leetcode/json/insert_interval.json
+++ b/.templates/leetcode/json/insert_interval.json
@@ -52,7 +52,7 @@
"name": "test_insert",
"signature": "(self, intervals: list[list[int]], new_interval: list[int], expected: list[list[int]])",
"parametrize": "intervals, new_interval, expected",
- "test_cases": "[([[1,3],[6,9]], [2,5], [[1,5],[6,9]]), ([[1,2],[3,5],[6,7],[8,10],[12,16]], [4,8], [[1,2],[3,10],[12,16]]), ([], [5,7], [[5,7]]), ([[1,5]], [2,3], [[1,5]]), ([[1,5]], [6,8], [[1,5],[6,8]]), ([[1,5]], [0,0], [[0,0],[1,5]]), ([[3,5],[12,15]], [6,6], [[3,5],[6,6],[12,15]])]",
+ "test_cases": "[([[1,3],[6,9]], [2,5], [[1,5],[6,9]]), ([[1,2],[3,5],[6,7],[8,10],[12,16]], [4,8], [[1,2],[3,10],[12,16]]), ([], [5,7], [[5,7]]), ([[1,5]], [2,3], [[1,5]]), ([[1,5]], [6,8], [[1,5],[6,8]]), ([[1,5]], [0,0], [[0,0],[1,5]]), ([[3,5],[12,15]], [6,6], [[3,5],[6,6],[12,15]]), ([[1,2],[4,5]], [3,3], [[1,2],[3,3],[4,5]]), ([[2,5],[6,7],[8,9]], [0,1], [[0,1],[2,5],[6,7],[8,9]]), ([[1,3],[6,9]], [10,12], [[1,3],[6,9],[10,12]]), ([[1,4],[5,6]], [2,3], [[1,4],[5,6]]), ([[1,2],[3,4],[5,6]], [0,7], [[0,7]]), ([[2,3],[5,6]], [1,4], [[1,4],[5,6]]), ([[1,5],[10,15]], [6,9], [[1,5],[6,9],[10,15]])]",
"body": " result = run_insert(Solution, intervals, new_interval)\n assert_insert(result, expected)"
}
]
diff --git a/.templates/leetcode/json/invert_binary_tree.json b/.templates/leetcode/json/invert_binary_tree.json
index d95e35c..b0d5f66 100644
--- a/.templates/leetcode/json/invert_binary_tree.json
+++ b/.templates/leetcode/json/invert_binary_tree.json
@@ -49,7 +49,7 @@
"name": "test_invert_tree",
"signature": "(self, root_list: list[int | None], expected_list: list[int | None])",
"parametrize": "root_list, expected_list",
- "test_cases": "[([4, 2, 7, 1, 3, 6, 9], [4, 7, 2, 9, 6, 3, 1]), ([2, 1, 3], [2, 3, 1]), ([], []), ([1], [1]), ([1, 2], [1, None, 2]), ([1, None, 2], [1, 2]), ([1, 2, 3, 4, 5], [1, 3, 2, None, None, 5, 4]), ([1, 2, 3, None, None, 4, 5], [1, 3, 2, 5, 4])]",
+ "test_cases": "[([4, 2, 7, 1, 3, 6, 9], [4, 7, 2, 9, 6, 3, 1]), ([2, 1, 3], [2, 3, 1]), ([], []), ([1], [1]), ([1, 2], [1, None, 2]), ([1, None, 2], [1, 2]), ([1, 2, 3, 4, 5], [1, 3, 2, None, None, 5, 4]), ([1, 2, 3, None, None, 4, 5], [1, 3, 2, 5, 4]), ([1, 2, 3, 4, 5, 6, 7], [1, 3, 2, 7, 6, 5, 4]), ([5, 3, 8, 2, 4, 7, 9], [5, 8, 3, 9, 7, 4, 2]), ([10, 5, 15, None, 6, 12, 20], [10, 15, 5, 20, 12, 6]), ([1, 2, None, 3], [1, None, 2, None, 3]), ([0, -1, 1], [0, 1, -1]), ([100, 50, 150], [100, 150, 50]), ([1, 2, 3, None, 4, None, 5], [1, 3, 2, 5, None, 4])]",
"body": " result = run_invert_tree(Solution, root_list)\n assert_invert_tree(result, expected_list)"
}
]
diff --git a/.templates/leetcode/json/k_closest_points_to_origin.json b/.templates/leetcode/json/k_closest_points_to_origin.json
index 8a648e5..d5ebb8f 100644
--- a/.templates/leetcode/json/k_closest_points_to_origin.json
+++ b/.templates/leetcode/json/k_closest_points_to_origin.json
@@ -52,7 +52,7 @@
"name": "test_k_closest",
"signature": "(self, points: list[list[int]], k: int, expected: list[list[int]])",
"parametrize": "points, k, expected",
- "test_cases": "[([[1, 3], [-2, 2]], 1, [[-2, 2]]), ([[3, 3], [5, -1], [-2, 4]], 2, [[3, 3], [-2, 4]]), ([[0, 1], [1, 0]], 2, [[0, 1], [1, 0]]), ([[1, 1], [1, 1], [1, 1]], 2, [[1, 1], [1, 1]]), ([[0, 0]], 1, [[0, 0]]), ([[1, 0], [2, 0], [3, 0]], 2, [[1, 0], [2, 0]])]",
+ "test_cases": "[([[1, 3], [-2, 2]], 1, [[-2, 2]]), ([[3, 3], [5, -1], [-2, 4]], 2, [[3, 3], [-2, 4]]), ([[0, 1], [1, 0]], 2, [[0, 1], [1, 0]]), ([[1, 1], [1, 1], [1, 1]], 2, [[1, 1], [1, 1]]), ([[0, 0]], 1, [[0, 0]]), ([[1, 0], [2, 0], [3, 0]], 2, [[1, 0], [2, 0]]), ([[0, 3], [4, 0]], 1, [[0, 3]]), ([[-5, 4], [4, 6], [2, -1]], 1, [[2, -1]]), ([[1, 1], [2, 2], [3, 3]], 1, [[1, 1]]), ([[10, 10], [1, 1], [5, 5]], 2, [[1, 1], [5, 5]]), ([[-1, -1], [1, 1], [-1, 1], [1, -1]], 3, [[-1, 1], [1, -1], [1, 1]]), ([[6, 10], [-3, 3], [-2, 5], [0, 2]], 3, [[-3, 3], [0, 2], [-2, 5]])]",
"body": " result = run_k_closest(Solution, points, k)\n assert_k_closest(result, expected)"
}
]
diff --git a/.templates/leetcode/json/kth_smallest_element_in_a_bst.json b/.templates/leetcode/json/kth_smallest_element_in_a_bst.json
index e41818c..0b4f072 100644
--- a/.templates/leetcode/json/kth_smallest_element_in_a_bst.json
+++ b/.templates/leetcode/json/kth_smallest_element_in_a_bst.json
@@ -52,7 +52,7 @@
"name": "test_kth_smallest",
"signature": "(self, root_list: list[int | None], k: int, expected: int)",
"parametrize": "root_list, k, expected",
- "test_cases": "[([3, 1, 4, None, 2], 1, 1), ([5, 3, 6, 2, 4, None, None, 1], 3, 3), ([1], 1, 1), ([2, 1, 3], 2, 2), ([4, 2, 6, 1, 3, 5, 7], 4, 4), ([1, None, 2], 2, 2)]",
+ "test_cases": "[([3, 1, 4, None, 2], 1, 1), ([5, 3, 6, 2, 4, None, None, 1], 3, 3), ([1], 1, 1), ([2, 1, 3], 2, 2), ([4, 2, 6, 1, 3, 5, 7], 4, 4), ([1, None, 2], 2, 2), ([5, 3, 6, 2, 4, None, None, 1], 1, 1), ([5, 3, 6, 2, 4, None, None, 1], 4, 4), ([10, 5, 15, 3, 7, 12, 20], 1, 3), ([10, 5, 15, 3, 7, 12, 20], 7, 20), ([1, None, 2, None, 3], 3, 3), ([3, 1, 4, None, 2], 4, 4)]",
"body": " result = run_kth_smallest(Solution, root_list, k)\n assert_kth_smallest(result, expected)"
}
]
diff --git a/.templates/leetcode/json/linked_list_cycle.json b/.templates/leetcode/json/linked_list_cycle.json
index eeb89c9..53aefe2 100644
--- a/.templates/leetcode/json/linked_list_cycle.json
+++ b/.templates/leetcode/json/linked_list_cycle.json
@@ -55,7 +55,7 @@
"name": "test_has_cycle",
"signature": "(self, values: list[int], pos: int, expected: bool)",
"parametrize": "values, pos, expected",
- "test_cases": "[([3, 2, 0, -4], 1, True), ([1, 2], 0, True), ([1], -1, False), ([], -1, False), ([1, 2, 3], -1, False), ([1, 2, 3, 4, 5], 0, True), ([1, 2, 3, 4, 5], 2, True), ([1, 2, 3, 4, 5], 4, True), ([1], 0, True), ([1, 2], 1, True)]",
+ "test_cases": "[([3, 2, 0, -4], 1, True), ([1, 2], 0, True), ([1], -1, False), ([], -1, False), ([1, 2, 3], -1, False), ([1, 2, 3, 4, 5], 0, True), ([1, 2, 3, 4, 5], 2, True), ([1, 2, 3, 4, 5], 4, True), ([1], 0, True), ([1, 2], 1, True), ([1, 2, 3, 4], -1, False), ([1, 2, 3, 4, 5, 6], 3, True), ([10, 20, 30], 1, True), ([100], -1, False), ([1, 2, 3, 4, 5, 6, 7, 8], 5, True)]",
"body": " result = run_has_cycle(Solution, values, pos)\n assert_has_cycle(result, expected)"
}
]
diff --git a/.templates/leetcode/json/lowest_common_ancestor_of_a_binary_search_tree.json b/.templates/leetcode/json/lowest_common_ancestor_of_a_binary_search_tree.json
index fab73c4..e310ef7 100644
--- a/.templates/leetcode/json/lowest_common_ancestor_of_a_binary_search_tree.json
+++ b/.templates/leetcode/json/lowest_common_ancestor_of_a_binary_search_tree.json
@@ -53,7 +53,7 @@
"name": "test_lowest_common_ancestor",
"signature": "(self, root_list: list[int | None], p_val: int, q_val: int, expected_val: int)",
"parametrize": "root_list, p_val, q_val, expected_val",
- "test_cases": "[([6, 2, 8, 0, 4, 7, 9, None, None, 3, 5], 2, 8, 6), ([6, 2, 8, 0, 4, 7, 9, None, None, 3, 5], 2, 4, 2), ([2, 1], 2, 1, 2), ([2, 1], 1, 2, 2), ([6, 2, 8, 0, 4, 7, 9], 0, 4, 2), ([6, 2, 8, 0, 4, 7, 9], 7, 9, 8)]",
+ "test_cases": "[([6, 2, 8, 0, 4, 7, 9, None, None, 3, 5], 2, 8, 6), ([6, 2, 8, 0, 4, 7, 9, None, None, 3, 5], 2, 4, 2), ([2, 1], 2, 1, 2), ([2, 1], 1, 2, 2), ([6, 2, 8, 0, 4, 7, 9], 0, 4, 2), ([6, 2, 8, 0, 4, 7, 9], 7, 9, 8), ([5, 3, 6, 2, 4, None, None, 1], 1, 4, 3), ([10, 5, 15, 3, 7, 12, 20], 3, 7, 5), ([1, None, 2], 1, 2, 1), ([3, 1, 4, None, 2], 1, 2, 1), ([20, 8, 22, 4, 12, None, None, None, None, 10, 14], 10, 14, 12), ([50, 30, 70, 20, 40, 60, 80], 20, 40, 30)]",
"body": " result = run_lowest_common_ancestor(Solution, root_list, p_val, q_val)\n assert_lowest_common_ancestor(result, expected_val)"
}
]
diff --git a/.templates/leetcode/json/lowest_common_ancestor_of_a_binary_tree.json b/.templates/leetcode/json/lowest_common_ancestor_of_a_binary_tree.json
index c1f4b0e..44c77e2 100644
--- a/.templates/leetcode/json/lowest_common_ancestor_of_a_binary_tree.json
+++ b/.templates/leetcode/json/lowest_common_ancestor_of_a_binary_tree.json
@@ -53,7 +53,7 @@
"name": "test_lowest_common_ancestor",
"signature": "(self, root_list: list[int | None], p_val: int, q_val: int, expected_val: int)",
"parametrize": "root_list, p_val, q_val, expected_val",
- "test_cases": "[([3,5,1,6,2,0,8,None,None,7,4], 5, 1, 3), ([3,5,1,6,2,0,8,None,None,7,4], 5, 4, 5), ([1,2], 1, 2, 1), ([2,1], 2, 1, 2), ([3,5,1,6,2,0,8,None,None,7,4], 6, 7, 5), ([3,5,1,6,2,0,8,None,None,7,4], 0, 8, 1)]",
+ "test_cases": "[([3,5,1,6,2,0,8,None,None,7,4], 5, 1, 3), ([3,5,1,6,2,0,8,None,None,7,4], 5, 4, 5), ([1,2], 1, 2, 1), ([2,1], 2, 1, 2), ([3,5,1,6,2,0,8,None,None,7,4], 6, 7, 5), ([3,5,1,6,2,0,8,None,None,7,4], 0, 8, 1), ([1, None, 2, None, 3], 2, 3, 2), ([4, 2, 6, 1, 3, 5, 7], 1, 7, 4), ([10, 5, 15, 3, 7, None, 18], 3, 7, 5), ([1, 2, 3, 4, 5, 6, 7], 4, 5, 2), ([20, 8, 22, 4, 12, None, 25], 4, 12, 8), ([50, 30, 70, 20, 40, 60, 80], 20, 40, 30)]",
"body": " result = run_lowest_common_ancestor(Solution, root_list, p_val, q_val)\n assert_lowest_common_ancestor(result, expected_val)"
}
]
diff --git a/.templates/leetcode/json/lru_cache.json b/.templates/leetcode/json/lru_cache.json
index 3bc81d9..2765e1f 100644
--- a/.templates/leetcode/json/lru_cache.json
+++ b/.templates/leetcode/json/lru_cache.json
@@ -57,7 +57,7 @@
"name": "test_lru_cache",
"signature": "(self, operations: list[str], inputs: list[list[int]], expected: list[int | None])",
"parametrize": "operations, inputs, expected",
- "test_cases": "[(['LRUCache', 'put', 'put', 'get', 'put', 'get', 'put', 'get', 'get', 'get'], [[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]], [None, None, None, 1, None, -1, None, -1, 3, 4]), (['LRUCache', 'get', 'put', 'get', 'put', 'put', 'get', 'get'], [[2], [2], [2, 6], [1], [1, 5], [1, 2], [1], [2]], [None, -1, None, -1, None, None, 2, 6]), (['LRUCache', 'put', 'get', 'put', 'get', 'get'], [[1], [2, 1], [2], [3, 2], [2], [3]], [None, None, 1, None, -1, 2])]",
+ "test_cases": "[(['LRUCache', 'put', 'put', 'get', 'put', 'get', 'put', 'get', 'get', 'get'], [[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]], [None, None, None, 1, None, -1, None, -1, 3, 4]), (['LRUCache', 'get', 'put', 'get', 'put', 'put', 'get', 'get'], [[2], [2], [2, 6], [1], [1, 5], [1, 2], [1], [2]], [None, -1, None, -1, None, None, 2, 6]), (['LRUCache', 'put', 'get', 'put', 'get', 'get'], [[1], [2, 1], [2], [3, 2], [2], [3]], [None, None, 1, None, -1, 2]), (['LRUCache', 'get'], [[1], [1]], [None, -1]), (['LRUCache', 'put', 'get'], [[1], [1, 100], [1]], [None, None, 100]), (['LRUCache', 'put', 'put', 'get', 'get'], [[2], [1, 1], [2, 2], [1], [2]], [None, None, None, 1, 2]), (['LRUCache', 'put', 'put', 'put', 'get', 'get', 'get'], [[2], [1, 1], [2, 2], [3, 3], [1], [2], [3]], [None, None, None, None, -1, 2, 3]), (['LRUCache', 'put', 'get', 'put', 'get', 'put', 'get'], [[3], [1, 1], [1], [2, 2], [2], [3, 3], [3]], [None, None, 1, None, 2, None, 3]), (['LRUCache', 'put', 'put', 'put', 'put', 'get', 'get'], [[3], [1, 1], [2, 2], [3, 3], [4, 4], [4], [3]], [None, None, None, None, None, 4, 3]), (['LRUCache', 'put', 'put', 'get', 'put', 'get', 'get'], [[2], [2, 1], [1, 1], [2], [4, 1], [1], [2]], [None, None, None, 1, None, -1, 1]), (['LRUCache', 'put', 'put', 'get', 'put', 'put', 'get'], [[2], [2, 1], [2, 2], [2], [1, 1], [4, 1], [2]], [None, None, None, 2, None, None, -1]), (['LRUCache', 'put', 'put', 'put', 'get', 'put', 'get', 'get', 'get', 'get'], [[3], [1, 1], [2, 2], [3, 3], [2], [4, 4], [1], [3], [4], [2]], [None, None, None, None, 2, None, -1, 3, 4, 2])]",
"body": " result, _ = run_lru_cache(LRUCache, operations, inputs)\n assert_lru_cache(result, expected)"
}
]
diff --git a/.templates/leetcode/json/majority_element.json b/.templates/leetcode/json/majority_element.json
index 1fc620a..36f438e 100644
--- a/.templates/leetcode/json/majority_element.json
+++ b/.templates/leetcode/json/majority_element.json
@@ -48,7 +48,7 @@
"name": "test_majority_element",
"signature": "(self, nums: list[int], expected: int)",
"parametrize": "nums, expected",
- "test_cases": "[([3,2,3], 3), ([2,2,1,1,1,2,2], 2), ([1], 1), ([1,1,2], 1), ([2,2,2,1,1], 2), ([5,5,5,5,1,2,3], 5), ([1,2,3,4,4,4,4], 4), ([0,0,0], 0), ([-1,-1,-1,1,1], -1)]",
+ "test_cases": "[([3,2,3], 3), ([2,2,1,1,1,2,2], 2), ([1], 1), ([1,1,2], 1), ([2,2,2,1,1], 2), ([5,5,5,5,1,2,3], 5), ([1,2,3,4,4,4,4], 4), ([0,0,0], 0), ([-1,-1,-1,1,1], -1), ([100,100,100,99,99], 100), ([7,7,7,7,7,8,8], 7), ([1,1,1,1,1,1,2,2,2], 1), ([9,9,9,9,8,8,8], 9), ([-5,-5,-5,-4,-4], -5), ([1000,1000,999,999,1000], 1000)]",
"body": " result = run_majority_element(Solution, nums)\n assert_majority_element(result, expected)"
}
]
diff --git a/.templates/leetcode/json/maximum_depth_of_binary_tree.json b/.templates/leetcode/json/maximum_depth_of_binary_tree.json
index fed5f39..1d62f00 100644
--- a/.templates/leetcode/json/maximum_depth_of_binary_tree.json
+++ b/.templates/leetcode/json/maximum_depth_of_binary_tree.json
@@ -50,7 +50,7 @@
"name": "test_max_depth",
"signature": "(self, root_list: list[int | None], expected: int)",
"parametrize": "root_list, expected",
- "test_cases": "[([3, 9, 20, None, None, 15, 7], 3), ([1, None, 2], 2), ([], 0), ([1], 1), ([1, 2], 2), ([1, 2, 3], 2), ([1, 2, 3, 4], 3), ([1, None, 2, None, 3], 3)]",
+ "test_cases": "[([3, 9, 20, None, None, 15, 7], 3), ([1, None, 2], 2), ([], 0), ([1], 1), ([1, 2], 2), ([1, 2, 3], 2), ([1, 2, 3, 4], 3), ([1, None, 2, None, 3], 3), ([1, 2, 3, 4, 5, 6, 7], 3), ([1, 2, None, 4, None, None, None, 8], 3), ([5, 4, 8, 11, None, 13, 4, 7, 2, None, None, None, 1], 4), ([1, 2, 3, None, None, 4, 5, None, None, 6], 4), ([10], 1), ([1, 2, 2, 3, 3, 3, 3], 3), ([0, -1, 1, -2, -1, 0, 2], 3)]",
"body": " result = run_max_depth(Solution, root_list)\n assert_max_depth(result, expected)"
}
]
diff --git a/.templates/leetcode/json/maximum_profit_in_job_scheduling.json b/.templates/leetcode/json/maximum_profit_in_job_scheduling.json
index c765195..54c0cd2 100644
--- a/.templates/leetcode/json/maximum_profit_in_job_scheduling.json
+++ b/.templates/leetcode/json/maximum_profit_in_job_scheduling.json
@@ -55,7 +55,7 @@
"name": "test_job_scheduling",
"signature": "(self, start_time: list[int], end_time: list[int], profit: list[int], expected: int)",
"parametrize": "start_time, end_time, profit, expected",
- "test_cases": "[([1, 2, 3, 3], [3, 4, 5, 6], [50, 10, 40, 70], 120), ([1, 2, 3, 4, 6], [3, 5, 10, 6, 9], [20, 20, 100, 70, 60], 150), ([1, 1, 1], [2, 3, 4], [5, 6, 4], 6), ([1], [2], [100], 100)]",
+ "test_cases": "[([1, 2, 3, 3], [3, 4, 5, 6], [50, 10, 40, 70], 120), ([1, 2, 3, 4, 6], [3, 5, 10, 6, 9], [20, 20, 100, 70, 60], 150), ([1, 1, 1], [2, 3, 4], [5, 6, 4], 6), ([1, 2], [2, 3], [100, 200], 300), ([6, 15, 7, 11, 1, 3, 16, 2], [19, 18, 19, 16, 10, 8, 19, 8], [2, 9, 1, 19, 5, 7, 3, 19], 41), ([1], [2], [100], 100), ([1, 2, 3], [2, 3, 4], [1, 1, 1], 3), ([1, 3, 6, 7, 8, 12], [4, 5, 10, 11, 12, 16], [20, 20, 100, 70, 60, 120], 240), ([1, 4, 6], [3, 5, 7], [50, 10, 40], 100), ([1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [10, 20, 30, 40, 50], 50), ([5, 4, 3, 2, 1], [6, 5, 4, 3, 2], [1, 2, 3, 4, 5], 15), ([1, 1000000000], [2, 1000000001], [1, 10000], 10001)]",
"body": " result = run_job_scheduling(Solution, start_time, end_time, profit)\n assert_job_scheduling(result, expected)"
}
]
diff --git a/.templates/leetcode/json/maximum_subarray.json b/.templates/leetcode/json/maximum_subarray.json
index bb4e76a..8c9bd1b 100644
--- a/.templates/leetcode/json/maximum_subarray.json
+++ b/.templates/leetcode/json/maximum_subarray.json
@@ -55,7 +55,7 @@
"name": "test_max_sub_array",
"signature": "(self, nums: list[int], expected: int)",
"parametrize": "nums, expected",
- "test_cases": "[([-2, 1, -3, 4, -1, 2, 1, -5, 4], 6), ([1], 1), ([5, 4, -1, 7, 8], 23), ([-1], -1), ([-2, -1], -1), ([1, 2, 3, 4, 5], 15), ([-5, -2, -8, -1], -1)]",
+ "test_cases": "[([-2, 1, -3, 4, -1, 2, 1, -5, 4], 6), ([1], 1), ([5, 4, -1, 7, 8], 23), ([-1], -1), ([-2, -1], -1), ([1, 2, 3, 4, 5], 15), ([-5, -2, -8, -1], -1), ([0], 0), ([0, -1, 0], 0), ([-3, -2, -1, -5], -1), ([2, -1, 2, -1, 2], 4), ([1, -3, 2, 1, -1], 3), ([-2, -3, 4, -1, -2, 1, 5, -3], 7), ([10, -5, 3, -2, 8], 14), ([100], 100)]",
"body": " result = run_max_sub_array(Solution, nums)\n assert_max_sub_array(result, expected)"
}
]
diff --git a/.templates/leetcode/json/merge_intervals.json b/.templates/leetcode/json/merge_intervals.json
index 7c0efbf..606741c 100644
--- a/.templates/leetcode/json/merge_intervals.json
+++ b/.templates/leetcode/json/merge_intervals.json
@@ -55,7 +55,7 @@
"name": "test_merge",
"signature": "(self, intervals: list[list[int]], expected: list[list[int]])",
"parametrize": "intervals, expected",
- "test_cases": "[([[1,3],[2,6],[8,10],[15,18]], [[1,6],[8,10],[15,18]]), ([[1,4],[4,5]], [[1,5]]), ([[4,7],[1,4]], [[1,7]]), ([[1,3]], [[1,3]]), ([[1,4],[2,3]], [[1,4]]), ([[1,2],[3,4],[5,6]], [[1,2],[3,4],[5,6]])]",
+ "test_cases": "[([[1,3],[2,6],[8,10],[15,18]], [[1,6],[8,10],[15,18]]), ([[1,4],[4,5]], [[1,5]]), ([[4,7],[1,4]], [[1,7]]), ([[1,3]], [[1,3]]), ([[1,4],[2,3]], [[1,4]]), ([[1,2],[3,4],[5,6]], [[1,2],[3,4],[5,6]]), ([[0,0]], [[0,0]]), ([[1,10],[2,3],[4,5],[6,7],[8,9]], [[1,10]]), ([[1,3],[2,6],[8,10],[9,12],[15,18]], [[1,6],[8,12],[15,18]]), ([[2,3],[4,5],[6,7],[8,9],[1,10]], [[1,10]]), ([[1,4],[0,4]], [[0,4]]), ([[1,4],[0,0],[3,5]], [[0,0],[1,5]])]",
"body": " result = run_merge(Solution, intervals)\n assert_merge(result, expected)"
}
]
diff --git a/.templates/leetcode/json/merge_k_sorted_lists.json b/.templates/leetcode/json/merge_k_sorted_lists.json
index 3031430..d85adc6 100644
--- a/.templates/leetcode/json/merge_k_sorted_lists.json
+++ b/.templates/leetcode/json/merge_k_sorted_lists.json
@@ -51,7 +51,7 @@
"name": "test_merge_k_lists",
"signature": "(self, lists_data: list[list[int]], expected_data: list[int])",
"parametrize": "lists_data, expected_data",
- "test_cases": "[([[1, 4, 5], [1, 3, 4], [2, 6]], [1, 1, 2, 3, 4, 4, 5, 6]), ([], []), ([[]], []), ([[1]], [1]), ([[1, 2], [3, 4]], [1, 2, 3, 4]), ([[5], [1, 3], [2, 4, 6]], [1, 2, 3, 4, 5, 6]), ([[-1, 0, 1], [-2, 2]], [-2, -1, 0, 1, 2]), ([[1, 1, 1], [2, 2, 2]], [1, 1, 1, 2, 2, 2]), ([[], [1], []], [1])]",
+ "test_cases": "[([[1, 4, 5], [1, 3, 4], [2, 6]], [1, 1, 2, 3, 4, 4, 5, 6]), ([], []), ([[]], []), ([[1]], [1]), ([[1, 2], [3, 4]], [1, 2, 3, 4]), ([[5], [1, 3], [2, 4, 6]], [1, 2, 3, 4, 5, 6]), ([[-1, 0, 1], [-2, 2]], [-2, -1, 0, 1, 2]), ([[1, 1, 1], [2, 2, 2]], [1, 1, 1, 2, 2, 2]), ([[], [1], []], [1]), ([[0, 0, 0], [1, 1, 1]], [0, 0, 0, 1, 1, 1]), ([[10], [5], [1]], [1, 5, 10]), ([[1, 2, 3, 4, 5]], [1, 2, 3, 4, 5]), ([[-10, -5], [-8, -3], [-6, -1]], [-10, -8, -6, -5, -3, -1]), ([[100]], [100]), ([[1, 3, 5], [2, 4, 6], [7, 8, 9]], [1, 2, 3, 4, 5, 6, 7, 8, 9])]",
"body": " result = run_merge_k_lists(Solution, lists_data)\n assert_merge_k_lists(result, expected_data)"
}
]
diff --git a/.templates/leetcode/json/merge_two_sorted_lists.json b/.templates/leetcode/json/merge_two_sorted_lists.json
index fe7dfb6..a6f7231 100644
--- a/.templates/leetcode/json/merge_two_sorted_lists.json
+++ b/.templates/leetcode/json/merge_two_sorted_lists.json
@@ -51,7 +51,7 @@
"name": "test_merge_two_lists",
"signature": "(self, list1_vals: list[int], list2_vals: list[int], expected_vals: list[int])",
"parametrize": "list1_vals, list2_vals, expected_vals",
- "test_cases": "[([1, 2, 4], [1, 3, 4], [1, 1, 2, 3, 4, 4]), ([], [], []), ([], [0], [0]), ([1], [2], [1, 2]), ([2], [1], [1, 2]), ([1, 3, 5], [2, 4, 6], [1, 2, 3, 4, 5, 6]), ([1, 1, 1], [2, 2, 2], [1, 1, 1, 2, 2, 2])]",
+ "test_cases": "[([1, 2, 4], [1, 3, 4], [1, 1, 2, 3, 4, 4]), ([], [], []), ([], [0], [0]), ([1], [2], [1, 2]), ([2], [1], [1, 2]), ([1, 3, 5], [2, 4, 6], [1, 2, 3, 4, 5, 6]), ([1, 1, 1], [2, 2, 2], [1, 1, 1, 2, 2, 2]), ([0], [], [0]), ([1, 2, 3], [], [1, 2, 3]), ([5], [1, 2, 3, 4], [1, 2, 3, 4, 5]), ([-1, 0, 1], [-2, 2, 3], [-2, -1, 0, 1, 2, 3]), ([1, 5, 9], [2, 6, 8], [1, 2, 5, 6, 8, 9]), ([10, 20, 30], [15, 25, 35], [10, 15, 20, 25, 30, 35]), ([1, 1], [1, 1], [1, 1, 1, 1])]",
"body": " result = run_merge_two_lists(Solution, list1_vals, list2_vals)\n assert_merge_two_lists(result, expected_vals)"
}
]
diff --git a/.templates/leetcode/json/middle_of_the_linked_list.json b/.templates/leetcode/json/middle_of_the_linked_list.json
index 9e6b152..f64df0a 100644
--- a/.templates/leetcode/json/middle_of_the_linked_list.json
+++ b/.templates/leetcode/json/middle_of_the_linked_list.json
@@ -52,7 +52,7 @@
"name": "test_middle_node",
"signature": "(self, head_list: list[int], expected_list: list[int])",
"parametrize": "head_list, expected_list",
- "test_cases": "[([1, 2, 3, 4, 5], [3, 4, 5]), ([1, 2, 3, 4, 5, 6], [4, 5, 6]), ([1], [1]), ([1, 2], [2]), ([1, 2, 3], [2, 3]), ([1, 2, 3, 4], [3, 4]), ([10, 20, 30, 40, 50, 60, 70], [40, 50, 60, 70])]",
+ "test_cases": "[([1, 2, 3, 4, 5], [3, 4, 5]), ([1, 2, 3, 4, 5, 6], [4, 5, 6]), ([1], [1]), ([1, 2], [2]), ([1, 2, 3], [2, 3]), ([1, 2, 3, 4], [3, 4]), ([10, 20, 30, 40, 50, 60, 70], [40, 50, 60, 70]), ([5, 10], [10]), ([1, 3, 5, 7, 9], [5, 7, 9]), ([2, 4, 6, 8, 10, 12], [8, 10, 12]), ([100], [100]), ([7, 14, 21], [14, 21]), ([11, 22, 33, 44], [33, 44]), ([1, 1, 1, 1, 1], [1, 1, 1])]",
"body": " result = run_middle_node(Solution, head_list)\n assert_middle_node(result, expected_list)"
}
]
diff --git a/.templates/leetcode/json/min_stack.json b/.templates/leetcode/json/min_stack.json
index 5e902b9..7ed6490 100644
--- a/.templates/leetcode/json/min_stack.json
+++ b/.templates/leetcode/json/min_stack.json
@@ -67,7 +67,7 @@
"name": "test_min_stack",
"signature": "(self, operations: list[str], inputs: list[list[int]], expected: list[int | None])",
"parametrize": "operations, inputs, expected",
- "test_cases": "[(['MinStack', 'push', 'push', 'push', 'getMin', 'pop', 'top', 'getMin'], [[], [-2], [0], [-3], [], [], [], []], [None, None, None, None, -3, None, 0, -2]), (['MinStack', 'push', 'top', 'getMin', 'pop'], [[], [5], [], [], []], [None, None, 5, 5, None]), (['MinStack', 'push', 'push', 'push', 'getMin', 'pop', 'getMin', 'pop', 'getMin'], [[], [1], [1], [2], [], [], [], [], []], [None, None, None, None, 1, None, 1, None, 1])]",
+ "test_cases": "[(['MinStack', 'push', 'push', 'push', 'getMin', 'pop', 'top', 'getMin'], [[], [-2], [0], [-3], [], [], [], []], [None, None, None, None, -3, None, 0, -2]), (['MinStack', 'push', 'top', 'getMin', 'pop'], [[], [5], [], [], []], [None, None, 5, 5, None]), (['MinStack', 'push', 'push', 'push', 'getMin', 'pop', 'getMin', 'pop', 'getMin'], [[], [1], [1], [2], [], [], [], [], []], [None, None, None, None, 1, None, 1, None, 1]), (['MinStack', 'push', 'getMin', 'top'], [[], [0], [], []], [None, None, 0, 0]), (['MinStack', 'push', 'push', 'getMin', 'push', 'getMin', 'pop', 'getMin'], [[], [2], [1], [], [0], [], [], []], [None, None, None, 1, None, 0, None, 1]), (['MinStack', 'push', 'push', 'push', 'top', 'getMin', 'pop', 'pop', 'top', 'getMin'], [[], [3], [1], [4], [], [], [], [], [], []], [None, None, None, None, 4, 1, None, None, 3, 3]), (['MinStack', 'push', 'push', 'getMin', 'pop', 'push', 'getMin'], [[], [-1], [-2], [], [], [0], []], [None, None, None, -2, None, None, -1]), (['MinStack', 'push', 'push', 'push', 'push', 'getMin', 'pop', 'pop', 'getMin'], [[], [5], [3], [7], [2], [], [], [], []], [None, None, None, None, None, 2, None, None, 3]), (['MinStack', 'push', 'push', 'push', 'getMin', 'pop', 'getMin', 'pop', 'getMin', 'pop', 'push', 'getMin'], [[], [10], [5], [15], [], [], [], [], [], [], [8], []], [None, None, None, None, 5, None, 5, None, 10, None, None, 8]), (['MinStack', 'push', 'push', 'push', 'push', 'push', 'getMin', 'pop', 'getMin', 'pop', 'getMin'], [[], [1], [2], [0], [3], [4], [], [], [], [], []], [None, None, None, None, None, None, 0, None, 0, None, 0]), (['MinStack', 'push', 'getMin', 'push', 'getMin', 'push', 'getMin', 'top'], [[], [2147483647], [], [-2147483648], [], [0], [], []], [None, None, 2147483647, None, -2147483648, None, -2147483648, 0]), (['MinStack', 'push', 'push', 'push', 'push', 'push', 'top', 'getMin', 'pop', 'top', 'getMin', 'pop', 'getMin'], [[], [1], [1], [1], [1], [1], [], [], [], [], [], [], []], [None, None, None, None, None, None, 1, 1, None, 1, 1, None, 1])]",
"body": " result = run_min_stack_operations(MinStack, operations, inputs)\n assert_min_stack_operations(result, expected)"
}
]
diff --git a/.templates/leetcode/json/minimum_height_trees.json b/.templates/leetcode/json/minimum_height_trees.json
index bc83ead..3378d91 100644
--- a/.templates/leetcode/json/minimum_height_trees.json
+++ b/.templates/leetcode/json/minimum_height_trees.json
@@ -52,7 +52,7 @@
"name": "test_find_min_height_trees",
"signature": "(self, n: int, edges: list[list[int]], expected: list[int])",
"parametrize": "n, edges, expected",
- "test_cases": "[(4, [[1,0],[1,2],[1,3]], [1]), (6, [[3,0],[3,1],[3,2],[3,4],[5,4]], [3,4]), (1, [], [0]), (2, [[0,1]], [0,1]), (3, [[0,1],[1,2]], [1])]",
+ "test_cases": "[(4, [[1, 0], [1, 2], [1, 3]], [1]), (6, [[3, 0], [3, 1], [3, 2], [3, 4], [5, 4]], [3, 4]), (1, [], [0]), (2, [[0, 1]], [0, 1]), (3, [[0, 1], [1, 2]], [1]), (5, [[0, 1], [1, 2], [2, 3], [3, 4]], [2]), (7, [[0, 1], [1, 2], [1, 3], [2, 4], [3, 5], [4, 6]], [1, 2]), (6, [[0, 3], [1, 3], [2, 3], [4, 3], [5, 4]], [3, 4]), (10, [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9]], [4, 5]), (8, [[0, 1], [1, 2], [2, 3], [0, 4], [4, 5], [5, 6], [6, 7]], [0, 4]), (9, [[0, 1], [0, 2], [1, 3], [1, 4], [2, 5], [2, 6], [3, 7], [4, 8]], [0, 1]), (11, [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10]], [5])]",
"body": " result = run_find_min_height_trees(Solution, n, edges)\n assert_find_min_height_trees(result, expected)"
}
]
diff --git a/.templates/leetcode/json/minimum_window_substring.json b/.templates/leetcode/json/minimum_window_substring.json
index 6a146ad..7032f45 100644
--- a/.templates/leetcode/json/minimum_window_substring.json
+++ b/.templates/leetcode/json/minimum_window_substring.json
@@ -55,7 +55,7 @@
"name": "test_min_window",
"signature": "(self, s: str, t: str, expected: str)",
"parametrize": "s, t, expected",
- "test_cases": "[(\"ADOBECODEBANC\", \"ABC\", \"BANC\"), (\"a\", \"a\", \"a\"), (\"a\", \"aa\", \"\"), (\"ab\", \"b\", \"b\"), (\"abc\", \"cba\", \"abc\")]",
+ "test_cases": "[(\"ADOBECODEBANC\", \"ABC\", \"BANC\"), (\"a\", \"a\", \"a\"), (\"a\", \"aa\", \"\"), (\"ab\", \"b\", \"b\"), (\"abc\", \"cba\", \"abc\"), (\"aa\", \"aa\", \"aa\"), (\"a\", \"b\", \"\"), (\"ab\", \"a\", \"a\"), (\"bba\", \"ab\", \"ba\"), (\"acbbaca\", \"aba\", \"baca\"), (\"cabwefgewcwaefgcf\", \"cae\", \"cwae\")]",
"body": " result = run_min_window(Solution, s, t)\n assert_min_window(result, expected)"
}
]
diff --git a/.templates/leetcode/json/number_of_islands.json b/.templates/leetcode/json/number_of_islands.json
index d1cf6ef..66f120d 100644
--- a/.templates/leetcode/json/number_of_islands.json
+++ b/.templates/leetcode/json/number_of_islands.json
@@ -52,7 +52,7 @@
"name": "test_num_islands",
"signature": "(self, grid: list[list[str]], expected: int)",
"parametrize": "grid, expected",
- "test_cases": "[([['1','1','1','1','0'],['1','1','0','1','0'],['1','1','0','0','0'],['0','0','0','0','0']], 1), ([['1','1','0','0','0'],['1','1','0','0','0'],['0','0','1','0','0'],['0','0','0','1','1']], 3), ([['1']], 1), ([['0']], 0), ([['1','0','1'],['0','1','0'],['1','0','1']], 5)]",
+ "test_cases": "[([[\"1\", \"1\", \"1\", \"1\", \"0\"], [\"1\", \"1\", \"0\", \"1\", \"0\"], [\"1\", \"1\", \"0\", \"0\", \"0\"], [\"0\", \"0\", \"0\", \"0\", \"0\"]], 1), ([[\"1\", \"1\", \"0\", \"0\", \"0\"], [\"1\", \"1\", \"0\", \"0\", \"0\"], [\"0\", \"0\", \"1\", \"0\", \"0\"], [\"0\", \"0\", \"0\", \"1\", \"1\"]], 3), ([[\"1\", \"0\", \"1\", \"1\", \"1\"], [\"1\", \"0\", \"1\", \"0\", \"1\"], [\"1\", \"1\", \"1\", \"0\", \"1\"]], 1), ([[\"0\", \"0\", \"0\", \"0\", \"0\"], [\"0\", \"0\", \"0\", \"0\", \"0\"], [\"0\", \"0\", \"0\", \"0\", \"0\"]], 0), ([[\"1\", \"1\", \"1\"], [\"0\", \"1\", \"0\"], [\"1\", \"1\", \"1\"]], 1), ([[\"1\"]], 1), ([[\"0\"]], 0), ([[\"1\", \"0\"], [\"0\", \"1\"]], 2), ([[\"1\", \"1\"], [\"1\", \"1\"]], 1), ([[\"1\", \"0\", \"1\"], [\"0\", \"1\", \"0\"], [\"1\", \"0\", \"1\"]], 5), ([[\"1\", \"1\", \"0\"], [\"0\", \"0\", \"1\"], [\"0\", \"1\", \"1\"]], 2), ([[\"1\", \"0\", \"0\", \"1\"], [\"0\", \"1\", \"1\", \"0\"], [\"0\", \"1\", \"1\", \"0\"], [\"1\", \"0\", \"0\", \"1\"]], 5), ([[\"0\", \"1\", \"0\"], [\"1\", \"0\", \"1\"], [\"0\", \"1\", \"0\"]], 4), ([[\"1\", \"1\", \"1\", \"1\"], [\"1\", \"0\", \"0\", \"1\"], [\"1\", \"1\", \"1\", \"1\"]], 1)]",
"body": " result = run_num_islands(Solution, grid)\n assert_num_islands(result, expected)"
}
]
diff --git a/.templates/leetcode/json/partition_equal_subset_sum.json b/.templates/leetcode/json/partition_equal_subset_sum.json
index da63474..64fa8db 100644
--- a/.templates/leetcode/json/partition_equal_subset_sum.json
+++ b/.templates/leetcode/json/partition_equal_subset_sum.json
@@ -52,7 +52,7 @@
"name": "test_can_partition",
"signature": "(self, nums: list[int], expected: bool)",
"parametrize": "nums, expected",
- "test_cases": "[([1, 5, 11, 5], True), ([1, 2, 3, 5], False), ([1, 1], True), ([1], False), ([2, 2, 1, 1], True), ([100], False), ([1, 2, 5], False)]",
+ "test_cases": "[([1, 5, 11, 5], True), ([1, 2, 3, 5], False), ([1, 1], True), ([1], False), ([2, 2, 1, 1], True), ([100], False), ([1, 2, 5], False), ([1, 3, 5, 7], True), ([2, 2, 3, 5], False), ([1, 2, 3, 4, 5, 6, 7], True), ([3, 3, 3, 4, 5], True), ([1, 1, 1, 1], True), ([23, 13, 11, 7, 6, 5, 5], True), ([1, 5, 3], False), ([4, 4, 4, 4, 4, 4], True)]",
"body": " result = run_can_partition(Solution, nums)\n assert_can_partition(result, expected)"
}
]
diff --git a/.templates/leetcode/json/permutations.json b/.templates/leetcode/json/permutations.json
index 081332d..cb974c4 100644
--- a/.templates/leetcode/json/permutations.json
+++ b/.templates/leetcode/json/permutations.json
@@ -51,7 +51,7 @@
"name": "test_permute",
"signature": "(self, nums: list[int], expected: list[list[int]])",
"parametrize": "nums, expected",
- "test_cases": "[([1, 2, 3], [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]), ([0, 1], [[0, 1], [1, 0]]), ([1], [[1]]), ([2, 1], [[2, 1], [1, 2]])]",
+ "test_cases": "[([1, 2, 3], [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]), ([0, 1], [[0, 1], [1, 0]]), ([1], [[1]]), ([2, 1], [[2, 1], [1, 2]]), ([0], [[0]]), ([-1, 0], [[-1, 0], [0, -1]]), ([1, 2], [[1, 2], [2, 1]]), ([3, 2, 1], [[3, 2, 1], [3, 1, 2], [2, 3, 1], [2, 1, 3], [1, 3, 2], [1, 2, 3]]), ([-1, 1], [[-1, 1], [1, -1]]), ([5, 4, 3, 2], [[5, 4, 3, 2], [5, 4, 2, 3], [5, 3, 4, 2], [5, 3, 2, 4], [5, 2, 4, 3], [5, 2, 3, 4], [4, 5, 3, 2], [4, 5, 2, 3], [4, 3, 5, 2], [4, 3, 2, 5], [4, 2, 5, 3], [4, 2, 3, 5], [3, 5, 4, 2], [3, 5, 2, 4], [3, 4, 5, 2], [3, 4, 2, 5], [3, 2, 5, 4], [3, 2, 4, 5], [2, 5, 4, 3], [2, 5, 3, 4], [2, 4, 5, 3], [2, 4, 3, 5], [2, 3, 5, 4], [2, 3, 4, 5]]), ([0, -1, 1], [[0, -1, 1], [0, 1, -1], [-1, 0, 1], [-1, 1, 0], [1, 0, -1], [1, -1, 0]]), ([10, -10], [[10, -10], [-10, 10]])]",
"body": " result = run_permute(Solution, nums)\n assert_permute(result, expected)"
}
]
diff --git a/.templates/leetcode/json/product_of_array_except_self.json b/.templates/leetcode/json/product_of_array_except_self.json
index d99aa69..d698e0c 100644
--- a/.templates/leetcode/json/product_of_array_except_self.json
+++ b/.templates/leetcode/json/product_of_array_except_self.json
@@ -48,7 +48,7 @@
"name": "test_product_except_self",
"signature": "(self, nums: list[int], expected: list[int])",
"parametrize": "nums, expected",
- "test_cases": "[([1, 2, 3, 4], [24, 12, 8, 6]), ([-1, 1, 0, -3, 3], [0, 0, 9, 0, 0]), ([2, 3, 4, 5], [60, 40, 30, 24]), ([1, 1], [1, 1]), ([5, 2], [2, 5]), ([0, 1, 2, 3], [6, 0, 0, 0]), ([1, 0, 3, 4], [0, 12, 0, 0])]",
+ "test_cases": "[([1, 2, 3, 4], [24, 12, 8, 6]), ([-1, 1, 0, -3, 3], [0, 0, 9, 0, 0]), ([2, 3, 4, 5], [60, 40, 30, 24]), ([1, 1], [1, 1]), ([5, 2], [2, 5]), ([0, 1, 2, 3], [6, 0, 0, 0]), ([1, 0, 3, 4], [0, 12, 0, 0]), ([-1, -2, -3], [6, 3, 2]), ([2, 2, 2], [4, 4, 4]), ([10, 3, 5, 6, 2], [180, 600, 360, 300, 900]), ([0, 0], [0, 0]), ([1, 2, 0, 4], [0, 0, 8, 0]), ([-2, 0, -3, 4], [0, 24, 0, 0]), ([7, 1, 3], [3, 21, 7]), ([4, 5, 1, 8, 2], [80, 64, 320, 40, 160])]",
"body": " result = run_product_except_self(Solution, nums)\n assert_product_except_self(result, expected)"
}
]
diff --git a/.templates/leetcode/json/reverse_linked_list.json b/.templates/leetcode/json/reverse_linked_list.json
index 2166957..9ea3b51 100644
--- a/.templates/leetcode/json/reverse_linked_list.json
+++ b/.templates/leetcode/json/reverse_linked_list.json
@@ -53,7 +53,7 @@
"name": "test_reverse_list",
"signature": "(self, head_list: list[int], expected_list: list[int])",
"parametrize": "head_list, expected_list",
- "test_cases": "[([1, 2, 3, 4, 5], [5, 4, 3, 2, 1]), ([1, 2], [2, 1]), ([1], [1]), ([], []), ([1, 2, 3], [3, 2, 1]), ([1, 2, 3, 4], [4, 3, 2, 1]), ([-1, -2, -3], [-3, -2, -1]), ([0], [0]), ([5000, -5000], [-5000, 5000]), ([1, 1, 1], [1, 1, 1])]",
+ "test_cases": "[([1, 2, 3, 4, 5], [5, 4, 3, 2, 1]), ([1, 2], [2, 1]), ([1], [1]), ([], []), ([1, 2, 3], [3, 2, 1]), ([1, 2, 3, 4], [4, 3, 2, 1]), ([-1, -2, -3], [-3, -2, -1]), ([0], [0]), ([5000, -5000], [-5000, 5000]), ([1, 1, 1], [1, 1, 1]), ([10, 20, 30, 40, 50, 60], [60, 50, 40, 30, 20, 10]), ([-100, 0, 100], [100, 0, -100]), ([7], [7]), ([1, 2, 3, 4, 5, 6, 7], [7, 6, 5, 4, 3, 2, 1]), ([42, 42, 42, 42], [42, 42, 42, 42])]",
"body": " result = run_reverse_list(Solution, head_list)\n assert_reverse_list(result, expected_list)"
}
]
diff --git a/.templates/leetcode/json/reverse_linked_list_ii.json b/.templates/leetcode/json/reverse_linked_list_ii.json
index 2efc947..75d9318 100644
--- a/.templates/leetcode/json/reverse_linked_list_ii.json
+++ b/.templates/leetcode/json/reverse_linked_list_ii.json
@@ -50,7 +50,7 @@
"name": "test_reverse_between",
"signature": "(self, head_list: list[int], left: int, right: int, expected_list: list[int])",
"parametrize": "head_list, left, right, expected_list",
- "test_cases": "[([1, 2, 3, 4, 5], 2, 4, [1, 4, 3, 2, 5]), ([5], 1, 1, [5]), ([1, 2], 1, 2, [2, 1]), ([1, 2, 3], 1, 3, [3, 2, 1]), ([1, 2, 3, 4, 5], 1, 5, [5, 4, 3, 2, 1]), ([1, 2, 3, 4, 5], 3, 3, [1, 2, 3, 4, 5])]",
+ "test_cases": "[([1, 2, 3, 4, 5], 2, 4, [1, 4, 3, 2, 5]), ([5], 1, 1, [5]), ([1, 2], 1, 2, [2, 1]), ([1, 2, 3], 1, 3, [3, 2, 1]), ([1, 2, 3, 4, 5], 1, 5, [5, 4, 3, 2, 1]), ([1, 2, 3, 4, 5], 3, 3, [1, 2, 3, 4, 5]), ([1, 2, 3, 4], 2, 3, [1, 3, 2, 4]), ([1, 2, 3, 4, 5, 6], 3, 5, [1, 2, 5, 4, 3, 6]), ([10], 1, 1, [10]), ([1, 2, 3, 4, 5, 6, 7], 1, 7, [7, 6, 5, 4, 3, 2, 1]), ([3, 5], 1, 1, [3, 5]), ([7, 9, 2, 10, 1, 8, 6], 4, 6, [7, 9, 2, 8, 1, 10, 6])]",
"body": " result = run_reverse_between(Solution, head_list, left, right)\n assert_reverse_between(result, expected_list)"
}
]
diff --git a/.templates/leetcode/json/search_in_rotated_sorted_array.json b/.templates/leetcode/json/search_in_rotated_sorted_array.json
index 9f2165b..b20a54c 100644
--- a/.templates/leetcode/json/search_in_rotated_sorted_array.json
+++ b/.templates/leetcode/json/search_in_rotated_sorted_array.json
@@ -49,7 +49,7 @@
"name": "test_search",
"signature": "(self, nums: list[int], target: int, expected: int)",
"parametrize": "nums, target, expected",
- "test_cases": "[([4, 5, 6, 7, 0, 1, 2], 0, 4), ([4, 5, 6, 7, 0, 1, 2], 3, -1), ([1], 0, -1), ([1], 1, 0), ([3, 1], 1, 1), ([1, 3], 3, 1), ([2, 1], 2, 0), ([5, 1, 3], 3, 2), ([4, 5, 6, 7, 8, 1, 2, 3], 8, 4)]",
+ "test_cases": "[([4, 5, 6, 7, 0, 1, 2], 0, 4), ([4, 5, 6, 7, 0, 1, 2], 3, -1), ([1], 0, -1), ([1], 1, 0), ([3, 1], 1, 1), ([1, 3], 3, 1), ([2, 1], 2, 0), ([5, 1, 3], 3, 2), ([4, 5, 6, 7, 8, 1, 2, 3], 8, 4), ([6, 7, 0, 1, 2, 3, 4, 5], 6, 0), ([7, 0, 1, 2, 3, 4, 5, 6], 7, 0), ([0, 1, 2, 3, 4, 5, 6, 7], 4, 4), ([3, 4, 5, 6, 7, 0, 1, 2], 2, 7), ([9, 0, 2, 7, 8], 3, -1), ([8, 9, 2, 3, 4], 9, 1)]",
"body": " result = run_search(Solution, nums, target)\n assert_search(result, expected)"
}
]
diff --git a/.templates/leetcode/json/serialize_and_deserialize_binary_tree.json b/.templates/leetcode/json/serialize_and_deserialize_binary_tree.json
index 552c8b7..e45c6e4 100644
--- a/.templates/leetcode/json/serialize_and_deserialize_binary_tree.json
+++ b/.templates/leetcode/json/serialize_and_deserialize_binary_tree.json
@@ -58,7 +58,7 @@
"name": "test_serialize_deserialize",
"signature": "(self, root_list: list[int | None])",
"parametrize": "root_list",
- "test_cases": "[([1, 2, 3, None, None, 4, 5]), ([]), ([1]), ([1, 2]), ([1, None, 2]), ([1, 2, 3, 4, 5, 6, 7]), ([5, 2, 3, None, None, 2, 4, 3, 1])]",
+ "test_cases": "[([1, 2, 3, None, None, 4, 5]), ([]), ([1]), ([1, 2]), ([1, None, 2]), ([1, 2, 3, 4, 5, 6, 7]), ([5, 2, 3, None, None, 2, 4, 3, 1]), ([1, 2, 3]), ([1, None, None]), ([1, 2, None, 4]), ([1, None, 2, None, 3]), ([10, 5, 15, None, 6, 12, 20]), ([0, -1, 1]), ([100]), ([1, 2, 3, 4, None, None, 7, 8])]",
"body": " result = run_serialize_deserialize(Codec, root_list)\n assert_serialize_deserialize(result, root_list)"
}
]
diff --git a/.templates/leetcode/json/sort_colors.json b/.templates/leetcode/json/sort_colors.json
index 3525a54..6633cb0 100644
--- a/.templates/leetcode/json/sort_colors.json
+++ b/.templates/leetcode/json/sort_colors.json
@@ -48,7 +48,7 @@
"name": "test_sort_colors",
"signature": "(self, nums: list[int], expected: list[int])",
"parametrize": "nums, expected",
- "test_cases": "[([2, 0, 2, 1, 1, 0], [0, 0, 1, 1, 2, 2]), ([2, 0, 1], [0, 1, 2]), ([0], [0]), ([1], [1]), ([2], [2]), ([0, 1, 2], [0, 1, 2]), ([2, 2, 2], [2, 2, 2]), ([0, 0, 0], [0, 0, 0]), ([1, 1, 1], [1, 1, 1])]",
+ "test_cases": "[([2, 0, 2, 1, 1, 0], [0, 0, 1, 1, 2, 2]), ([2, 0, 1], [0, 1, 2]), ([0], [0]), ([1], [1]), ([2], [2]), ([0, 1, 2], [0, 1, 2]), ([2, 2, 2], [2, 2, 2]), ([0, 0, 0], [0, 0, 0]), ([1, 1, 1], [1, 1, 1]), ([2, 1, 0], [0, 1, 2]), ([1, 0, 2, 1, 0, 2], [0, 0, 1, 1, 2, 2]), ([0, 2, 1, 0, 2, 1], [0, 0, 1, 1, 2, 2]), ([2, 2, 1, 0, 0, 1], [0, 0, 1, 1, 2, 2]), ([1, 2, 0, 1, 2, 0, 1], [0, 0, 1, 1, 1, 2, 2]), ([0, 1, 0, 2, 1, 2, 0], [0, 0, 0, 1, 1, 2, 2])]",
"body": " result = run_sort_colors(Solution, nums)\n assert_sort_colors(result, expected)"
}
]
diff --git a/.templates/leetcode/json/spiral_matrix.json b/.templates/leetcode/json/spiral_matrix.json
index db80ac1..355427b 100644
--- a/.templates/leetcode/json/spiral_matrix.json
+++ b/.templates/leetcode/json/spiral_matrix.json
@@ -52,7 +52,7 @@
"name": "test_spiral_order",
"signature": "(self, matrix: list[list[int]], expected: list[int])",
"parametrize": "matrix, expected",
- "test_cases": "[([[1,2,3],[4,5,6],[7,8,9]], [1,2,3,6,9,8,7,4,5]), ([[1,2,3,4],[5,6,7,8],[9,10,11,12]], [1,2,3,4,8,12,11,10,9,5,6,7]), ([[1]], [1]), ([[1,2]], [1,2]), ([[1],[2]], [1,2]), ([[1,2,3]], [1,2,3]), ([[1],[2],[3]], [1,2,3])]",
+ "test_cases": "[([[1,2,3],[4,5,6],[7,8,9]], [1,2,3,6,9,8,7,4,5]), ([[1,2,3,4],[5,6,7,8],[9,10,11,12]], [1,2,3,4,8,12,11,10,9,5,6,7]), ([[1]], [1]), ([[1,2]], [1,2]), ([[1],[2]], [1,2]), ([[1,2,3]], [1,2,3]), ([[1],[2],[3]], [1,2,3]), ([[1,2],[3,4]], [1,2,4,3]), ([[1,2,3,4,5]], [1,2,3,4,5]), ([[1],[2],[3],[4],[5]], [1,2,3,4,5]), ([[1,2,3],[4,5,6]], [1,2,3,6,5,4]), ([[1,2],[3,4],[5,6]], [1,2,4,6,5,3]), ([[7,9,6],[2,8,6],[1,3,5]], [7,9,6,6,5,3,1,2,8]), ([[1,2,3,4],[5,6,7,8]], [1,2,3,4,8,7,6,5])]",
"body": " result = run_spiral_order(Solution, matrix)\n assert_spiral_order(result, expected)"
}
]
diff --git a/.templates/leetcode/json/task_scheduler.json b/.templates/leetcode/json/task_scheduler.json
index 908512f..a416607 100644
--- a/.templates/leetcode/json/task_scheduler.json
+++ b/.templates/leetcode/json/task_scheduler.json
@@ -55,7 +55,7 @@
"name": "test_least_interval",
"signature": "(self, tasks: list[str], n: int, expected: int)",
"parametrize": "tasks, n, expected",
- "test_cases": "[(['A', 'A', 'A', 'B', 'B', 'B'], 2, 8), (['A', 'C', 'A', 'B', 'D', 'B'], 1, 6), (['A', 'A', 'A', 'B', 'B', 'B'], 3, 10), (['A'], 0, 1), (['A', 'A'], 1, 3), (['A', 'B'], 0, 2)]",
+ "test_cases": "[(['A', 'A', 'A', 'B', 'B', 'B'], 2, 8), (['A', 'C', 'A', 'B', 'D', 'B'], 1, 6), (['A', 'A', 'A', 'B', 'B', 'B'], 3, 10), (['A'], 0, 1), (['A', 'A'], 1, 3), (['A', 'B'], 0, 2), (['A', 'A', 'A'], 0, 3), (['A', 'B', 'C', 'D', 'E', 'F'], 2, 6), (['A', 'A', 'A', 'A', 'A', 'A', 'B', 'C', 'D', 'E', 'F', 'G'], 2, 16), (['A', 'A', 'B', 'B'], 2, 5), (['A', 'B', 'A', 'B'], 1, 4), (['A', 'A', 'A', 'A'], 3, 13)]",
"body": " result = run_least_interval(Solution, tasks, n)\n assert_least_interval(result, expected)"
}
]
diff --git a/.templates/leetcode/json/three_sum.json b/.templates/leetcode/json/three_sum.json
index e80a8d6..2f099e1 100644
--- a/.templates/leetcode/json/three_sum.json
+++ b/.templates/leetcode/json/three_sum.json
@@ -55,7 +55,7 @@
"name": "test_three_sum",
"signature": "(self, nums: list[int], expected: list[list[int]])",
"parametrize": "nums, expected",
- "test_cases": "[([-1, 0, 1, 2, -1, -4], [[-1, -1, 2], [-1, 0, 1]]), ([0, 1, 1], []), ([0, 0, 0], [[0, 0, 0]]), ([-1, 0, 1], [[-1, 0, 1]]), ([1, 2, -2, -1], []), ([-2, 0, 1, 1, 2], [[-2, 0, 2], [-2, 1, 1]])]",
+ "test_cases": "[([-1, 0, 1, 2, -1, -4], [[-1, -1, 2], [-1, 0, 1]]), ([0, 1, 1], []), ([0, 0, 0], [[0, 0, 0]]), ([-1, 0, 1], [[-1, 0, 1]]), ([1, 2, -2, -1], []), ([-2, 0, 1, 1, 2], [[-2, 0, 2], [-2, 1, 1]]), ([1, -1, -1, 0], [[-1, 0, 1]]), ([-4, -2, -2, -2, 0, 1, 2, 2, 2, 3, 3, 4, 4, 6, 6], [[-4, -2, 6], [-4, 0, 4], [-4, 1, 3], [-4, 2, 2], [-2, -2, 4], [-2, 0, 2]]), ([3, 0, -2, -1, 1, 2], [[-2, -1, 3], [-2, 0, 2], [-1, 0, 1]]), ([0, 0, 0, 0], [[0, 0, 0]]), ([-1, -1, 2], [[-1, -1, 2]]), ([1, 1, -2], [[-2, 1, 1]])]",
"body": " result = run_three_sum(Solution, nums)\n assert_three_sum(result, expected)"
}
]
diff --git a/.templates/leetcode/json/trapping_rain_water.json b/.templates/leetcode/json/trapping_rain_water.json
index 5b44338..4a21e57 100644
--- a/.templates/leetcode/json/trapping_rain_water.json
+++ b/.templates/leetcode/json/trapping_rain_water.json
@@ -50,7 +50,7 @@
"name": "test_trap",
"signature": "(self, height: list[int], expected: int)",
"parametrize": "height, expected",
- "test_cases": "[([0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1], 6), ([4, 2, 0, 3, 2, 5], 9), ([3, 0, 2, 0, 4], 7), ([0], 0), ([1], 0), ([1, 2], 0), ([2, 1], 0)]",
+ "test_cases": "[([0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1], 6), ([4, 2, 0, 3, 2, 5], 9), ([3, 0, 2, 0, 4], 7), ([0], 0), ([1], 0), ([1, 2], 0), ([2, 1], 0), ([3, 2, 0, 4], 4), ([5, 4, 1, 2], 1), ([2, 0, 2], 2), ([1, 0, 1], 1), ([0, 2, 0], 0), ([1, 2, 1], 0), ([5, 2, 7, 2, 6, 1, 5, 3, 2, 1], 11), ([0, 0, 0, 0], 0)]",
"body": " result = run_trap(Solution, height)\n assert_trap(result, expected)"
}
]
diff --git a/.templates/leetcode/json/valid_palindrome.json b/.templates/leetcode/json/valid_palindrome.json
index 3e264eb..4f84dc9 100644
--- a/.templates/leetcode/json/valid_palindrome.json
+++ b/.templates/leetcode/json/valid_palindrome.json
@@ -55,7 +55,7 @@
"name": "test_is_palindrome",
"signature": "(self, s: str, expected: bool)",
"parametrize": "s, expected",
- "test_cases": "[(\"A man, a plan, a canal: Panama\", True), (\"race a car\", False), (\" \", True), (\"\", True), (\"a\", True), (\"Madam\", True), (\"No 'x' in Nixon\", True), (\"Mr. Owl ate my metal worm\", True)]",
+ "test_cases": "[(\"A man, a plan, a canal: Panama\", True), (\"race a car\", False), (\" \", True), (\"\", True), (\"a\", True), (\"Madam\", True), (\"No 'x' in Nixon\", True), (\"Mr. Owl ate my metal worm\", True), (\"Was it a car or a cat I saw?\", True), (\"Madam, I'm Adam\", True), (\"Never odd or even\", True), (\"Do geese see God?\", True), (\"Step on no pets\", True), (\"12321\", True), (\"hello\", False), (\"ab\", False)]",
"body": " result = run_is_palindrome(Solution, s)\n assert_is_palindrome(result, expected)"
}
]
diff --git a/.templates/leetcode/json/valid_parentheses.json b/.templates/leetcode/json/valid_parentheses.json
index cc3c986..554ca10 100644
--- a/.templates/leetcode/json/valid_parentheses.json
+++ b/.templates/leetcode/json/valid_parentheses.json
@@ -51,7 +51,7 @@
"name": "test_is_valid",
"signature": "(self, s: str, expected: bool)",
"parametrize": "s, expected",
- "test_cases": "[('()', True), ('()[]{}', True), ('(]', False), ('([])', True), ('([)]', False), ('', True), ('(', False), (')', False), ('{[()]}', True), ('{[(])}', False)]",
+ "test_cases": "[('()', True), ('()[]{}', True), ('(]', False), ('([])', True), ('([)]', False), ('', True), ('(', False), (')', False), ('{[()]}', True), ('{[(])}', False), ('((', False), ('))', False), ('([{}])', True), ('([{]})', False), ('{[}]', False), ('((()))', True), ('((())', False), ('(){}[]', True), ('{[(', False), (']})', False)]",
"body": " result = run_is_valid(Solution, s)\n assert_is_valid(result, expected)"
}
]
diff --git a/.templates/leetcode/json/validate_binary_search_tree.json b/.templates/leetcode/json/validate_binary_search_tree.json
index ef141e2..b0202c1 100644
--- a/.templates/leetcode/json/validate_binary_search_tree.json
+++ b/.templates/leetcode/json/validate_binary_search_tree.json
@@ -52,7 +52,7 @@
"name": "test_is_valid_bst",
"signature": "(self, root_list: list[int | None], expected: bool)",
"parametrize": "root_list, expected",
- "test_cases": "[([2, 1, 3], True), ([5, 1, 4, None, None, 3, 6], False), ([1], True), ([1, 1], False), ([10, 5, 15, None, None, 6, 20], False), ([2, 1, 3, None, None, None, 4], True)]",
+ "test_cases": "[([2, 1, 3], True), ([5, 1, 4, None, None, 3, 6], False), ([1], True), ([1, 1], False), ([10, 5, 15, None, None, 6, 20], False), ([2, 1, 3, None, None, None, 4], True), ([0], True), ([2147483647], True), ([-2147483648], True), ([5, 4, 6, None, None, 3, 7], False), ([10, 5, 15, None, None, 12, 20, None, None, None, None, 6, 25], True), ([3, 1, 5, 0, 2, 4, 6], True)]",
"body": " result = run_is_valid_bst(Solution, root_list)\n assert_is_valid_bst(result, expected)"
}
]
diff --git a/.templates/leetcode/json/word_break.json b/.templates/leetcode/json/word_break.json
index 1a0f5c0..28a1de4 100644
--- a/.templates/leetcode/json/word_break.json
+++ b/.templates/leetcode/json/word_break.json
@@ -55,7 +55,7 @@
"name": "test_word_break",
"signature": "(self, s: str, word_dict: list[str], expected: bool)",
"parametrize": "s, word_dict, expected",
- "test_cases": "[('leetcode', ['leet', 'code'], True), ('applepenapple', ['apple', 'pen'], True), ('catsandog', ['cats', 'dog', 'sand', 'and', 'cat'], False), ('', [], True), ('a', ['a'], True), ('ab', ['a', 'b'], True), ('abcd', ['a', 'abc', 'd'], True)]",
+ "test_cases": "[('leetcode', ['leet', 'code'], True), ('applepenapple', ['apple', 'pen'], True), ('catsandog', ['cats', 'dog', 'sand', 'and', 'cat'], False), ('', [], True), ('a', ['a'], True), ('ab', ['a', 'b'], True), ('abcd', ['a', 'abc', 'd'], True), ('aaaaaaa', ['aaaa', 'aaa'], True), ('aaaaaaa', ['aaaa', 'aa'], False), ('cars', ['car', 'ca', 'rs'], True), ('raceacar', ['race', 'a', 'car'], True), ('abcdef', ['abc', 'def'], True), ('abcdef', ['ab', 'cd', 'ef'], True), ('goalspecial', ['go', 'goal', 'goals', 'special'], True), ('bb', ['a', 'b', 'bbb', 'bbbb'], True)]",
"body": " result = run_word_break(Solution, s, word_dict)\n assert_word_break(result, expected)"
}
]
diff --git a/.templates/leetcode/json/word_ladder.json b/.templates/leetcode/json/word_ladder.json
index 78cf3f5..216257a 100644
--- a/.templates/leetcode/json/word_ladder.json
+++ b/.templates/leetcode/json/word_ladder.json
@@ -52,7 +52,7 @@
"name": "test_ladder_length",
"signature": "(self, begin_word: str, end_word: str, word_list: list[str], expected: int)",
"parametrize": "begin_word, end_word, word_list, expected",
- "test_cases": "[('hit', 'cog', ['hot', 'dot', 'dog', 'lot', 'log', 'cog'], 5), ('hit', 'cog', ['hot', 'dot', 'dog', 'lot', 'log'], 0), ('a', 'c', ['a', 'b', 'c'], 2), ('hot', 'dog', ['hot', 'dog'], 0), ('hot', 'dog', ['hot', 'hog', 'dog'], 3)]",
+ "test_cases": "[(\"hit\", \"cog\", [\"hot\", \"dot\", \"dog\", \"lot\", \"log\", \"cog\"], 5), (\"hit\", \"cog\", [\"hot\", \"dot\", \"dog\", \"lot\", \"log\"], 0), (\"a\", \"c\", [\"a\", \"b\", \"c\"], 2), (\"hot\", \"dog\", [\"hot\", \"dog\"], 0), (\"hot\", \"dog\", [\"hot\", \"hog\", \"dog\"], 3), (\"red\", \"tax\", [\"ted\", \"tex\", \"red\", \"tax\", \"tad\", \"den\", \"rex\", \"pee\"], 4), (\"talk\", \"tail\", [\"talk\", \"tons\", \"fall\", \"tail\", \"gale\", \"hall\", \"negs\"], 0), (\"qa\", \"sq\", [\"si\", \"go\", \"se\", \"cm\", \"so\", \"ph\", \"mt\", \"db\", \"mb\", \"sb\", \"kr\", \"ln\", \"tm\", \"le\", \"av\", \"sm\", \"ar\", \"ci\", \"ca\", \"br\", \"ti\", \"ba\", \"to\", \"ra\", \"fa\", \"yo\", \"ow\", \"sn\", \"ya\", \"cr\", \"po\", \"fe\", \"ho\", \"ma\", \"re\", \"or\", \"rn\", \"au\", \"ur\", \"rh\", \"sr\", \"tc\", \"lt\", \"lo\", \"as\", \"fr\", \"nb\", \"yb\", \"if\", \"pb\", \"ge\", \"th\", \"pm\", \"rb\", \"sh\", \"co\", \"ga\", \"li\", \"ha\", \"hz\", \"no\", \"bi\", \"di\", \"hi\", \"qa\", \"pi\", \"os\", \"uh\", \"wm\", \"an\", \"me\", \"mo\", \"na\", \"la\", \"st\", \"er\", \"sc\", \"ne\", \"mn\", \"mi\", \"am\", \"ex\", \"pt\", \"io\", \"be\", \"fm\", \"ta\", \"tb\", \"ni\", \"mr\", \"pa\", \"he\", \"lr\", \"sq\", \"ye\"], 5), (\"cet\", \"ism\", [\"kid\", \"tag\", \"pup\", \"ail\", \"tun\", \"woo\"], 0), (\"lost\", \"miss\", [\"most\", \"mist\", \"miss\", \"lost\", \"fist\", \"fish\"], 4), (\"cat\", \"dog\", [\"bat\", \"bag\", \"dag\", \"dog\", \"cat\"], 5), (\"game\", \"thee\", [\"frye\", \"heat\", \"tree\", \"thee\", \"game\", \"free\"], 0), (\"teach\", \"place\", [\"peale\", \"wilts\", \"place\", \"fetch\"], 0), (\"sail\", \"boat\", [\"bail\", \"foil\", \"coat\", \"boat\", \"sail\"], 0), (\"cold\", \"warm\", [\"cold\", \"cord\", \"word\", \"ward\", \"warm\"], 5)]",
"body": " result = run_ladder_length(Solution, begin_word, end_word, word_list)\n assert_ladder_length(result, expected)"
}
]
diff --git a/.templates/leetcode/json/zero_one_matrix.json b/.templates/leetcode/json/zero_one_matrix.json
index 81ab126..f0bac0c 100644
--- a/.templates/leetcode/json/zero_one_matrix.json
+++ b/.templates/leetcode/json/zero_one_matrix.json
@@ -52,7 +52,7 @@
"name": "test_update_matrix",
"signature": "(self, mat: list[list[int]], expected: list[list[int]])",
"parametrize": "mat, expected",
- "test_cases": "[([[0, 0, 0], [0, 1, 0], [0, 0, 0]], [[0, 0, 0], [0, 1, 0], [0, 0, 0]]), ([[0, 0, 0], [0, 1, 0], [1, 1, 1]], [[0, 0, 0], [0, 1, 0], [1, 2, 1]]), ([[0]], [[0]]), ([[1, 0]], [[1, 0]])]",
+ "test_cases": "[([[0, 0, 0], [0, 1, 0], [0, 0, 0]], [[0, 0, 0], [0, 1, 0], [0, 0, 0]]), ([[0, 0, 0], [0, 1, 0], [1, 1, 1]], [[0, 0, 0], [0, 1, 0], [1, 2, 1]]), ([[0]], [[0]]), ([[1, 0]], [[1, 0]]), ([[1, 1], [1, 0]], [[2, 1], [1, 0]]), ([[0, 1, 0], [1, 1, 1], [0, 1, 0]], [[0, 1, 0], [1, 2, 1], [0, 1, 0]]), ([[1, 0, 1], [1, 1, 1], [1, 1, 1]], [[1, 0, 1], [2, 1, 2], [3, 2, 3]]), ([[0, 1, 0, 0], [1, 1, 1, 0], [1, 1, 1, 0]], [[0, 1, 0, 0], [1, 2, 1, 0], [2, 2, 1, 0]]), ([[1, 1, 1], [1, 1, 1], [1, 1, 0]], [[4, 3, 2], [3, 2, 1], [2, 1, 0]]), ([[0, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]], [[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]), ([[1, 0, 0], [1, 1, 0], [1, 1, 1]], [[1, 0, 0], [2, 1, 0], [3, 2, 1]]), ([[0, 0, 1], [0, 1, 1], [1, 1, 1]], [[0, 0, 1], [0, 1, 2], [1, 2, 3]]), ([[1, 1, 0, 1], [1, 0, 1, 1], [0, 1, 1, 1]], [[2, 1, 0, 1], [1, 0, 1, 2], [0, 1, 2, 3]])]",
"body": " result = run_update_matrix(Solution, mat)\n assert_update_matrix(result, expected)"
}
]
diff --git a/leetcode/accounts_merge/test_solution.py b/leetcode/accounts_merge/test_solution.py
index 5b98579..fc73296 100644
--- a/leetcode/accounts_merge/test_solution.py
+++ b/leetcode/accounts_merge/test_solution.py
@@ -44,7 +44,6 @@ def setup_method(self):
],
),
([["John", "john@mail.com"]], [["John", "john@mail.com"]]),
- ([["John"]], [["John"]]),
(
[["John", "john1@mail.com"], ["John", "john2@mail.com"], ["John", "john3@mail.com"]],
[["John", "john1@mail.com"], ["John", "john2@mail.com"], ["John", "john3@mail.com"]],
@@ -65,7 +64,44 @@ def setup_method(self):
],
[["Alice", "alice1@mail.com", "alice2@mail.com", "alice3@mail.com", "alice@mail.com"]],
),
- ([["John", "shared@mail.com"], ["Jane", "shared@mail.com"]], [["John", "shared@mail.com"]]),
+ ([["Bob", "bob@mail.com"], ["Bob", "bob@mail.com"]], [["Bob", "bob@mail.com"]]),
+ (
+ [
+ ["David", "david1@mail.com", "david2@mail.com"],
+ ["David", "david3@mail.com"],
+ ["David", "david2@mail.com", "david4@mail.com"],
+ ],
+ [
+ ["David", "david1@mail.com", "david2@mail.com", "david4@mail.com"],
+ ["David", "david3@mail.com"],
+ ],
+ ),
+ (
+ [
+ ["Alex", "alex@mail.com"],
+ ["Alex", "alex@mail.com", "alex2@mail.com"],
+ ["Alex", "alex3@mail.com"],
+ ],
+ [["Alex", "alex2@mail.com", "alex@mail.com"], ["Alex", "alex3@mail.com"]],
+ ),
+ (
+ [
+ ["Tom", "tom1@mail.com"],
+ ["Tom", "tom2@mail.com"],
+ ["Tom", "tom3@mail.com"],
+ ["Tom", "tom4@mail.com"],
+ ],
+ [
+ ["Tom", "tom1@mail.com"],
+ ["Tom", "tom2@mail.com"],
+ ["Tom", "tom3@mail.com"],
+ ["Tom", "tom4@mail.com"],
+ ],
+ ),
+ (
+ [["Sam", "sam@mail.com", "sam1@mail.com", "sam2@mail.com"]],
+ [["Sam", "sam@mail.com", "sam1@mail.com", "sam2@mail.com"]],
+ ),
],
)
def test_accounts_merge(self, accounts: list[list[str]], expected: list[list[str]]):
diff --git a/leetcode/balanced_binary_tree/test_solution.py b/leetcode/balanced_binary_tree/test_solution.py
index 08eaaa8..97000d1 100644
--- a/leetcode/balanced_binary_tree/test_solution.py
+++ b/leetcode/balanced_binary_tree/test_solution.py
@@ -22,6 +22,13 @@ def setup_method(self):
([1, None, 2], True),
([1, 2, 3, 4], True),
([1, 2, 2, 3, None, None, 3, 4, None, None, 4], False),
+ ([1, 2, 3], True),
+ ([1, 2, None, 3], False),
+ ([1, None, 2, None, 3], False),
+ ([1, 2, 3, 4, 5, 6, 7], True),
+ ([1, 2, 3, None, None, 4, None, None, 5], False),
+ ([5, 1, 4, None, None, 3, 6], True),
+ ([1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, None, None, 5, 5], True),
],
)
def test_is_balanced(self, root_list: list[int | None], expected: bool):
diff --git a/leetcode/best_time_to_buy_and_sell_stock/test_solution.py b/leetcode/best_time_to_buy_and_sell_stock/test_solution.py
index d889ade..4ed9be5 100644
--- a/leetcode/best_time_to_buy_and_sell_stock/test_solution.py
+++ b/leetcode/best_time_to_buy_and_sell_stock/test_solution.py
@@ -22,6 +22,13 @@ def setup_method(self):
([2, 1], 0),
([1, 2], 1),
([3, 2, 6, 5, 0, 3], 4),
+ ([2, 4, 1], 2),
+ ([1, 5, 3, 6, 4], 5),
+ ([10, 1, 5, 6, 7, 1], 6),
+ ([6, 1, 3, 2, 4, 7], 6),
+ ([1, 4, 2], 3),
+ ([3, 3, 5, 0, 0, 3, 1, 4], 4),
+ ([2, 1, 2, 1, 0, 1, 2], 2),
],
)
def test_max_profit(self, prices: list[int], expected: int):
diff --git a/leetcode/binary_tree_right_side_view/test_solution.py b/leetcode/binary_tree_right_side_view/test_solution.py
index 1da8582..2a1ca50 100644
--- a/leetcode/binary_tree_right_side_view/test_solution.py
+++ b/leetcode/binary_tree_right_side_view/test_solution.py
@@ -3,7 +3,7 @@
from leetcode_py.test_utils import logged_test
from .helpers import assert_right_side_view, run_right_side_view
-from .solution import Solution, SolutionBFS, SolutionDFS
+from .solution import Solution
class TestBinaryTreeRightSideView:
@@ -11,7 +11,6 @@ def setup_method(self):
self.solution = Solution()
@logged_test
- @pytest.mark.parametrize("solution_class", [Solution, SolutionBFS, SolutionDFS])
@pytest.mark.parametrize(
"root_list, expected",
[
@@ -22,10 +21,15 @@ def setup_method(self):
([1], [1]),
([1, 2], [1, 2]),
([1, None, 2], [1, 2]),
+ ([1, 2, 3], [1, 3]),
+ ([1, 2, None, 4], [1, 2, 4]),
+ ([1, 2, 3, 4, 5, 6, 7], [1, 3, 7]),
+ ([1, 2, 3, None, None, 4, 5], [1, 3, 5]),
+ ([5, 4, 6, None, None, None, 7], [5, 6, 7]),
+ ([1, 2, 3, 4, 5, None, None, 8], [1, 3, 5, 8]),
+ ([10, 5, 15, None, 6, 12, 20], [10, 15, 20]),
],
)
- def test_right_side_view(
- self, solution_class: type, root_list: list[int | None], expected: list[int]
- ):
- result = run_right_side_view(solution_class, root_list)
+ def test_right_side_view(self, root_list: list[int | None], expected: list[int]):
+ result = run_right_side_view(Solution, root_list)
assert_right_side_view(result, expected)
diff --git a/leetcode/climbing_stairs/test_solution.py b/leetcode/climbing_stairs/test_solution.py
index 7e80934..a141b4e 100644
--- a/leetcode/climbing_stairs/test_solution.py
+++ b/leetcode/climbing_stairs/test_solution.py
@@ -13,7 +13,25 @@ def setup_method(self):
@logged_test
@pytest.mark.parametrize(
"n, expected",
- [(1, 1), (2, 2), (3, 3), (4, 5), (5, 8), (6, 13), (10, 89), (20, 10946), (45, 1836311903)],
+ [
+ (1, 1),
+ (2, 2),
+ (3, 3),
+ (4, 5),
+ (5, 8),
+ (6, 13),
+ (7, 21),
+ (8, 34),
+ (9, 55),
+ (10, 89),
+ (15, 987),
+ (20, 10946),
+ (25, 121393),
+ (30, 1346269),
+ (35, 14930352),
+ (40, 165580141),
+ (45, 1836311903),
+ ],
)
def test_climb_stairs(self, n: int, expected: int):
result = run_climb_stairs(Solution, n)
diff --git a/leetcode/coin_change/test_solution.py b/leetcode/coin_change/test_solution.py
index a49a846..62eede4 100644
--- a/leetcode/coin_change/test_solution.py
+++ b/leetcode/coin_change/test_solution.py
@@ -23,6 +23,12 @@ def setup_method(self):
([1], 1, 1),
([1, 2], 2, 1),
([186, 419, 83, 408], 6249, 20),
+ ([1, 5, 10, 25], 30, 2),
+ ([2, 3, 5], 9, 3),
+ ([1, 4, 5], 8, 2),
+ ([3, 5], 1, -1),
+ ([1, 2, 5], 100, 20),
+ ([7, 11], 14, 2),
],
)
def test_coin_change(self, coins: list[int], amount: int, expected: int):
diff --git a/leetcode/combination_sum/test_solution.py b/leetcode/combination_sum/test_solution.py
index 3bbe52b..de34df9 100644
--- a/leetcode/combination_sum/test_solution.py
+++ b/leetcode/combination_sum/test_solution.py
@@ -17,6 +17,15 @@ def setup_method(self):
([2, 3, 6, 7], 7, [[2, 2, 3], [7]]),
([2, 3, 5], 8, [[2, 2, 2, 2], [2, 3, 3], [3, 5]]),
([2], 1, []),
+ ([2, 3], 1, []),
+ ([3, 5], 3, [[3]]),
+ ([2, 4], 6, [[2, 2, 2], [2, 4]]),
+ ([5], 5, [[5]]),
+ ([2, 3, 4], 6, [[2, 2, 2], [2, 4], [3, 3]]),
+ ([4, 2, 8], 8, [[2, 2, 2, 2], [2, 2, 4], [4, 4], [8]]),
+ ([3, 4, 5], 9, [[3, 3, 3], [4, 5]]),
+ ([6, 3, 2], 6, [[2, 2, 2], [3, 3], [6]]),
+ ([2, 7], 9, [[2, 7]]),
],
)
def test_combination_sum(self, candidates: list[int], target: int, expected: list[list[int]]):
diff --git a/leetcode/container_with_most_water/test_solution.py b/leetcode/container_with_most_water/test_solution.py
index 4ac5842..c2bf0e1 100644
--- a/leetcode/container_with_most_water/test_solution.py
+++ b/leetcode/container_with_most_water/test_solution.py
@@ -12,7 +12,21 @@ def setup_method(self):
@logged_test
@pytest.mark.parametrize(
- "height, expected", [([1, 8, 6, 2, 5, 4, 8, 3, 7], 49), ([1, 1], 1), ([1, 2, 1], 2)]
+ "height, expected",
+ [
+ ([1, 8, 6, 2, 5, 4, 8, 3, 7], 49),
+ ([1, 1], 1),
+ ([1, 2, 1], 2),
+ ([2, 1], 1),
+ ([1, 2, 4, 3], 4),
+ ([1, 3, 2, 5, 25, 24, 5], 24),
+ ([2, 3, 4, 5, 18, 17, 6], 17),
+ ([1, 2, 3, 4, 5], 6),
+ ([5, 4, 3, 2, 1], 6),
+ ([0, 2], 0),
+ ([3, 9, 3, 4, 7, 2, 12, 6], 45),
+ ([1, 0, 0, 0, 0, 0, 0, 2, 2], 8),
+ ],
)
def test_max_area(self, height: list[int], expected: int):
result = run_max_area(Solution, height)
diff --git a/leetcode/contains_duplicate/test_solution.py b/leetcode/contains_duplicate/test_solution.py
index 5eaa35a..e8c2c7e 100644
--- a/leetcode/contains_duplicate/test_solution.py
+++ b/leetcode/contains_duplicate/test_solution.py
@@ -13,7 +13,20 @@ def setup_method(self):
@logged_test
@pytest.mark.parametrize(
"nums, expected",
- [([1, 2, 3, 1], True), ([1, 2, 3, 4], False), ([1, 1, 1, 3, 3, 4, 3, 2, 4, 2], True)],
+ [
+ ([1, 2, 3, 1], True),
+ ([1, 2, 3, 4], False),
+ ([1, 1, 1, 3, 3, 4, 3, 2, 4, 2], True),
+ ([1], False),
+ ([1, 1], True),
+ ([0, 0], True),
+ ([-1, -1], True),
+ ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], False),
+ ([10, 9, 8, 7, 6, 5, 4, 3, 2, 1], False),
+ ([1, 2, 3, 4, 5, 1], True),
+ ([-1000000000, 1000000000, -1000000000], True),
+ ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0], True),
+ ],
)
def test_contains_duplicate(self, nums: list[int], expected: bool):
result = run_contains_duplicate(Solution, nums)
diff --git a/leetcode/course_schedule/test_solution.py b/leetcode/course_schedule/test_solution.py
index 2fc24fc..35aae35 100644
--- a/leetcode/course_schedule/test_solution.py
+++ b/leetcode/course_schedule/test_solution.py
@@ -19,6 +19,13 @@ def setup_method(self):
(1, [], True),
(3, [[1, 0], [2, 1]], True),
(4, [[1, 0], [2, 1], [3, 2], [1, 3]], False),
+ (3, [[0, 1], [0, 2], [1, 2]], True),
+ (4, [[0, 1], [1, 2], [2, 3], [3, 1]], False),
+ (6, [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5]], True),
+ (3, [[1, 0], [2, 0]], True),
+ (5, [[0, 1], [1, 2], [2, 3], [3, 4], [4, 0]], False),
+ (4, [[1, 0], [2, 0], [3, 1], [3, 2]], True),
+ (5, [[1, 0], [2, 1], [3, 2], [4, 3], [0, 4]], False),
],
)
def test_can_finish(self, num_courses: int, prerequisites: list[list[int]], expected: bool):
diff --git a/leetcode/diameter_of_binary_tree/test_solution.py b/leetcode/diameter_of_binary_tree/test_solution.py
index 1abc301..11468a0 100644
--- a/leetcode/diameter_of_binary_tree/test_solution.py
+++ b/leetcode/diameter_of_binary_tree/test_solution.py
@@ -13,7 +13,20 @@ def setup_method(self):
@logged_test
@pytest.mark.parametrize(
"root_list, expected",
- [([1, 2, 3, 4, 5], 3), ([1, 2], 1), ([], 0), ([1], 0), ([1, 2, 3], 2), ([1, None, 2], 1)],
+ [
+ ([1, 2, 3, 4, 5], 3),
+ ([1, 2], 1),
+ ([], 0),
+ ([1], 0),
+ ([1, 2, 3], 2),
+ ([1, None, 2], 1),
+ ([1, 2, 3, 4, 5, None, None, 6, 7], 4),
+ ([4, 2, 6, 1, 3, 5, 7], 4),
+ ([1, 2, None, 3, None, 4], 3),
+ ([1, 2, 3, None, None, 4, 5, None, None, 6, 7], 4),
+ ([10, 5, 15, 3, 7, 12, 20], 4),
+ ([1, None, 2, None, 3, None, 4], 3),
+ ],
)
def test_diameter_of_binary_tree(self, root_list: list[int | None], expected: int):
result = run_diameter_of_binary_tree(Solution, root_list)
diff --git a/leetcode/evaluate_reverse_polish_notation/test_solution.py b/leetcode/evaluate_reverse_polish_notation/test_solution.py
index e422248..244730f 100644
--- a/leetcode/evaluate_reverse_polish_notation/test_solution.py
+++ b/leetcode/evaluate_reverse_polish_notation/test_solution.py
@@ -17,6 +17,16 @@ def setup_method(self):
(["2", "1", "+", "3", "*"], 9),
(["4", "13", "5", "/", "+"], 6),
(["10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+"], 22),
+ (["3"], 3),
+ (["15", "7", "1", "1", "+", "-", "/", "3", "*", "2", "1", "1", "+", "+", "-"], 5),
+ (["2", "1", "+"], 3),
+ (["2", "1", "-"], 1),
+ (["3", "4", "*"], 12),
+ (["8", "2", "/"], 4),
+ (["5", "1", "2", "+", "4", "*", "+", "3", "-"], 14),
+ (["-1", "2", "+"], 1),
+ (["0", "3", "/"], 0),
+ (["18", "6", "/", "3", "/"], 1),
],
)
def test_eval_rpn(self, tokens: list[str], expected: int):
diff --git a/leetcode/first_bad_version/test_solution.py b/leetcode/first_bad_version/test_solution.py
index 12f25a5..3ea5446 100644
--- a/leetcode/first_bad_version/test_solution.py
+++ b/leetcode/first_bad_version/test_solution.py
@@ -24,6 +24,11 @@ def setup_method(self):
(1000, 1, 1),
(1000, 999, 999),
(1000, 500, 500),
+ (20, 15, 15),
+ (50, 25, 25),
+ (8, 3, 3),
+ (16, 9, 9),
+ (200, 150, 150),
],
)
def test_first_bad_version(self, n: int, bad: int, expected: int):
diff --git a/leetcode/flood_fill/test_solution.py b/leetcode/flood_fill/test_solution.py
index ee4a476..c9703c3 100644
--- a/leetcode/flood_fill/test_solution.py
+++ b/leetcode/flood_fill/test_solution.py
@@ -18,6 +18,20 @@ def setup_method(self):
([[0, 0, 0], [0, 0, 0]], 0, 0, 0, [[0, 0, 0], [0, 0, 0]]),
([[0, 0, 0], [0, 1, 1]], 1, 1, 1, [[0, 0, 0], [0, 1, 1]]),
([[1, 1, 1], [1, 1, 0], [1, 0, 1]], 1, 1, 1, [[1, 1, 1], [1, 1, 0], [1, 0, 1]]),
+ ([[1]], 0, 0, 2, [[2]]),
+ ([[0, 1], [1, 0]], 0, 0, 3, [[3, 1], [1, 0]]),
+ ([[1, 1], [1, 1]], 0, 0, 2, [[2, 2], [2, 2]]),
+ ([[0, 1, 0], [1, 0, 1], [0, 1, 0]], 1, 1, 2, [[0, 1, 0], [1, 2, 1], [0, 1, 0]]),
+ ([[2, 2, 2], [2, 2, 0], [2, 0, 1]], 0, 0, 3, [[3, 3, 3], [3, 3, 0], [3, 0, 1]]),
+ ([[1, 0, 1], [0, 1, 0], [1, 0, 1]], 1, 1, 5, [[1, 0, 1], [0, 5, 0], [1, 0, 1]]),
+ (
+ [[0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0]],
+ 1,
+ 1,
+ 2,
+ [[0, 0, 0, 0], [0, 2, 2, 0], [0, 2, 2, 0], [0, 0, 0, 0]],
+ ),
+ ([[1, 2, 3], [4, 5, 6], [7, 8, 9]], 1, 1, 0, [[1, 2, 3], [4, 0, 6], [7, 8, 9]]),
],
)
def test_flood_fill(
diff --git a/leetcode/implement_queue_using_stacks/test_solution.py b/leetcode/implement_queue_using_stacks/test_solution.py
index 3363ac1..24520ea 100644
--- a/leetcode/implement_queue_using_stacks/test_solution.py
+++ b/leetcode/implement_queue_using_stacks/test_solution.py
@@ -27,6 +27,43 @@ class TestImplementQueueUsingStacks:
[[], [1], [2], [3], [], [], [], [], []],
[None, None, None, None, 1, 2, 3, 3, True],
),
+ (["MyQueue", "push", "peek", "pop"], [[], [5], [], []], [None, None, 5, 5]),
+ (
+ ["MyQueue", "push", "push", "pop", "push", "peek"],
+ [[], [1], [2], [], [3], []],
+ [None, None, None, 1, None, 2],
+ ),
+ (["MyQueue", "empty"], [[], []], [None, True]),
+ (
+ ["MyQueue", "push", "push", "push", "push", "pop", "pop", "pop", "pop", "empty"],
+ [[], [1], [2], [3], [4], [], [], [], [], []],
+ [None, None, None, None, None, 1, 2, 3, 4, True],
+ ),
+ (
+ ["MyQueue", "push", "pop", "push", "pop", "empty"],
+ [[], [7], [], [8], [], []],
+ [None, None, 7, None, 8, True],
+ ),
+ (
+ ["MyQueue", "push", "push", "peek", "peek", "pop", "peek"],
+ [[], [9], [8], [], [], [], []],
+ [None, None, None, 9, 9, 9, 8],
+ ),
+ (
+ ["MyQueue", "push", "push", "push", "push", "push", "pop", "pop", "pop", "push", "peek"],
+ [[], [1], [2], [3], [4], [5], [], [], [], [6], []],
+ [None, None, None, None, None, None, 1, 2, 3, None, 4],
+ ),
+ (
+ ["MyQueue", "push", "empty", "pop", "empty", "push", "empty"],
+ [[], [1], [], [], [], [2], []],
+ [None, None, False, 1, True, None, False],
+ ),
+ (
+ ["MyQueue", "push", "push", "push", "pop", "push", "pop", "pop", "push", "pop"],
+ [[], [1], [2], [3], [], [4], [], [], [5], []],
+ [None, None, None, None, 1, None, 2, 3, None, 4],
+ ),
],
)
def test_queue_operations(
diff --git a/leetcode/implement_trie_prefix_tree/test_solution.py b/leetcode/implement_trie_prefix_tree/test_solution.py
index 48a4c13..272e9bd 100644
--- a/leetcode/implement_trie_prefix_tree/test_solution.py
+++ b/leetcode/implement_trie_prefix_tree/test_solution.py
@@ -13,26 +13,93 @@ class TestImplementTriePrefixTree:
"operations, inputs, expected",
[
(
- ["Trie", "insert", "search", "search", "starts_with", "insert", "search"],
- [[], ["apple"], ["apple"], ["app"], ["app"], ["app"], ["app"]],
- [None, None, True, False, True, None, True],
+ ["Trie", "insert", "insert", "search", "search", "search"],
+ [[], ["app"], ["apple"], ["app"], ["apple"], ["appl"]],
+ [None, None, None, True, True, False],
),
(
- ["Trie", "insert", "insert", "search", "search", "starts_with", "starts_with"],
- [[], ["hello"], ["world"], ["hello"], ["hi"], ["hel"], ["wor"]],
- [None, None, None, True, False, True, True],
+ ["Trie", "insert", "insert", "insert", "search", "search", "search"],
+ [[], ["cat"], ["car"], ["card"], ["cat"], ["car"], ["care"]],
+ [None, None, None, None, True, True, False],
+ ),
+ (
+ ["Trie", "insert", "insert", "starts_with", "starts_with", "starts_with"],
+ [[], ["test"], ["testing"], ["test"], ["testing"], ["te"]],
+ [None, None, None, True, True, True],
+ ),
+ (
+ ["Trie", "insert", "search", "search", "insert", "search", "search"],
+ [[], ["abc"], ["abc"], ["ab"], ["ab"], ["ab"], ["abc"]],
+ [None, None, True, False, None, True, True],
+ ),
+ (
+ ["Trie", "insert", "search", "starts_with"],
+ [[], ["a"], ["a"], ["a"]],
+ [None, None, True, True],
+ ),
+ (
+ ["Trie", "search", "starts_with"],
+ [[], ["empty"], ["empty"]],
+ [None, False, False],
),
(
["Trie", "insert", "insert", "search", "search", "starts_with", "starts_with"],
- [[], ["a"], ["aa"], ["a"], ["aa"], ["a"], ["aa"]],
+ [[], ["word"], ["world"], ["word"], ["world"], ["wor"], ["wo"]],
[None, None, None, True, True, True, True],
),
+ (
+ ["Trie", "insert", "insert", "insert", "search", "search", "search", "starts_with"],
+ [[], ["aa"], ["aaa"], ["aaaa"], ["aa"], ["aaa"], ["aaaa"], ["a"]],
+ [None, None, None, None, True, True, True, True],
+ ),
+ (
+ ["Trie", "insert", "search", "search", "starts_with", "starts_with"],
+ [[], ["hello"], ["hello"], ["hell"], ["hello"], ["hel"]],
+ [None, None, True, False, True, True],
+ ),
+ (
+ [
+ "Trie",
+ "insert",
+ "insert",
+ "insert",
+ "search",
+ "search",
+ "search",
+ "starts_with",
+ "starts_with",
+ ],
+ [[], ["she"], ["sells"], ["sea"], ["she"], ["shells"], ["sea"], ["se"], ["s"]],
+ [None, None, None, None, True, False, True, True, True],
+ ),
+ (
+ [
+ "Trie",
+ "insert",
+ "insert",
+ "search",
+ "search",
+ "starts_with",
+ "starts_with",
+ "starts_with",
+ ],
+ [
+ [],
+ ["programming"],
+ ["program"],
+ ["programming"],
+ ["program"],
+ ["prog"],
+ ["programming"],
+ ["programm"],
+ ],
+ [None, None, None, True, True, True, True, True],
+ ),
(
["Trie", "insert", "search", "starts_with", "insert", "search", "starts_with"],
- [[], ["test"], ["testing"], ["test"], ["testing"], ["testing"], ["test"]],
- [None, None, False, True, None, True, True],
+ [[], ["z"], ["z"], ["z"], ["zzz"], ["zzz"], ["zz"]],
+ [None, None, True, True, None, True, True],
),
- (["Trie", "search", "starts_with"], [[], ["empty"], ["empty"]], [None, False, False]),
],
)
def test_trie_operations(
diff --git a/leetcode/insert_interval/test_solution.py b/leetcode/insert_interval/test_solution.py
index 7e83e00..a7ab73d 100644
--- a/leetcode/insert_interval/test_solution.py
+++ b/leetcode/insert_interval/test_solution.py
@@ -21,6 +21,13 @@ def setup_method(self):
([[1, 5]], [6, 8], [[1, 5], [6, 8]]),
([[1, 5]], [0, 0], [[0, 0], [1, 5]]),
([[3, 5], [12, 15]], [6, 6], [[3, 5], [6, 6], [12, 15]]),
+ ([[1, 2], [4, 5]], [3, 3], [[1, 2], [3, 3], [4, 5]]),
+ ([[2, 5], [6, 7], [8, 9]], [0, 1], [[0, 1], [2, 5], [6, 7], [8, 9]]),
+ ([[1, 3], [6, 9]], [10, 12], [[1, 3], [6, 9], [10, 12]]),
+ ([[1, 4], [5, 6]], [2, 3], [[1, 4], [5, 6]]),
+ ([[1, 2], [3, 4], [5, 6]], [0, 7], [[0, 7]]),
+ ([[2, 3], [5, 6]], [1, 4], [[1, 4], [5, 6]]),
+ ([[1, 5], [10, 15]], [6, 9], [[1, 5], [6, 9], [10, 15]]),
],
)
def test_insert(
diff --git a/leetcode/invert_binary_tree/test_solution.py b/leetcode/invert_binary_tree/test_solution.py
index 9e8cf8e..f20e784 100644
--- a/leetcode/invert_binary_tree/test_solution.py
+++ b/leetcode/invert_binary_tree/test_solution.py
@@ -3,7 +3,7 @@
from leetcode_py.test_utils import logged_test
from .helpers import assert_invert_tree, run_invert_tree
-from .solution import Solution, SolutionBFS, SolutionDFS
+from .solution import Solution
class TestInvertBinaryTree:
@@ -11,7 +11,6 @@ def setup_method(self):
self.solution = Solution()
@logged_test
- @pytest.mark.parametrize("solution_class", [Solution, SolutionDFS, SolutionBFS])
@pytest.mark.parametrize(
"root_list, expected_list",
[
@@ -23,10 +22,15 @@ def setup_method(self):
([1, None, 2], [1, 2]),
([1, 2, 3, 4, 5], [1, 3, 2, None, None, 5, 4]),
([1, 2, 3, None, None, 4, 5], [1, 3, 2, 5, 4]),
+ ([1, 2, 3, 4, 5, 6, 7], [1, 3, 2, 7, 6, 5, 4]),
+ ([5, 3, 8, 2, 4, 7, 9], [5, 8, 3, 9, 7, 4, 2]),
+ ([10, 5, 15, None, 6, 12, 20], [10, 15, 5, 20, 12, 6]),
+ ([1, 2, None, 3], [1, None, 2, None, 3]),
+ ([0, -1, 1], [0, 1, -1]),
+ ([100, 50, 150], [100, 150, 50]),
+ ([1, 2, 3, None, 4, None, 5], [1, 3, 2, 5, None, 4]),
],
)
- def test_invert_tree(
- self, root_list: list[int | None], expected_list: list[int | None], solution_class: type
- ):
- result = run_invert_tree(solution_class, root_list)
+ def test_invert_tree(self, root_list: list[int | None], expected_list: list[int | None]):
+ result = run_invert_tree(Solution, root_list)
assert_invert_tree(result, expected_list)
diff --git a/leetcode/k_closest_points_to_origin/test_solution.py b/leetcode/k_closest_points_to_origin/test_solution.py
index 3ef3ad3..df391c0 100644
--- a/leetcode/k_closest_points_to_origin/test_solution.py
+++ b/leetcode/k_closest_points_to_origin/test_solution.py
@@ -20,6 +20,12 @@ def setup_method(self):
([[1, 1], [1, 1], [1, 1]], 2, [[1, 1], [1, 1]]),
([[0, 0]], 1, [[0, 0]]),
([[1, 0], [2, 0], [3, 0]], 2, [[1, 0], [2, 0]]),
+ ([[0, 3], [4, 0]], 1, [[0, 3]]),
+ ([[-5, 4], [4, 6], [2, -1]], 1, [[2, -1]]),
+ ([[1, 1], [2, 2], [3, 3]], 1, [[1, 1]]),
+ ([[10, 10], [1, 1], [5, 5]], 2, [[1, 1], [5, 5]]),
+ ([[-1, -1], [1, 1], [-1, 1], [1, -1]], 3, [[-1, 1], [1, -1], [1, 1]]),
+ ([[6, 10], [-3, 3], [-2, 5], [0, 2]], 3, [[-3, 3], [0, 2], [-2, 5]]),
],
)
def test_k_closest(self, points: list[list[int]], k: int, expected: list[list[int]]):
diff --git a/leetcode/kth_smallest_element_in_a_bst/test_solution.py b/leetcode/kth_smallest_element_in_a_bst/test_solution.py
index 9f1e4d8..be3683e 100644
--- a/leetcode/kth_smallest_element_in_a_bst/test_solution.py
+++ b/leetcode/kth_smallest_element_in_a_bst/test_solution.py
@@ -20,6 +20,12 @@ def setup_method(self):
([2, 1, 3], 2, 2),
([4, 2, 6, 1, 3, 5, 7], 4, 4),
([1, None, 2], 2, 2),
+ ([5, 3, 6, 2, 4, None, None, 1], 1, 1),
+ ([5, 3, 6, 2, 4, None, None, 1], 4, 4),
+ ([10, 5, 15, 3, 7, 12, 20], 1, 3),
+ ([10, 5, 15, 3, 7, 12, 20], 7, 20),
+ ([1, None, 2, None, 3], 3, 3),
+ ([3, 1, 4, None, 2], 4, 4),
],
)
def test_kth_smallest(self, root_list: list[int | None], k: int, expected: int):
diff --git a/leetcode/linked_list_cycle/test_solution.py b/leetcode/linked_list_cycle/test_solution.py
index 2660c0e..25f3780 100644
--- a/leetcode/linked_list_cycle/test_solution.py
+++ b/leetcode/linked_list_cycle/test_solution.py
@@ -24,6 +24,11 @@ def setup_method(self):
([1, 2, 3, 4, 5], 4, True),
([1], 0, True),
([1, 2], 1, True),
+ ([1, 2, 3, 4], -1, False),
+ ([1, 2, 3, 4, 5, 6], 3, True),
+ ([10, 20, 30], 1, True),
+ ([100], -1, False),
+ ([1, 2, 3, 4, 5, 6, 7, 8], 5, True),
],
)
def test_has_cycle(self, values: list[int], pos: int, expected: bool):
diff --git a/leetcode/lowest_common_ancestor_of_a_binary_search_tree/test_solution.py b/leetcode/lowest_common_ancestor_of_a_binary_search_tree/test_solution.py
index d92a905..fd2cede 100644
--- a/leetcode/lowest_common_ancestor_of_a_binary_search_tree/test_solution.py
+++ b/leetcode/lowest_common_ancestor_of_a_binary_search_tree/test_solution.py
@@ -20,6 +20,12 @@ def setup_method(self):
([2, 1], 1, 2, 2),
([6, 2, 8, 0, 4, 7, 9], 0, 4, 2),
([6, 2, 8, 0, 4, 7, 9], 7, 9, 8),
+ ([5, 3, 6, 2, 4, None, None, 1], 1, 4, 3),
+ ([10, 5, 15, 3, 7, 12, 20], 3, 7, 5),
+ ([1, None, 2], 1, 2, 1),
+ ([3, 1, 4, None, 2], 1, 2, 1),
+ ([20, 8, 22, 4, 12, None, None, None, None, 10, 14], 10, 14, 12),
+ ([50, 30, 70, 20, 40, 60, 80], 20, 40, 30),
],
)
def test_lowest_common_ancestor(
diff --git a/leetcode/lowest_common_ancestor_of_a_binary_tree/test_solution.py b/leetcode/lowest_common_ancestor_of_a_binary_tree/test_solution.py
index 0f1d86a..3d28a96 100644
--- a/leetcode/lowest_common_ancestor_of_a_binary_tree/test_solution.py
+++ b/leetcode/lowest_common_ancestor_of_a_binary_tree/test_solution.py
@@ -20,6 +20,12 @@ def setup_method(self):
([2, 1], 2, 1, 2),
([3, 5, 1, 6, 2, 0, 8, None, None, 7, 4], 6, 7, 5),
([3, 5, 1, 6, 2, 0, 8, None, None, 7, 4], 0, 8, 1),
+ ([1, None, 2, None, 3], 2, 3, 2),
+ ([4, 2, 6, 1, 3, 5, 7], 1, 7, 4),
+ ([10, 5, 15, 3, 7, None, 18], 3, 7, 5),
+ ([1, 2, 3, 4, 5, 6, 7], 4, 5, 2),
+ ([20, 8, 22, 4, 12, None, 25], 4, 12, 8),
+ ([50, 30, 70, 20, 40, 60, 80], 20, 40, 30),
],
)
def test_lowest_common_ancestor(
diff --git a/leetcode/lru_cache/test_solution.py b/leetcode/lru_cache/test_solution.py
index 5c709c9..0fcaa3d 100644
--- a/leetcode/lru_cache/test_solution.py
+++ b/leetcode/lru_cache/test_solution.py
@@ -3,13 +3,12 @@
from leetcode_py.test_utils import logged_test
from .helpers import assert_lru_cache, run_lru_cache
-from .solution import LRUCache, LRUCacheWithDoublyList
+from .solution import LRUCache
class TestLRUCache:
@logged_test
- @pytest.mark.parametrize("solution_class", [LRUCache, LRUCacheWithDoublyList])
@pytest.mark.parametrize(
"operations, inputs, expected",
[
@@ -28,14 +27,45 @@ class TestLRUCache:
[[1], [2, 1], [2], [3, 2], [2], [3]],
[None, None, 1, None, -1, 2],
),
+ (["LRUCache", "get"], [[1], [1]], [None, -1]),
+ (["LRUCache", "put", "get"], [[1], [1, 100], [1]], [None, None, 100]),
+ (
+ ["LRUCache", "put", "put", "get", "get"],
+ [[2], [1, 1], [2, 2], [1], [2]],
+ [None, None, None, 1, 2],
+ ),
+ (
+ ["LRUCache", "put", "put", "put", "get", "get", "get"],
+ [[2], [1, 1], [2, 2], [3, 3], [1], [2], [3]],
+ [None, None, None, None, -1, 2, 3],
+ ),
+ (
+ ["LRUCache", "put", "get", "put", "get", "put", "get"],
+ [[3], [1, 1], [1], [2, 2], [2], [3, 3], [3]],
+ [None, None, 1, None, 2, None, 3],
+ ),
+ (
+ ["LRUCache", "put", "put", "put", "put", "get", "get"],
+ [[3], [1, 1], [2, 2], [3, 3], [4, 4], [4], [3]],
+ [None, None, None, None, None, 4, 3],
+ ),
+ (
+ ["LRUCache", "put", "put", "get", "put", "get", "get"],
+ [[2], [2, 1], [1, 1], [2], [4, 1], [1], [2]],
+ [None, None, None, 1, None, -1, 1],
+ ),
+ (
+ ["LRUCache", "put", "put", "get", "put", "put", "get"],
+ [[2], [2, 1], [2, 2], [2], [1, 1], [4, 1], [2]],
+ [None, None, None, 2, None, None, -1],
+ ),
+ (
+ ["LRUCache", "put", "put", "put", "get", "put", "get", "get", "get", "get"],
+ [[3], [1, 1], [2, 2], [3, 3], [2], [4, 4], [1], [3], [4], [2]],
+ [None, None, None, None, 2, None, -1, 3, 4, 2],
+ ),
],
)
- def test_lru_cache(
- self,
- operations: list[str],
- inputs: list[list[int]],
- expected: list[int | None],
- solution_class: type,
- ):
- result, _ = run_lru_cache(solution_class, operations, inputs)
+ def test_lru_cache(self, operations: list[str], inputs: list[list[int]], expected: list[int | None]):
+ result, _ = run_lru_cache(LRUCache, operations, inputs)
assert_lru_cache(result, expected)
diff --git a/leetcode/majority_element/test_solution.py b/leetcode/majority_element/test_solution.py
index d4c439f..ef73961 100644
--- a/leetcode/majority_element/test_solution.py
+++ b/leetcode/majority_element/test_solution.py
@@ -23,6 +23,12 @@ def setup_method(self):
([1, 2, 3, 4, 4, 4, 4], 4),
([0, 0, 0], 0),
([-1, -1, -1, 1, 1], -1),
+ ([100, 100, 100, 99, 99], 100),
+ ([7, 7, 7, 7, 7, 8, 8], 7),
+ ([1, 1, 1, 1, 1, 1, 2, 2, 2], 1),
+ ([9, 9, 9, 9, 8, 8, 8], 9),
+ ([-5, -5, -5, -4, -4], -5),
+ ([1000, 1000, 999, 999, 1000], 1000),
],
)
def test_majority_element(self, nums: list[int], expected: int):
diff --git a/leetcode/maximum_depth_of_binary_tree/test_solution.py b/leetcode/maximum_depth_of_binary_tree/test_solution.py
index 229701e..e86979c 100644
--- a/leetcode/maximum_depth_of_binary_tree/test_solution.py
+++ b/leetcode/maximum_depth_of_binary_tree/test_solution.py
@@ -22,6 +22,13 @@ def setup_method(self):
([1, 2, 3], 2),
([1, 2, 3, 4], 3),
([1, None, 2, None, 3], 3),
+ ([1, 2, 3, 4, 5, 6, 7], 3),
+ ([1, 2, None, 4, None, None, None, 8], 3),
+ ([5, 4, 8, 11, None, 13, 4, 7, 2, None, None, None, 1], 4),
+ ([1, 2, 3, None, None, 4, 5, None, None, 6], 4),
+ ([10], 1),
+ ([1, 2, 2, 3, 3, 3, 3], 3),
+ ([0, -1, 1, -2, -1, 0, 2], 3),
],
)
def test_max_depth(self, root_list: list[int | None], expected: int):
diff --git a/leetcode/maximum_profit_in_job_scheduling/test_solution.py b/leetcode/maximum_profit_in_job_scheduling/test_solution.py
index 3cfe330..8e17451 100644
--- a/leetcode/maximum_profit_in_job_scheduling/test_solution.py
+++ b/leetcode/maximum_profit_in_job_scheduling/test_solution.py
@@ -17,7 +17,20 @@ def setup_method(self):
([1, 2, 3, 3], [3, 4, 5, 6], [50, 10, 40, 70], 120),
([1, 2, 3, 4, 6], [3, 5, 10, 6, 9], [20, 20, 100, 70, 60], 150),
([1, 1, 1], [2, 3, 4], [5, 6, 4], 6),
+ ([1, 2], [2, 3], [100, 200], 300),
+ (
+ [6, 15, 7, 11, 1, 3, 16, 2],
+ [19, 18, 19, 16, 10, 8, 19, 8],
+ [2, 9, 1, 19, 5, 7, 3, 19],
+ 41,
+ ),
([1], [2], [100], 100),
+ ([1, 2, 3], [2, 3, 4], [1, 1, 1], 3),
+ ([1, 3, 6, 7, 8, 12], [4, 5, 10, 11, 12, 16], [20, 20, 100, 70, 60, 120], 240),
+ ([1, 4, 6], [3, 5, 7], [50, 10, 40], 100),
+ ([1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [10, 20, 30, 40, 50], 50),
+ ([5, 4, 3, 2, 1], [6, 5, 4, 3, 2], [1, 2, 3, 4, 5], 15),
+ ([1, 1000000000], [2, 1000000001], [1, 10000], 10001),
],
)
def test_job_scheduling(
diff --git a/leetcode/maximum_subarray/test_solution.py b/leetcode/maximum_subarray/test_solution.py
index 1690628..ddb4d89 100644
--- a/leetcode/maximum_subarray/test_solution.py
+++ b/leetcode/maximum_subarray/test_solution.py
@@ -21,6 +21,14 @@ def setup_method(self):
([-2, -1], -1),
([1, 2, 3, 4, 5], 15),
([-5, -2, -8, -1], -1),
+ ([0], 0),
+ ([0, -1, 0], 0),
+ ([-3, -2, -1, -5], -1),
+ ([2, -1, 2, -1, 2], 4),
+ ([1, -3, 2, 1, -1], 3),
+ ([-2, -3, 4, -1, -2, 1, 5, -3], 7),
+ ([10, -5, 3, -2, 8], 14),
+ ([100], 100),
],
)
def test_max_sub_array(self, nums: list[int], expected: int):
diff --git a/leetcode/merge_intervals/test_solution.py b/leetcode/merge_intervals/test_solution.py
index 045bc7f..195cced 100644
--- a/leetcode/merge_intervals/test_solution.py
+++ b/leetcode/merge_intervals/test_solution.py
@@ -20,6 +20,12 @@ def setup_method(self):
([[1, 3]], [[1, 3]]),
([[1, 4], [2, 3]], [[1, 4]]),
([[1, 2], [3, 4], [5, 6]], [[1, 2], [3, 4], [5, 6]]),
+ ([[0, 0]], [[0, 0]]),
+ ([[1, 10], [2, 3], [4, 5], [6, 7], [8, 9]], [[1, 10]]),
+ ([[1, 3], [2, 6], [8, 10], [9, 12], [15, 18]], [[1, 6], [8, 12], [15, 18]]),
+ ([[2, 3], [4, 5], [6, 7], [8, 9], [1, 10]], [[1, 10]]),
+ ([[1, 4], [0, 4]], [[0, 4]]),
+ ([[1, 4], [0, 0], [3, 5]], [[0, 0], [1, 5]]),
],
)
def test_merge(self, intervals: list[list[int]], expected: list[list[int]]):
diff --git a/leetcode/merge_k_sorted_lists/test_solution.py b/leetcode/merge_k_sorted_lists/test_solution.py
index ea7d200..e9d9cfc 100644
--- a/leetcode/merge_k_sorted_lists/test_solution.py
+++ b/leetcode/merge_k_sorted_lists/test_solution.py
@@ -23,6 +23,12 @@ def setup_method(self):
([[-1, 0, 1], [-2, 2]], [-2, -1, 0, 1, 2]),
([[1, 1, 1], [2, 2, 2]], [1, 1, 1, 2, 2, 2]),
([[], [1], []], [1]),
+ ([[0, 0, 0], [1, 1, 1]], [0, 0, 0, 1, 1, 1]),
+ ([[10], [5], [1]], [1, 5, 10]),
+ ([[1, 2, 3, 4, 5]], [1, 2, 3, 4, 5]),
+ ([[-10, -5], [-8, -3], [-6, -1]], [-10, -8, -6, -5, -3, -1]),
+ ([[100]], [100]),
+ ([[1, 3, 5], [2, 4, 6], [7, 8, 9]], [1, 2, 3, 4, 5, 6, 7, 8, 9]),
],
)
def test_merge_k_lists(self, lists_data: list[list[int]], expected_data: list[int]):
diff --git a/leetcode/merge_two_sorted_lists/test_solution.py b/leetcode/merge_two_sorted_lists/test_solution.py
index c0deaf5..58b2887 100644
--- a/leetcode/merge_two_sorted_lists/test_solution.py
+++ b/leetcode/merge_two_sorted_lists/test_solution.py
@@ -21,6 +21,13 @@ def setup_method(self):
([2], [1], [1, 2]),
([1, 3, 5], [2, 4, 6], [1, 2, 3, 4, 5, 6]),
([1, 1, 1], [2, 2, 2], [1, 1, 1, 2, 2, 2]),
+ ([0], [], [0]),
+ ([1, 2, 3], [], [1, 2, 3]),
+ ([5], [1, 2, 3, 4], [1, 2, 3, 4, 5]),
+ ([-1, 0, 1], [-2, 2, 3], [-2, -1, 0, 1, 2, 3]),
+ ([1, 5, 9], [2, 6, 8], [1, 2, 5, 6, 8, 9]),
+ ([10, 20, 30], [15, 25, 35], [10, 15, 20, 25, 30, 35]),
+ ([1, 1], [1, 1], [1, 1, 1, 1]),
],
)
def test_merge_two_lists(
diff --git a/leetcode/middle_of_the_linked_list/test_solution.py b/leetcode/middle_of_the_linked_list/test_solution.py
index 5bf4440..0cdfdd0 100644
--- a/leetcode/middle_of_the_linked_list/test_solution.py
+++ b/leetcode/middle_of_the_linked_list/test_solution.py
@@ -21,6 +21,13 @@ def setup_method(self):
([1, 2, 3], [2, 3]),
([1, 2, 3, 4], [3, 4]),
([10, 20, 30, 40, 50, 60, 70], [40, 50, 60, 70]),
+ ([5, 10], [10]),
+ ([1, 3, 5, 7, 9], [5, 7, 9]),
+ ([2, 4, 6, 8, 10, 12], [8, 10, 12]),
+ ([100], [100]),
+ ([7, 14, 21], [14, 21]),
+ ([11, 22, 33, 44], [33, 44]),
+ ([1, 1, 1, 1, 1], [1, 1, 1]),
],
)
def test_middle_node(self, head_list: list[int], expected_list: list[int]):
diff --git a/leetcode/min_stack/test_solution.py b/leetcode/min_stack/test_solution.py
index 0604301..fd75d51 100644
--- a/leetcode/min_stack/test_solution.py
+++ b/leetcode/min_stack/test_solution.py
@@ -27,6 +27,86 @@ class TestTestMinStack:
[[], [1], [1], [2], [], [], [], [], []],
[None, None, None, None, 1, None, 1, None, 1],
),
+ (["MinStack", "push", "getMin", "top"], [[], [0], [], []], [None, None, 0, 0]),
+ (
+ ["MinStack", "push", "push", "getMin", "push", "getMin", "pop", "getMin"],
+ [[], [2], [1], [], [0], [], [], []],
+ [None, None, None, 1, None, 0, None, 1],
+ ),
+ (
+ ["MinStack", "push", "push", "push", "top", "getMin", "pop", "pop", "top", "getMin"],
+ [[], [3], [1], [4], [], [], [], [], [], []],
+ [None, None, None, None, 4, 1, None, None, 3, 3],
+ ),
+ (
+ ["MinStack", "push", "push", "getMin", "pop", "push", "getMin"],
+ [[], [-1], [-2], [], [], [0], []],
+ [None, None, None, -2, None, None, -1],
+ ),
+ (
+ ["MinStack", "push", "push", "push", "push", "getMin", "pop", "pop", "getMin"],
+ [[], [5], [3], [7], [2], [], [], [], []],
+ [None, None, None, None, None, 2, None, None, 3],
+ ),
+ (
+ [
+ "MinStack",
+ "push",
+ "push",
+ "push",
+ "getMin",
+ "pop",
+ "getMin",
+ "pop",
+ "getMin",
+ "pop",
+ "push",
+ "getMin",
+ ],
+ [[], [10], [5], [15], [], [], [], [], [], [], [8], []],
+ [None, None, None, None, 5, None, 5, None, 10, None, None, 8],
+ ),
+ (
+ [
+ "MinStack",
+ "push",
+ "push",
+ "push",
+ "push",
+ "push",
+ "getMin",
+ "pop",
+ "getMin",
+ "pop",
+ "getMin",
+ ],
+ [[], [1], [2], [0], [3], [4], [], [], [], [], []],
+ [None, None, None, None, None, None, 0, None, 0, None, 0],
+ ),
+ (
+ ["MinStack", "push", "getMin", "push", "getMin", "push", "getMin", "top"],
+ [[], [2147483647], [], [-2147483648], [], [0], [], []],
+ [None, None, 2147483647, None, -2147483648, None, -2147483648, 0],
+ ),
+ (
+ [
+ "MinStack",
+ "push",
+ "push",
+ "push",
+ "push",
+ "push",
+ "top",
+ "getMin",
+ "pop",
+ "top",
+ "getMin",
+ "pop",
+ "getMin",
+ ],
+ [[], [1], [1], [1], [1], [1], [], [], [], [], [], [], []],
+ [None, None, None, None, None, None, 1, 1, None, 1, 1, None, 1],
+ ),
],
)
def test_min_stack(self, operations: list[str], inputs: list[list[int]], expected: list[int | None]):
diff --git a/leetcode/minimum_height_trees/test_solution.py b/leetcode/minimum_height_trees/test_solution.py
index d9a27c4..74cd63c 100644
--- a/leetcode/minimum_height_trees/test_solution.py
+++ b/leetcode/minimum_height_trees/test_solution.py
@@ -19,6 +19,13 @@ def setup_method(self):
(1, [], [0]),
(2, [[0, 1]], [0, 1]),
(3, [[0, 1], [1, 2]], [1]),
+ (5, [[0, 1], [1, 2], [2, 3], [3, 4]], [2]),
+ (7, [[0, 1], [1, 2], [1, 3], [2, 4], [3, 5], [4, 6]], [1, 2]),
+ (6, [[0, 3], [1, 3], [2, 3], [4, 3], [5, 4]], [3, 4]),
+ (10, [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9]], [4, 5]),
+ (8, [[0, 1], [1, 2], [2, 3], [0, 4], [4, 5], [5, 6], [6, 7]], [0, 4]),
+ (9, [[0, 1], [0, 2], [1, 3], [1, 4], [2, 5], [2, 6], [3, 7], [4, 8]], [0, 1]),
+ (11, [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10]], [5]),
],
)
def test_find_min_height_trees(self, n: int, edges: list[list[int]], expected: list[int]):
diff --git a/leetcode/minimum_window_substring/test_solution.py b/leetcode/minimum_window_substring/test_solution.py
index 2be62d0..a76fe7a 100644
--- a/leetcode/minimum_window_substring/test_solution.py
+++ b/leetcode/minimum_window_substring/test_solution.py
@@ -19,6 +19,12 @@ def setup_method(self):
("a", "aa", ""),
("ab", "b", "b"),
("abc", "cba", "abc"),
+ ("aa", "aa", "aa"),
+ ("a", "b", ""),
+ ("ab", "a", "a"),
+ ("bba", "ab", "ba"),
+ ("acbbaca", "aba", "baca"),
+ ("cabwefgewcwaefgcf", "cae", "cwae"),
],
)
def test_min_window(self, s: str, t: str, expected: str):
diff --git a/leetcode/number_of_islands/test_solution.py b/leetcode/number_of_islands/test_solution.py
index 2428a04..2b37d2d 100644
--- a/leetcode/number_of_islands/test_solution.py
+++ b/leetcode/number_of_islands/test_solution.py
@@ -32,9 +32,21 @@ def setup_method(self):
],
3,
),
+ ([["1", "0", "1", "1", "1"], ["1", "0", "1", "0", "1"], ["1", "1", "1", "0", "1"]], 1),
+ ([["0", "0", "0", "0", "0"], ["0", "0", "0", "0", "0"], ["0", "0", "0", "0", "0"]], 0),
+ ([["1", "1", "1"], ["0", "1", "0"], ["1", "1", "1"]], 1),
([["1"]], 1),
([["0"]], 0),
+ ([["1", "0"], ["0", "1"]], 2),
+ ([["1", "1"], ["1", "1"]], 1),
([["1", "0", "1"], ["0", "1", "0"], ["1", "0", "1"]], 5),
+ ([["1", "1", "0"], ["0", "0", "1"], ["0", "1", "1"]], 2),
+ (
+ [["1", "0", "0", "1"], ["0", "1", "1", "0"], ["0", "1", "1", "0"], ["1", "0", "0", "1"]],
+ 5,
+ ),
+ ([["0", "1", "0"], ["1", "0", "1"], ["0", "1", "0"]], 4),
+ ([["1", "1", "1", "1"], ["1", "0", "0", "1"], ["1", "1", "1", "1"]], 1),
],
)
def test_num_islands(self, grid: list[list[str]], expected: int):
diff --git a/leetcode/partition_equal_subset_sum/test_solution.py b/leetcode/partition_equal_subset_sum/test_solution.py
index a04af23..e826127 100644
--- a/leetcode/partition_equal_subset_sum/test_solution.py
+++ b/leetcode/partition_equal_subset_sum/test_solution.py
@@ -3,13 +3,14 @@
from leetcode_py.test_utils import logged_test
from .helpers import assert_can_partition, run_can_partition
-from .solution import Solution, SolutionBitset
+from .solution import Solution
class TestPartitionEqualSubsetSum:
+ def setup_method(self):
+ self.solution = Solution()
@logged_test
- @pytest.mark.parametrize("solution_class", [Solution, SolutionBitset])
@pytest.mark.parametrize(
"nums, expected",
[
@@ -20,8 +21,16 @@ class TestPartitionEqualSubsetSum:
([2, 2, 1, 1], True),
([100], False),
([1, 2, 5], False),
+ ([1, 3, 5, 7], True),
+ ([2, 2, 3, 5], False),
+ ([1, 2, 3, 4, 5, 6, 7], True),
+ ([3, 3, 3, 4, 5], True),
+ ([1, 1, 1, 1], True),
+ ([23, 13, 11, 7, 6, 5, 5], True),
+ ([1, 5, 3], False),
+ ([4, 4, 4, 4, 4, 4], True),
],
)
- def test_can_partition(self, nums: list[int], expected: bool, solution_class: type):
- result = run_can_partition(solution_class, nums)
+ def test_can_partition(self, nums: list[int], expected: bool):
+ result = run_can_partition(Solution, nums)
assert_can_partition(result, expected)
diff --git a/leetcode/permutations/test_solution.py b/leetcode/permutations/test_solution.py
index da684e9..d8d1bce 100644
--- a/leetcode/permutations/test_solution.py
+++ b/leetcode/permutations/test_solution.py
@@ -18,6 +18,42 @@ def setup_method(self):
([0, 1], [[0, 1], [1, 0]]),
([1], [[1]]),
([2, 1], [[2, 1], [1, 2]]),
+ ([0], [[0]]),
+ ([-1, 0], [[-1, 0], [0, -1]]),
+ ([1, 2], [[1, 2], [2, 1]]),
+ ([3, 2, 1], [[3, 2, 1], [3, 1, 2], [2, 3, 1], [2, 1, 3], [1, 3, 2], [1, 2, 3]]),
+ ([-1, 1], [[-1, 1], [1, -1]]),
+ (
+ [5, 4, 3, 2],
+ [
+ [5, 4, 3, 2],
+ [5, 4, 2, 3],
+ [5, 3, 4, 2],
+ [5, 3, 2, 4],
+ [5, 2, 4, 3],
+ [5, 2, 3, 4],
+ [4, 5, 3, 2],
+ [4, 5, 2, 3],
+ [4, 3, 5, 2],
+ [4, 3, 2, 5],
+ [4, 2, 5, 3],
+ [4, 2, 3, 5],
+ [3, 5, 4, 2],
+ [3, 5, 2, 4],
+ [3, 4, 5, 2],
+ [3, 4, 2, 5],
+ [3, 2, 5, 4],
+ [3, 2, 4, 5],
+ [2, 5, 4, 3],
+ [2, 5, 3, 4],
+ [2, 4, 5, 3],
+ [2, 4, 3, 5],
+ [2, 3, 5, 4],
+ [2, 3, 4, 5],
+ ],
+ ),
+ ([0, -1, 1], [[0, -1, 1], [0, 1, -1], [-1, 0, 1], [-1, 1, 0], [1, 0, -1], [1, -1, 0]]),
+ ([10, -10], [[10, -10], [-10, 10]]),
],
)
def test_permute(self, nums: list[int], expected: list[list[int]]):
diff --git a/leetcode/product_of_array_except_self/test_solution.py b/leetcode/product_of_array_except_self/test_solution.py
index 2645aff..84013ac 100644
--- a/leetcode/product_of_array_except_self/test_solution.py
+++ b/leetcode/product_of_array_except_self/test_solution.py
@@ -21,6 +21,14 @@ def setup_method(self):
([5, 2], [2, 5]),
([0, 1, 2, 3], [6, 0, 0, 0]),
([1, 0, 3, 4], [0, 12, 0, 0]),
+ ([-1, -2, -3], [6, 3, 2]),
+ ([2, 2, 2], [4, 4, 4]),
+ ([10, 3, 5, 6, 2], [180, 600, 360, 300, 900]),
+ ([0, 0], [0, 0]),
+ ([1, 2, 0, 4], [0, 0, 8, 0]),
+ ([-2, 0, -3, 4], [0, 24, 0, 0]),
+ ([7, 1, 3], [3, 21, 7]),
+ ([4, 5, 1, 8, 2], [80, 64, 320, 40, 160]),
],
)
def test_product_except_self(self, nums: list[int], expected: list[int]):
diff --git a/leetcode/reverse_linked_list/test_solution.py b/leetcode/reverse_linked_list/test_solution.py
index 38404d5..8f8198e 100644
--- a/leetcode/reverse_linked_list/test_solution.py
+++ b/leetcode/reverse_linked_list/test_solution.py
@@ -24,6 +24,11 @@ def setup_method(self):
([0], [0]),
([5000, -5000], [-5000, 5000]),
([1, 1, 1], [1, 1, 1]),
+ ([10, 20, 30, 40, 50, 60], [60, 50, 40, 30, 20, 10]),
+ ([-100, 0, 100], [100, 0, -100]),
+ ([7], [7]),
+ ([1, 2, 3, 4, 5, 6, 7], [7, 6, 5, 4, 3, 2, 1]),
+ ([42, 42, 42, 42], [42, 42, 42, 42]),
],
)
def test_reverse_list(self, head_list: list[int], expected_list: list[int]):
diff --git a/leetcode/reverse_linked_list_ii/test_solution.py b/leetcode/reverse_linked_list_ii/test_solution.py
index daecb86..5964711 100644
--- a/leetcode/reverse_linked_list_ii/test_solution.py
+++ b/leetcode/reverse_linked_list_ii/test_solution.py
@@ -20,6 +20,12 @@ def setup_method(self):
([1, 2, 3], 1, 3, [3, 2, 1]),
([1, 2, 3, 4, 5], 1, 5, [5, 4, 3, 2, 1]),
([1, 2, 3, 4, 5], 3, 3, [1, 2, 3, 4, 5]),
+ ([1, 2, 3, 4], 2, 3, [1, 3, 2, 4]),
+ ([1, 2, 3, 4, 5, 6], 3, 5, [1, 2, 5, 4, 3, 6]),
+ ([10], 1, 1, [10]),
+ ([1, 2, 3, 4, 5, 6, 7], 1, 7, [7, 6, 5, 4, 3, 2, 1]),
+ ([3, 5], 1, 1, [3, 5]),
+ ([7, 9, 2, 10, 1, 8, 6], 4, 6, [7, 9, 2, 8, 1, 10, 6]),
],
)
def test_reverse_between(
diff --git a/leetcode/search_in_rotated_sorted_array/test_solution.py b/leetcode/search_in_rotated_sorted_array/test_solution.py
index c63c101..a227711 100644
--- a/leetcode/search_in_rotated_sorted_array/test_solution.py
+++ b/leetcode/search_in_rotated_sorted_array/test_solution.py
@@ -23,6 +23,12 @@ def setup_method(self):
([2, 1], 2, 0),
([5, 1, 3], 3, 2),
([4, 5, 6, 7, 8, 1, 2, 3], 8, 4),
+ ([6, 7, 0, 1, 2, 3, 4, 5], 6, 0),
+ ([7, 0, 1, 2, 3, 4, 5, 6], 7, 0),
+ ([0, 1, 2, 3, 4, 5, 6, 7], 4, 4),
+ ([3, 4, 5, 6, 7, 0, 1, 2], 2, 7),
+ ([9, 0, 2, 7, 8], 3, -1),
+ ([8, 9, 2, 3, 4], 9, 1),
],
)
def test_search(self, nums: list[int], target: int, expected: int):
diff --git a/leetcode/serialize_and_deserialize_binary_tree/test_solution.py b/leetcode/serialize_and_deserialize_binary_tree/test_solution.py
index 4e523e9..8f67b6e 100644
--- a/leetcode/serialize_and_deserialize_binary_tree/test_solution.py
+++ b/leetcode/serialize_and_deserialize_binary_tree/test_solution.py
@@ -19,6 +19,14 @@ class TestSerializeAndDeserializeBinaryTree:
([1, None, 2]),
([1, 2, 3, 4, 5, 6, 7]),
([5, 2, 3, None, None, 2, 4, 3, 1]),
+ ([1, 2, 3]),
+ ([1, None, None]),
+ ([1, 2, None, 4]),
+ ([1, None, 2, None, 3]),
+ ([10, 5, 15, None, 6, 12, 20]),
+ ([0, -1, 1]),
+ ([100]),
+ ([1, 2, 3, 4, None, None, 7, 8]),
],
)
def test_serialize_deserialize(self, root_list: list[int | None]):
diff --git a/leetcode/sort_colors/test_solution.py b/leetcode/sort_colors/test_solution.py
index df38daf..43f6085 100644
--- a/leetcode/sort_colors/test_solution.py
+++ b/leetcode/sort_colors/test_solution.py
@@ -23,6 +23,12 @@ def setup_method(self):
([2, 2, 2], [2, 2, 2]),
([0, 0, 0], [0, 0, 0]),
([1, 1, 1], [1, 1, 1]),
+ ([2, 1, 0], [0, 1, 2]),
+ ([1, 0, 2, 1, 0, 2], [0, 0, 1, 1, 2, 2]),
+ ([0, 2, 1, 0, 2, 1], [0, 0, 1, 1, 2, 2]),
+ ([2, 2, 1, 0, 0, 1], [0, 0, 1, 1, 2, 2]),
+ ([1, 2, 0, 1, 2, 0, 1], [0, 0, 1, 1, 1, 2, 2]),
+ ([0, 1, 0, 2, 1, 2, 0], [0, 0, 0, 1, 1, 2, 2]),
],
)
def test_sort_colors(self, nums: list[int], expected: list[int]):
diff --git a/leetcode/spiral_matrix/test_solution.py b/leetcode/spiral_matrix/test_solution.py
index 6d36a02..22bda84 100644
--- a/leetcode/spiral_matrix/test_solution.py
+++ b/leetcode/spiral_matrix/test_solution.py
@@ -21,6 +21,13 @@ def setup_method(self):
([[1], [2]], [1, 2]),
([[1, 2, 3]], [1, 2, 3]),
([[1], [2], [3]], [1, 2, 3]),
+ ([[1, 2], [3, 4]], [1, 2, 4, 3]),
+ ([[1, 2, 3, 4, 5]], [1, 2, 3, 4, 5]),
+ ([[1], [2], [3], [4], [5]], [1, 2, 3, 4, 5]),
+ ([[1, 2, 3], [4, 5, 6]], [1, 2, 3, 6, 5, 4]),
+ ([[1, 2], [3, 4], [5, 6]], [1, 2, 4, 6, 5, 3]),
+ ([[7, 9, 6], [2, 8, 6], [1, 3, 5]], [7, 9, 6, 6, 5, 3, 1, 2, 8]),
+ ([[1, 2, 3, 4], [5, 6, 7, 8]], [1, 2, 3, 4, 8, 7, 6, 5]),
],
)
def test_spiral_order(self, matrix: list[list[int]], expected: list[int]):
diff --git a/leetcode/task_scheduler/test_solution.py b/leetcode/task_scheduler/test_solution.py
index b2db53e..85794ce 100644
--- a/leetcode/task_scheduler/test_solution.py
+++ b/leetcode/task_scheduler/test_solution.py
@@ -3,13 +3,14 @@
from leetcode_py.test_utils import logged_test
from .helpers import assert_least_interval, run_least_interval
-from .solution import Solution, SolutionGreedy
+from .solution import Solution
class TestTaskScheduler:
+ def setup_method(self):
+ self.solution = Solution()
@logged_test
- @pytest.mark.parametrize("solution_class", [Solution, SolutionGreedy])
@pytest.mark.parametrize(
"tasks, n, expected",
[
@@ -19,8 +20,14 @@ class TestTaskScheduler:
(["A"], 0, 1),
(["A", "A"], 1, 3),
(["A", "B"], 0, 2),
+ (["A", "A", "A"], 0, 3),
+ (["A", "B", "C", "D", "E", "F"], 2, 6),
+ (["A", "A", "A", "A", "A", "A", "B", "C", "D", "E", "F", "G"], 2, 16),
+ (["A", "A", "B", "B"], 2, 5),
+ (["A", "B", "A", "B"], 1, 4),
+ (["A", "A", "A", "A"], 3, 13),
],
)
- def test_least_interval(self, tasks: list[str], n: int, expected: int, solution_class: type):
- result = run_least_interval(solution_class, tasks, n)
+ def test_least_interval(self, tasks: list[str], n: int, expected: int):
+ result = run_least_interval(Solution, tasks, n)
assert_least_interval(result, expected)
diff --git a/leetcode/three_sum/test_solution.py b/leetcode/three_sum/test_solution.py
index 9ec9f76..2bba573 100644
--- a/leetcode/three_sum/test_solution.py
+++ b/leetcode/three_sum/test_solution.py
@@ -20,6 +20,15 @@ def setup_method(self):
([-1, 0, 1], [[-1, 0, 1]]),
([1, 2, -2, -1], []),
([-2, 0, 1, 1, 2], [[-2, 0, 2], [-2, 1, 1]]),
+ ([1, -1, -1, 0], [[-1, 0, 1]]),
+ (
+ [-4, -2, -2, -2, 0, 1, 2, 2, 2, 3, 3, 4, 4, 6, 6],
+ [[-4, -2, 6], [-4, 0, 4], [-4, 1, 3], [-4, 2, 2], [-2, -2, 4], [-2, 0, 2]],
+ ),
+ ([3, 0, -2, -1, 1, 2], [[-2, -1, 3], [-2, 0, 2], [-1, 0, 1]]),
+ ([0, 0, 0, 0], [[0, 0, 0]]),
+ ([-1, -1, 2], [[-1, -1, 2]]),
+ ([1, 1, -2], [[-2, 1, 1]]),
],
)
def test_three_sum(self, nums: list[int], expected: list[list[int]]):
diff --git a/leetcode/trapping_rain_water/test_solution.py b/leetcode/trapping_rain_water/test_solution.py
index fb1fc4c..c35bb3f 100644
--- a/leetcode/trapping_rain_water/test_solution.py
+++ b/leetcode/trapping_rain_water/test_solution.py
@@ -21,6 +21,14 @@ def setup_method(self):
([1], 0),
([1, 2], 0),
([2, 1], 0),
+ ([3, 2, 0, 4], 4),
+ ([5, 4, 1, 2], 1),
+ ([2, 0, 2], 2),
+ ([1, 0, 1], 1),
+ ([0, 2, 0], 0),
+ ([1, 2, 1], 0),
+ ([5, 2, 7, 2, 6, 1, 5, 3, 2, 1], 11),
+ ([0, 0, 0, 0], 0),
],
)
def test_trap(self, height: list[int], expected: int):
diff --git a/leetcode/valid_palindrome/test_solution.py b/leetcode/valid_palindrome/test_solution.py
index f1fedb9..83b4362 100644
--- a/leetcode/valid_palindrome/test_solution.py
+++ b/leetcode/valid_palindrome/test_solution.py
@@ -22,6 +22,14 @@ def setup_method(self):
("Madam", True),
("No 'x' in Nixon", True),
("Mr. Owl ate my metal worm", True),
+ ("Was it a car or a cat I saw?", True),
+ ("Madam, I'm Adam", True),
+ ("Never odd or even", True),
+ ("Do geese see God?", True),
+ ("Step on no pets", True),
+ ("12321", True),
+ ("hello", False),
+ ("ab", False),
],
)
def test_is_palindrome(self, s: str, expected: bool):
diff --git a/leetcode/valid_parentheses/test_solution.py b/leetcode/valid_parentheses/test_solution.py
index 88b32d6..7e4c8b2 100644
--- a/leetcode/valid_parentheses/test_solution.py
+++ b/leetcode/valid_parentheses/test_solution.py
@@ -24,6 +24,16 @@ def setup_method(self):
(")", False),
("{[()]}", True),
("{[(])}", False),
+ ("((", False),
+ ("))", False),
+ ("([{}])", True),
+ ("([{]})", False),
+ ("{[}]", False),
+ ("((()))", True),
+ ("((())", False),
+ ("(){}[]", True),
+ ("{[(", False),
+ ("]})", False),
],
)
def test_is_valid(self, s: str, expected: bool):
diff --git a/leetcode/validate_binary_search_tree/test_solution.py b/leetcode/validate_binary_search_tree/test_solution.py
index e7af72f..8e5eca0 100644
--- a/leetcode/validate_binary_search_tree/test_solution.py
+++ b/leetcode/validate_binary_search_tree/test_solution.py
@@ -3,13 +3,14 @@
from leetcode_py.test_utils import logged_test
from .helpers import assert_is_valid_bst, run_is_valid_bst
-from .solution import Solution, SolutionBFS, SolutionDFS
+from .solution import Solution
class TestValidateBinarySearchTree:
+ def setup_method(self):
+ self.solution = Solution()
@logged_test
- @pytest.mark.parametrize("solution_class", [Solution, SolutionDFS, SolutionBFS])
@pytest.mark.parametrize(
"root_list, expected",
[
@@ -19,8 +20,14 @@ class TestValidateBinarySearchTree:
([1, 1], False),
([10, 5, 15, None, None, 6, 20], False),
([2, 1, 3, None, None, None, 4], True),
+ ([0], True),
+ ([2147483647], True),
+ ([-2147483648], True),
+ ([5, 4, 6, None, None, 3, 7], False),
+ ([10, 5, 15, None, None, 12, 20, None, None, None, None, 6, 25], True),
+ ([3, 1, 5, 0, 2, 4, 6], True),
],
)
- def test_is_valid_bst(self, root_list: list[int | None], expected: bool, solution_class: type):
- result = run_is_valid_bst(solution_class, root_list)
+ def test_is_valid_bst(self, root_list: list[int | None], expected: bool):
+ result = run_is_valid_bst(Solution, root_list)
assert_is_valid_bst(result, expected)
diff --git a/leetcode/word_break/test_solution.py b/leetcode/word_break/test_solution.py
index fe2f52e..97a2619 100644
--- a/leetcode/word_break/test_solution.py
+++ b/leetcode/word_break/test_solution.py
@@ -21,6 +21,14 @@ def setup_method(self):
("a", ["a"], True),
("ab", ["a", "b"], True),
("abcd", ["a", "abc", "d"], True),
+ ("aaaaaaa", ["aaaa", "aaa"], True),
+ ("aaaaaaa", ["aaaa", "aa"], False),
+ ("cars", ["car", "ca", "rs"], True),
+ ("raceacar", ["race", "a", "car"], True),
+ ("abcdef", ["abc", "def"], True),
+ ("abcdef", ["ab", "cd", "ef"], True),
+ ("goalspecial", ["go", "goal", "goals", "special"], True),
+ ("bb", ["a", "b", "bbb", "bbbb"], True),
],
)
def test_word_break(self, s: str, word_dict: list[str], expected: bool):
diff --git a/leetcode/word_ladder/test_solution.py b/leetcode/word_ladder/test_solution.py
index ed83464..94008a8 100644
--- a/leetcode/word_ladder/test_solution.py
+++ b/leetcode/word_ladder/test_solution.py
@@ -19,6 +19,117 @@ def setup_method(self):
("a", "c", ["a", "b", "c"], 2),
("hot", "dog", ["hot", "dog"], 0),
("hot", "dog", ["hot", "hog", "dog"], 3),
+ ("red", "tax", ["ted", "tex", "red", "tax", "tad", "den", "rex", "pee"], 4),
+ ("talk", "tail", ["talk", "tons", "fall", "tail", "gale", "hall", "negs"], 0),
+ (
+ "qa",
+ "sq",
+ [
+ "si",
+ "go",
+ "se",
+ "cm",
+ "so",
+ "ph",
+ "mt",
+ "db",
+ "mb",
+ "sb",
+ "kr",
+ "ln",
+ "tm",
+ "le",
+ "av",
+ "sm",
+ "ar",
+ "ci",
+ "ca",
+ "br",
+ "ti",
+ "ba",
+ "to",
+ "ra",
+ "fa",
+ "yo",
+ "ow",
+ "sn",
+ "ya",
+ "cr",
+ "po",
+ "fe",
+ "ho",
+ "ma",
+ "re",
+ "or",
+ "rn",
+ "au",
+ "ur",
+ "rh",
+ "sr",
+ "tc",
+ "lt",
+ "lo",
+ "as",
+ "fr",
+ "nb",
+ "yb",
+ "if",
+ "pb",
+ "ge",
+ "th",
+ "pm",
+ "rb",
+ "sh",
+ "co",
+ "ga",
+ "li",
+ "ha",
+ "hz",
+ "no",
+ "bi",
+ "di",
+ "hi",
+ "qa",
+ "pi",
+ "os",
+ "uh",
+ "wm",
+ "an",
+ "me",
+ "mo",
+ "na",
+ "la",
+ "st",
+ "er",
+ "sc",
+ "ne",
+ "mn",
+ "mi",
+ "am",
+ "ex",
+ "pt",
+ "io",
+ "be",
+ "fm",
+ "ta",
+ "tb",
+ "ni",
+ "mr",
+ "pa",
+ "he",
+ "lr",
+ "sq",
+ "ye",
+ ],
+ 5,
+ ),
+ ("cet", "ism", ["kid", "tag", "pup", "ail", "tun", "woo"], 0),
+ ("lost", "miss", ["most", "mist", "miss", "lost", "fist", "fish"], 4),
+ ("cat", "dog", ["bat", "bag", "dag", "dog", "cat"], 5),
+ ("game", "thee", ["frye", "heat", "tree", "thee", "game", "free"], 0),
+ ("teach", "place", ["peale", "wilts", "place", "fetch"], 0),
+ ("sail", "boat", ["bail", "foil", "coat", "boat", "sail"], 0),
+ ("cold", "warm", ["cold", "cord", "word", "ward", "warm"], 5),
],
)
def test_ladder_length(self, begin_word: str, end_word: str, word_list: list[str], expected: int):
diff --git a/leetcode/zero_one_matrix/test_solution.py b/leetcode/zero_one_matrix/test_solution.py
index ea195cb..4129b47 100644
--- a/leetcode/zero_one_matrix/test_solution.py
+++ b/leetcode/zero_one_matrix/test_solution.py
@@ -18,6 +18,15 @@ def setup_method(self):
([[0, 0, 0], [0, 1, 0], [1, 1, 1]], [[0, 0, 0], [0, 1, 0], [1, 2, 1]]),
([[0]], [[0]]),
([[1, 0]], [[1, 0]]),
+ ([[1, 1], [1, 0]], [[2, 1], [1, 0]]),
+ ([[0, 1, 0], [1, 1, 1], [0, 1, 0]], [[0, 1, 0], [1, 2, 1], [0, 1, 0]]),
+ ([[1, 0, 1], [1, 1, 1], [1, 1, 1]], [[1, 0, 1], [2, 1, 2], [3, 2, 3]]),
+ ([[0, 1, 0, 0], [1, 1, 1, 0], [1, 1, 1, 0]], [[0, 1, 0, 0], [1, 2, 1, 0], [2, 2, 1, 0]]),
+ ([[1, 1, 1], [1, 1, 1], [1, 1, 0]], [[4, 3, 2], [3, 2, 1], [2, 1, 0]]),
+ ([[0, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]], [[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]),
+ ([[1, 0, 0], [1, 1, 0], [1, 1, 1]], [[1, 0, 0], [2, 1, 0], [3, 2, 1]]),
+ ([[0, 0, 1], [0, 1, 1], [1, 1, 1]], [[0, 0, 1], [0, 1, 2], [1, 2, 3]]),
+ ([[1, 1, 0, 1], [1, 0, 1, 1], [0, 1, 1, 1]], [[2, 1, 0, 1], [1, 0, 1, 2], [0, 1, 2, 3]]),
],
)
def test_update_matrix(self, mat: list[list[int]], expected: list[list[int]]):
diff --git a/poetry.lock b/poetry.lock
index 1ee7322..54bb124 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -993,50 +993,50 @@ files = [
[[package]]
name = "mypy"
-version = "1.17.1"
+version = "1.18.1"
description = "Optional static typing for Python"
optional = false
python-versions = ">=3.9"
groups = ["dev"]
files = [
- {file = "mypy-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3fbe6d5555bf608c47203baa3e72dbc6ec9965b3d7c318aa9a4ca76f465bd972"},
- {file = "mypy-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:80ef5c058b7bce08c83cac668158cb7edea692e458d21098c7d3bce35a5d43e7"},
- {file = "mypy-1.17.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4a580f8a70c69e4a75587bd925d298434057fe2a428faaf927ffe6e4b9a98df"},
- {file = "mypy-1.17.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dd86bb649299f09d987a2eebb4d52d10603224500792e1bee18303bbcc1ce390"},
- {file = "mypy-1.17.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a76906f26bd8d51ea9504966a9c25419f2e668f012e0bdf3da4ea1526c534d94"},
- {file = "mypy-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:e79311f2d904ccb59787477b7bd5d26f3347789c06fcd7656fa500875290264b"},
- {file = "mypy-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ad37544be07c5d7fba814eb370e006df58fed8ad1ef33ed1649cb1889ba6ff58"},
- {file = "mypy-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:064e2ff508e5464b4bd807a7c1625bc5047c5022b85c70f030680e18f37273a5"},
- {file = "mypy-1.17.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:70401bbabd2fa1aa7c43bb358f54037baf0586f41e83b0ae67dd0534fc64edfd"},
- {file = "mypy-1.17.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e92bdc656b7757c438660f775f872a669b8ff374edc4d18277d86b63edba6b8b"},
- {file = "mypy-1.17.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c1fdf4abb29ed1cb091cf432979e162c208a5ac676ce35010373ff29247bcad5"},
- {file = "mypy-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:ff2933428516ab63f961644bc49bc4cbe42bbffb2cd3b71cc7277c07d16b1a8b"},
- {file = "mypy-1.17.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:69e83ea6553a3ba79c08c6e15dbd9bfa912ec1e493bf75489ef93beb65209aeb"},
- {file = "mypy-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1b16708a66d38abb1e6b5702f5c2c87e133289da36f6a1d15f6a5221085c6403"},
- {file = "mypy-1.17.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:89e972c0035e9e05823907ad5398c5a73b9f47a002b22359b177d40bdaee7056"},
- {file = "mypy-1.17.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03b6d0ed2b188e35ee6d5c36b5580cffd6da23319991c49ab5556c023ccf1341"},
- {file = "mypy-1.17.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c837b896b37cd103570d776bda106eabb8737aa6dd4f248451aecf53030cdbeb"},
- {file = "mypy-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:665afab0963a4b39dff7c1fa563cc8b11ecff7910206db4b2e64dd1ba25aed19"},
- {file = "mypy-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:93378d3203a5c0800c6b6d850ad2f19f7a3cdf1a3701d3416dbf128805c6a6a7"},
- {file = "mypy-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:15d54056f7fe7a826d897789f53dd6377ec2ea8ba6f776dc83c2902b899fee81"},
- {file = "mypy-1.17.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:209a58fed9987eccc20f2ca94afe7257a8f46eb5df1fb69958650973230f91e6"},
- {file = "mypy-1.17.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:099b9a5da47de9e2cb5165e581f158e854d9e19d2e96b6698c0d64de911dd849"},
- {file = "mypy-1.17.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa6ffadfbe6994d724c5a1bb6123a7d27dd68fc9c059561cd33b664a79578e14"},
- {file = "mypy-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:9a2b7d9180aed171f033c9f2fc6c204c1245cf60b0cb61cf2e7acc24eea78e0a"},
- {file = "mypy-1.17.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:15a83369400454c41ed3a118e0cc58bd8123921a602f385cb6d6ea5df050c733"},
- {file = "mypy-1.17.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:55b918670f692fc9fba55c3298d8a3beae295c5cded0a55dccdc5bbead814acd"},
- {file = "mypy-1.17.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:62761474061feef6f720149d7ba876122007ddc64adff5ba6f374fda35a018a0"},
- {file = "mypy-1.17.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c49562d3d908fd49ed0938e5423daed8d407774a479b595b143a3d7f87cdae6a"},
- {file = "mypy-1.17.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:397fba5d7616a5bc60b45c7ed204717eaddc38f826e3645402c426057ead9a91"},
- {file = "mypy-1.17.1-cp314-cp314-win_amd64.whl", hash = "sha256:9d6b20b97d373f41617bd0708fd46aa656059af57f2ef72aa8c7d6a2b73b74ed"},
- {file = "mypy-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5d1092694f166a7e56c805caaf794e0585cabdbf1df36911c414e4e9abb62ae9"},
- {file = "mypy-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:79d44f9bfb004941ebb0abe8eff6504223a9c1ac51ef967d1263c6572bbebc99"},
- {file = "mypy-1.17.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b01586eed696ec905e61bd2568f48740f7ac4a45b3a468e6423a03d3788a51a8"},
- {file = "mypy-1.17.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43808d9476c36b927fbcd0b0255ce75efe1b68a080154a38ae68a7e62de8f0f8"},
- {file = "mypy-1.17.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:feb8cc32d319edd5859da2cc084493b3e2ce5e49a946377663cc90f6c15fb259"},
- {file = "mypy-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d7598cf74c3e16539d4e2f0b8d8c318e00041553d83d4861f87c7a72e95ac24d"},
- {file = "mypy-1.17.1-py3-none-any.whl", hash = "sha256:a9f52c0351c21fe24c21d8c0eb1f62967b262d6729393397b6f443c3b773c3b9"},
- {file = "mypy-1.17.1.tar.gz", hash = "sha256:25e01ec741ab5bb3eec8ba9cdb0f769230368a22c959c4937360efb89b7e9f01"},
+ {file = "mypy-1.18.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2761b6ae22a2b7d8e8607fb9b81ae90bc2e95ec033fd18fa35e807af6c657763"},
+ {file = "mypy-1.18.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5b10e3ea7f2eec23b4929a3fabf84505da21034a4f4b9613cda81217e92b74f3"},
+ {file = "mypy-1.18.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:261fbfced030228bc0f724d5d92f9ae69f46373bdfd0e04a533852677a11dbea"},
+ {file = "mypy-1.18.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4dc6b34a1c6875e6286e27d836a35c0d04e8316beac4482d42cfea7ed2527df8"},
+ {file = "mypy-1.18.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1cabb353194d2942522546501c0ff75c4043bf3b63069cb43274491b44b773c9"},
+ {file = "mypy-1.18.1-cp310-cp310-win_amd64.whl", hash = "sha256:738b171690c8e47c93569635ee8ec633d2cdb06062f510b853b5f233020569a9"},
+ {file = "mypy-1.18.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6c903857b3e28fc5489e54042684a9509039ea0aedb2a619469438b544ae1961"},
+ {file = "mypy-1.18.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2a0c8392c19934c2b6c65566d3a6abdc6b51d5da7f5d04e43f0eb627d6eeee65"},
+ {file = "mypy-1.18.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f85eb7efa2ec73ef63fc23b8af89c2fe5bf2a4ad985ed2d3ff28c1bb3c317c92"},
+ {file = "mypy-1.18.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:82ace21edf7ba8af31c3308a61dc72df30500f4dbb26f99ac36b4b80809d7e94"},
+ {file = "mypy-1.18.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a2dfd53dfe632f1ef5d161150a4b1f2d0786746ae02950eb3ac108964ee2975a"},
+ {file = "mypy-1.18.1-cp311-cp311-win_amd64.whl", hash = "sha256:320f0ad4205eefcb0e1a72428dde0ad10be73da9f92e793c36228e8ebf7298c0"},
+ {file = "mypy-1.18.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:502cde8896be8e638588b90fdcb4c5d5b8c1b004dfc63fd5604a973547367bb9"},
+ {file = "mypy-1.18.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7509549b5e41be279afc1228242d0e397f1af2919a8f2877ad542b199dc4083e"},
+ {file = "mypy-1.18.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5956ecaabb3a245e3f34100172abca1507be687377fe20e24d6a7557e07080e2"},
+ {file = "mypy-1.18.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8750ceb014a96c9890421c83f0db53b0f3b8633e2864c6f9bc0a8e93951ed18d"},
+ {file = "mypy-1.18.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fb89ea08ff41adf59476b235293679a6eb53a7b9400f6256272fb6029bec3ce5"},
+ {file = "mypy-1.18.1-cp312-cp312-win_amd64.whl", hash = "sha256:2657654d82fcd2a87e02a33e0d23001789a554059bbf34702d623dafe353eabf"},
+ {file = "mypy-1.18.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d70d2b5baf9b9a20bc9c730015615ae3243ef47fb4a58ad7b31c3e0a59b5ef1f"},
+ {file = "mypy-1.18.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b8367e33506300f07a43012fc546402f283c3f8bcff1dc338636affb710154ce"},
+ {file = "mypy-1.18.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:913f668ec50c3337b89df22f973c1c8f0b29ee9e290a8b7fe01cc1ef7446d42e"},
+ {file = "mypy-1.18.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1a0e70b87eb27b33209fa4792b051c6947976f6ab829daa83819df5f58330c71"},
+ {file = "mypy-1.18.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c378d946e8a60be6b6ede48c878d145546fb42aad61df998c056ec151bf6c746"},
+ {file = "mypy-1.18.1-cp313-cp313-win_amd64.whl", hash = "sha256:2cd2c1e0f3a7465f22731987fff6fc427e3dcbb4ca5f7db5bbeaff2ff9a31f6d"},
+ {file = "mypy-1.18.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ba24603c58e34dd5b096dfad792d87b304fc6470cbb1c22fd64e7ebd17edcc61"},
+ {file = "mypy-1.18.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ed36662fb92ae4cb3cacc682ec6656208f323bbc23d4b08d091eecfc0863d4b5"},
+ {file = "mypy-1.18.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:040ecc95e026f71a9ad7956fea2724466602b561e6a25c2e5584160d3833aaa8"},
+ {file = "mypy-1.18.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:937e3ed86cb731276706e46e03512547e43c391a13f363e08d0fee49a7c38a0d"},
+ {file = "mypy-1.18.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1f95cc4f01c0f1701ca3b0355792bccec13ecb2ec1c469e5b85a6ef398398b1d"},
+ {file = "mypy-1.18.1-cp314-cp314-win_amd64.whl", hash = "sha256:e4f16c0019d48941220ac60b893615be2f63afedaba6a0801bdcd041b96991ce"},
+ {file = "mypy-1.18.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e37763af63a8018308859bc83d9063c501a5820ec5bd4a19f0a2ac0d1c25c061"},
+ {file = "mypy-1.18.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:51531b6e94f34b8bd8b01dee52bbcee80daeac45e69ec5c36e25bce51cbc46e6"},
+ {file = "mypy-1.18.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dbfdea20e90e9c5476cea80cfd264d8e197c6ef2c58483931db2eefb2f7adc14"},
+ {file = "mypy-1.18.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:99f272c9b59f5826fffa439575716276d19cbf9654abc84a2ba2d77090a0ba14"},
+ {file = "mypy-1.18.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8c05a7f8c00300a52f3a4fcc95a185e99bf944d7e851ff141bae8dcf6dcfeac4"},
+ {file = "mypy-1.18.1-cp39-cp39-win_amd64.whl", hash = "sha256:2fbcecbe5cf213ba294aa8c0b8c104400bf7bb64db82fb34fe32a205da4b3531"},
+ {file = "mypy-1.18.1-py3-none-any.whl", hash = "sha256:b76a4de66a0ac01da1be14ecc8ae88ddea33b8380284a9e3eae39d57ebcbe26e"},
+ {file = "mypy-1.18.1.tar.gz", hash = "sha256:9e988c64ad3ac5987f43f5154f884747faf62141b7f842e87465b45299eea5a9"},
]
[package.dependencies]
From 4079793461735e6bd8b42d504fbac1d916d36ad4 Mon Sep 17 00:00:00 2001
From: Wisaroot <66859294+wisarootl@users.noreply.github.com>
Date: Sat, 13 Sep 2025 00:07:29 +0700
Subject: [PATCH 02/58] feat: add two_sum (#36)
---
.github/workflows/ci-test-reproducibility.yml | 46 ++++++++++
.templates/check_test_cases.py | 6 +-
.templates/leetcode/json/two_sum.json | 63 +++++++++++++
Makefile | 2 +-
leetcode/two_sum/README.md | 49 ++++++++++
leetcode/two_sum/__init__.py | 0
leetcode/two_sum/helpers.py | 8 ++
leetcode/two_sum/playground.ipynb | 92 +++++++++++++++++++
leetcode/two_sum/solution.py | 12 +++
leetcode/two_sum/test_solution.py | 39 ++++++++
10 files changed, 315 insertions(+), 2 deletions(-)
create mode 100644 .templates/leetcode/json/two_sum.json
create mode 100644 leetcode/two_sum/README.md
create mode 100644 leetcode/two_sum/__init__.py
create mode 100644 leetcode/two_sum/helpers.py
create mode 100644 leetcode/two_sum/playground.ipynb
create mode 100644 leetcode/two_sum/solution.py
create mode 100644 leetcode/two_sum/test_solution.py
diff --git a/.github/workflows/ci-test-reproducibility.yml b/.github/workflows/ci-test-reproducibility.yml
index 42c71c2..1be9cab 100644
--- a/.github/workflows/ci-test-reproducibility.yml
+++ b/.github/workflows/ci-test-reproducibility.yml
@@ -35,6 +35,40 @@ jobs:
- name: Install dependencies
run: poetry install --no-interaction --no-ansi
+ - name: Cache Graphviz installation
+ id: cache-graphviz
+ uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
+ with:
+ path: ~/graphviz-cache
+ key: graphviz-installed-${{ runner.os }}
+
+ - name: Install Graphviz
+ run: |
+ if [ "${{ steps.cache-graphviz.outputs.cache-hit }}" = "true" ]; then
+ sudo cp ~/graphviz-cache/bin/* /usr/bin/ 2>/dev/null || true
+ sudo cp ~/graphviz-cache/lib/* /usr/lib/x86_64-linux-gnu/ 2>/dev/null || true
+ sudo cp -r ~/graphviz-cache/share/graphviz /usr/share/ 2>/dev/null || true
+ sudo cp -r ~/graphviz-cache/lib/graphviz /usr/lib/x86_64-linux-gnu/ 2>/dev/null || true
+ sudo ldconfig
+ sudo dot -c
+ else
+ sudo apt-get update
+ sudo apt-get install -y graphviz
+ mkdir -p ~/graphviz-cache/{bin,lib,share}
+ cp /usr/bin/{dot,neato,twopi,circo,fdp,sfdp,patchwork,osage} ~/graphviz-cache/bin/ 2>/dev/null || true
+ cp /usr/lib/x86_64-linux-gnu/lib{gvc,cgraph,cdt,pathplan,gvpr,lab-gamut,ann,gts}* ~/graphviz-cache/lib/ 2>/dev/null || true
+ cp -r /usr/lib/x86_64-linux-gnu/graphviz ~/graphviz-cache/lib/ 2>/dev/null || true
+ cp -r /usr/share/graphviz ~/graphviz-cache/share/ 2>/dev/null || true
+ fi
+
+ - name: Check test case count
+ run: poetry run python .templates/check_test_cases.py --threshold=10 --max=100
+
+ - name: Backup existing problems
+ run: |
+ mkdir -p .cache
+ cp -r leetcode .cache/
+
- name: Delete existing problems
run: rm -rf leetcode/*/
@@ -46,3 +80,15 @@ jobs:
- name: Run linting to verify reproducibility
run: make lint
+
+ - name: Copy solution files from backup
+ run: |
+ for problem in .cache/leetcode/*/; do
+ problem_name=$(basename "$problem")
+ if [ -f "$problem/solution.py" ] && [ -d "leetcode/$problem_name" ]; then
+ cp "$problem/solution.py" "leetcode/$problem_name/solution.py"
+ fi
+ done
+
+ - name: Run tests
+ run: make test
diff --git a/.templates/check_test_cases.py b/.templates/check_test_cases.py
index 4c36ffe..a99a310 100644
--- a/.templates/check_test_cases.py
+++ b/.templates/check_test_cases.py
@@ -82,10 +82,14 @@ def main(
typer.echo(f"Invalid max_results value: {max_results}", err=True)
raise typer.Exit(1)
- typer.echo(f"Files with ≤{threshold} test cases ({len(filtered_files)} total):")
+ typer.echo(f"Problems with ≤{threshold} test cases ({len(filtered_files)} total):")
for filename, count in filtered_files:
typer.echo(f"{filename}: {count} test cases")
+ # Exit with non-zero code if any files found
+ if filtered_files:
+ raise typer.Exit(1)
+
if __name__ == "__main__":
typer.run(main)
diff --git a/.templates/leetcode/json/two_sum.json b/.templates/leetcode/json/two_sum.json
new file mode 100644
index 0000000..a1c69c3
--- /dev/null
+++ b/.templates/leetcode/json/two_sum.json
@@ -0,0 +1,63 @@
+{
+ "problem_name": "two_sum",
+ "solution_class_name": "Solution",
+ "problem_number": "1",
+ "problem_title": "Two Sum",
+ "difficulty": "Easy",
+ "topics": "Array, Hash Table",
+ "_tags": { "list": ["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\nYou may assume that each input would have exactly one solution, and you may not use the same element twice.\n\nYou can return the answer in any order.",
+ "_readme_examples": {
+ "list": [
+ {
+ "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": "```\nInput: nums = [3,2,4], target = 6\nOutput: [1,2]\n```" },
+ { "content": "```\nInput: nums = [3,3], target = 6\nOutput: [0,1]\n```" }
+ ]
+ },
+ "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": "**Follow-up:** Can you come up with an algorithm that is less than O(n^2) time complexity?",
+ "helpers_imports": "",
+ "helpers_content": "",
+ "helpers_run_name": "two_sum",
+ "helpers_run_signature": "(solution_class: type, nums: list[int], target: int)",
+ "helpers_run_body": " implementation = solution_class()\n return implementation.two_sum(nums, target)",
+ "helpers_assert_name": "two_sum",
+ "helpers_assert_signature": "(result: list[int], expected: list[int]) -> bool",
+ "helpers_assert_body": " assert result == expected\n return True",
+ "solution_imports": "",
+ "solution_contents": "",
+ "solution_class_content": "",
+ "test_imports": "import pytest\nfrom leetcode_py.test_utils import logged_test\nfrom .helpers import assert_two_sum, run_two_sum\nfrom .solution import Solution",
+ "test_content": "",
+ "test_class_name": "TwoSum",
+ "test_class_content": " def setup_method(self):\n self.solution = Solution()",
+ "_solution_methods": {
+ "list": [
+ {
+ "name": "two_sum",
+ "signature": "(self, nums: list[int], target: int) -> list[int]",
+ "body": " # TODO: Implement two_sum\n return []"
+ }
+ ]
+ },
+ "_test_helper_methods": {
+ "list": [{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }]
+ },
+ "_test_methods": {
+ "list": [
+ {
+ "name": "test_two_sum",
+ "signature": "(self, nums: list[int], target: int, expected: list[int])",
+ "parametrize": "nums, target, expected",
+ "test_cases": "[([2, 7, 11, 15], 9, [0, 1]), ([3, 2, 4], 6, [1, 2]), ([3, 3], 6, [0, 1]), ([2, 5, 5, 11], 10, [1, 2]), ([1, 2, 3, 4, 5], 8, [2, 4]), ([0, 4, 3, 0], 0, [0, 3]), ([-1, -2, -3, -4, -5], -8, [2, 4]), ([1, 3, 4, 2], 6, [2, 3]), ([5, 75, 25], 100, [1, 2]), ([-3, 4, 3, 90], 0, [0, 2]), ([1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 2], 6, [5, 11]), ([2, 1, 9, 4, 4, 56, 90, 3], 8, [3, 4]), ([89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99], 185, [3, 4]), ([-1000000000, 1000000000], 0, [0, 1]), ([0, 1], 1, [0, 1]), ([1, 2], 5, []), ([3, 5, 7], 1, []), ([10, 20, 30], 15, [])]",
+ "body": " result = run_two_sum(Solution, nums, target)\n assert_two_sum(result, expected)"
+ }
+ ]
+ },
+ "playground_imports": "from helpers import run_two_sum, assert_two_sum\nfrom solution import Solution",
+ "playground_setup": "# Example test case\nnums = [2, 7, 11, 15]\ntarget = 9\nexpected = [0, 1]",
+ "playground_run": "result = run_two_sum(Solution, nums, target)\nresult",
+ "playground_assert": "assert_two_sum(result, expected)"
+}
diff --git a/Makefile b/Makefile
index 3bdc248..0f97dae 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
PYTHON_VERSION = 3.13
-PROBLEM ?= min_stack
+PROBLEM ?= two_sum
FORCE ?= 0
COMMA := ,
diff --git a/leetcode/two_sum/README.md b/leetcode/two_sum/README.md
new file mode 100644
index 0000000..7f8a41d
--- /dev/null
+++ b/leetcode/two_sum/README.md
@@ -0,0 +1,49 @@
+# Two Sum
+
+**Difficulty:** Easy
+**Topics:** Array, Hash Table
+**Tags:** grind-75
+
+**LeetCode:** [Problem 1](https://leetcode.com/problems/two-sum/description/)
+
+## 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`.
+
+You may assume that each input would have exactly one solution, and you may not use the same element twice.
+
+You can return the answer in any order.
+
+## Examples
+
+### Example 1:
+
+```
+Input: nums = [2,7,11,15], target = 9
+Output: [0,1]
+```
+
+**Explanation:** Because nums[0] + nums[1] == 9, we return [0, 1].
+
+### Example 2:
+
+```
+Input: nums = [3,2,4], target = 6
+Output: [1,2]
+```
+
+### Example 3:
+
+```
+Input: nums = [3,3], target = 6
+Output: [0,1]
+```
+
+## Constraints
+
+- 2 <= nums.length <= 10^4
+- -10^9 <= nums[i] <= 10^9
+- -10^9 <= target <= 10^9
+- Only one valid answer exists.
+
+**Follow-up:** Can you come up with an algorithm that is less than O(n^2) time complexity?
diff --git a/leetcode/two_sum/__init__.py b/leetcode/two_sum/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/leetcode/two_sum/helpers.py b/leetcode/two_sum/helpers.py
new file mode 100644
index 0000000..00f7b73
--- /dev/null
+++ b/leetcode/two_sum/helpers.py
@@ -0,0 +1,8 @@
+def run_two_sum(solution_class: type, nums: list[int], target: int):
+ implementation = solution_class()
+ return implementation.two_sum(nums, target)
+
+
+def assert_two_sum(result: list[int], expected: list[int]) -> bool:
+ assert result == expected
+ return True
diff --git a/leetcode/two_sum/playground.ipynb b/leetcode/two_sum/playground.ipynb
new file mode 100644
index 0000000..1a6ec8b
--- /dev/null
+++ b/leetcode/two_sum/playground.ipynb
@@ -0,0 +1,92 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "imports",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from helpers import assert_two_sum, run_two_sum\n",
+ "from solution import Solution"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "setup",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Example test case\n",
+ "nums = [2, 7, 11, 15]\n",
+ "target = 9\n",
+ "expected = [0, 1]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "run",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[0, 1]"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "result = run_two_sum(Solution, nums, target)\n",
+ "result"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "assert",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "assert_two_sum(result, expected)"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "leetcode-py-py3.13",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.13.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/leetcode/two_sum/solution.py b/leetcode/two_sum/solution.py
new file mode 100644
index 0000000..ea4c593
--- /dev/null
+++ b/leetcode/two_sum/solution.py
@@ -0,0 +1,12 @@
+class Solution:
+
+ # Time: O(n)
+ # Space: O(n)
+ def two_sum(self, nums: list[int], target: int) -> list[int]:
+ seen: dict[int, int] = {}
+ for i, num in enumerate(nums):
+ complement = target - num
+ if complement in seen:
+ return [seen[complement], i]
+ seen[num] = i
+ return []
diff --git a/leetcode/two_sum/test_solution.py b/leetcode/two_sum/test_solution.py
new file mode 100644
index 0000000..75cb3f3
--- /dev/null
+++ b/leetcode/two_sum/test_solution.py
@@ -0,0 +1,39 @@
+import pytest
+
+from leetcode_py.test_utils import logged_test
+
+from .helpers import assert_two_sum, run_two_sum
+from .solution import Solution
+
+
+class TestTwoSum:
+ def setup_method(self):
+ self.solution = Solution()
+
+ @logged_test
+ @pytest.mark.parametrize(
+ "nums, target, expected",
+ [
+ ([2, 7, 11, 15], 9, [0, 1]),
+ ([3, 2, 4], 6, [1, 2]),
+ ([3, 3], 6, [0, 1]),
+ ([2, 5, 5, 11], 10, [1, 2]),
+ ([1, 2, 3, 4, 5], 8, [2, 4]),
+ ([0, 4, 3, 0], 0, [0, 3]),
+ ([-1, -2, -3, -4, -5], -8, [2, 4]),
+ ([1, 3, 4, 2], 6, [2, 3]),
+ ([5, 75, 25], 100, [1, 2]),
+ ([-3, 4, 3, 90], 0, [0, 2]),
+ ([1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 2], 6, [5, 11]),
+ ([2, 1, 9, 4, 4, 56, 90, 3], 8, [3, 4]),
+ ([89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99], 185, [3, 4]),
+ ([-1000000000, 1000000000], 0, [0, 1]),
+ ([0, 1], 1, [0, 1]),
+ ([1, 2], 5, []),
+ ([3, 5, 7], 1, []),
+ ([10, 20, 30], 15, []),
+ ],
+ )
+ def test_two_sum(self, nums: list[int], target: int, expected: list[int]):
+ result = run_two_sum(Solution, nums, target)
+ assert_two_sum(result, expected)
From 9f2c846652153909a578b1c5730a985f2a892493 Mon Sep 17 00:00:00 2001
From: Wisaroot <66859294+wisarootl@users.noreply.github.com>
Date: Sat, 13 Sep 2025 01:09:34 +0700
Subject: [PATCH 03/58] feat: convert .ipynb to .py (#37)
---
.codecov.yml | 2 +
.github/workflows/ci-pre-commit.yml | 4 +
.pre-commit-config.yaml | 11 +
Makefile | 7 +
leetcode/accounts_merge/playground.ipynb | 102 ------
leetcode/accounts_merge/playground.py | 38 ++
leetcode/add_binary/playground.ipynb | 69 ----
leetcode/add_binary/playground.py | 30 ++
.../balanced_binary_tree/playground.ipynb | 183 ----------
leetcode/balanced_binary_tree/playground.py | 35 ++
leetcode/basic_calculator/playground.ipynb | 91 -----
leetcode/basic_calculator/playground.py | 30 ++
.../playground.ipynb | 91 -----
.../playground.py | 30 ++
leetcode/binary_search/playground.ipynb | 69 ----
leetcode/binary_search/playground.py | 31 ++
.../playground.ipynb | 70 ----
.../playground.py | 30 ++
.../playground.ipynb | 183 ----------
.../binary_tree_right_side_view/playground.py | 36 ++
.../test_solution.py | 9 +-
leetcode/climbing_stairs/playground.ipynb | 68 ----
leetcode/climbing_stairs/playground.py | 30 ++
leetcode/clone_graph/playground.ipynb | 69 ----
leetcode/clone_graph/playground.py | 29 ++
leetcode/coin_change/playground.ipynb | 69 ----
leetcode/coin_change/playground.py | 31 ++
leetcode/combination_sum/playground.ipynb | 69 ----
leetcode/combination_sum/playground.py | 31 ++
.../playground.ipynb | 68 ----
.../container_with_most_water/playground.py | 30 ++
leetcode/contains_duplicate/playground.ipynb | 91 -----
leetcode/contains_duplicate/playground.py | 30 ++
leetcode/course_schedule/playground.ipynb | 69 ----
leetcode/course_schedule/playground.py | 31 ++
.../diameter_of_binary_tree/playground.ipynb | 70 ----
.../diameter_of_binary_tree/playground.py | 30 ++
.../playground.ipynb | 68 ----
.../playground.py | 30 ++
.../playground.ipynb | 70 ----
.../playground.py | 32 ++
leetcode/first_bad_version/playground.ipynb | 69 ----
leetcode/first_bad_version/playground.py | 31 ++
leetcode/flood_fill/playground.ipynb | 71 ----
leetcode/flood_fill/playground.py | 33 ++
.../playground.ipynb | 70 ----
.../playground.py | 32 ++
.../playground.ipynb | 204 -----------
.../implement_trie_prefix_tree/playground.py | 32 ++
leetcode/insert_interval/playground.ipynb | 69 ----
leetcode/insert_interval/playground.py | 31 ++
leetcode/invert_binary_tree/playground.ipynb | 185 ----------
leetcode/invert_binary_tree/playground.py | 30 ++
leetcode/invert_binary_tree/test_solution.py | 9 +-
.../playground.ipynb | 69 ----
.../k_closest_points_to_origin/playground.py | 31 ++
.../playground.ipynb | 71 ----
.../playground.py | 31 ++
.../playground.ipynb | 68 ----
.../playground.py | 30 ++
leetcode/linked_list_cycle/playground.ipynb | 177 ----------
leetcode/linked_list_cycle/playground.py | 35 ++
leetcode/longest_palindrome/playground.ipynb | 68 ----
leetcode/longest_palindrome/playground.py | 30 ++
.../playground.ipynb | 68 ----
.../playground.py | 30 ++
.../test_solution.py | 7 +-
.../playground.ipynb | 68 ----
.../playground.py | 30 ++
.../playground.ipynb | 72 ----
.../playground.py | 32 ++
.../playground.ipynb | 72 ----
.../playground.py | 32 ++
leetcode/lru_cache/playground.ipynb | 100 ------
leetcode/lru_cache/playground.py | 32 ++
leetcode/lru_cache/test_solution.py | 13 +-
leetcode/majority_element/playground.ipynb | 68 ----
leetcode/majority_element/playground.py | 30 ++
.../playground.ipynb | 70 ----
.../playground.py | 30 ++
.../playground.ipynb | 70 ----
.../playground.py | 32 ++
leetcode/maximum_subarray/playground.ipynb | 68 ----
leetcode/maximum_subarray/playground.py | 30 ++
leetcode/merge_intervals/playground.ipynb | 68 ----
leetcode/merge_intervals/playground.py | 30 ++
.../merge_k_sorted_lists/playground.ipynb | 70 ----
leetcode/merge_k_sorted_lists/playground.py | 32 ++
.../merge_two_sorted_lists/playground.ipynb | 71 ----
leetcode/merge_two_sorted_lists/playground.py | 33 ++
.../playground.ipynb | 70 ----
.../middle_of_the_linked_list/playground.py | 32 ++
leetcode/min_stack/playground.ipynb | 69 ----
leetcode/min_stack/playground.py | 31 ++
.../minimum_height_trees/playground.ipynb | 69 ----
leetcode/minimum_height_trees/playground.py | 31 ++
.../minimum_window_substring/playground.ipynb | 69 ----
.../minimum_window_substring/playground.py | 31 ++
leetcode/number_of_islands/playground.ipynb | 73 ----
leetcode/number_of_islands/playground.py | 35 ++
.../playground.ipynb | 68 ----
.../partition_equal_subset_sum/playground.py | 30 ++
.../test_solution.py | 7 +-
leetcode/permutations/playground.ipynb | 68 ----
leetcode/permutations/playground.py | 30 ++
.../playground.ipynb | 68 ----
.../playground.py | 30 ++
leetcode/ransom_note/playground.ipynb | 69 ----
leetcode/ransom_note/playground.py | 31 ++
leetcode/reverse_linked_list/playground.ipynb | 70 ----
leetcode/reverse_linked_list/playground.py | 30 ++
.../reverse_linked_list_ii/playground.ipynb | 71 ----
leetcode/reverse_linked_list_ii/playground.py | 31 ++
leetcode/rotting_oranges/playground.ipynb | 68 ----
leetcode/rotting_oranges/playground.py | 30 ++
.../playground.ipynb | 69 ----
.../playground.py | 31 ++
.../playground.ipynb | 69 ----
.../playground.py | 29 ++
leetcode/sort_colors/playground.ipynb | 68 ----
leetcode/sort_colors/playground.py | 30 ++
leetcode/spiral_matrix/playground.ipynb | 68 ----
leetcode/spiral_matrix/playground.py | 30 ++
.../string_to_integer_atoi/playground.ipynb | 68 ----
leetcode/string_to_integer_atoi/playground.py | 30 ++
leetcode/task_scheduler/playground.ipynb | 69 ----
leetcode/task_scheduler/playground.py | 31 ++
leetcode/three_sum/playground.ipynb | 68 ----
leetcode/three_sum/playground.py | 30 ++
.../playground.ipynb | 69 ----
.../time_based_key_value_store/playground.py | 31 ++
leetcode/trapping_rain_water/playground.ipynb | 91 -----
leetcode/trapping_rain_water/playground.py | 30 ++
leetcode/two_sum/playground.ipynb | 92 -----
leetcode/two_sum/playground.py | 31 ++
leetcode/valid_anagram/playground.ipynb | 92 -----
leetcode/valid_anagram/playground.py | 31 ++
leetcode/valid_palindrome/playground.ipynb | 68 ----
leetcode/valid_palindrome/playground.py | 30 ++
leetcode/valid_parentheses/playground.ipynb | 68 ----
leetcode/valid_parentheses/playground.py | 30 ++
.../playground.ipynb | 70 ----
.../validate_binary_search_tree/playground.py | 30 ++
.../test_solution.py | 7 +-
leetcode/word_break/playground.ipynb | 69 ----
leetcode/word_break/playground.py | 31 ++
leetcode/word_ladder/playground.ipynb | 70 ----
leetcode/word_ladder/playground.py | 32 ++
leetcode/zero_one_matrix/playground.ipynb | 91 -----
leetcode/zero_one_matrix/playground.py | 30 ++
poetry.lock | 326 +++++++++++++++++-
pyproject.toml | 1 +
scripts/shared | 2 +-
sonar-project.properties | 2 +-
154 files changed, 2558 insertions(+), 5667 deletions(-)
delete mode 100644 leetcode/accounts_merge/playground.ipynb
create mode 100644 leetcode/accounts_merge/playground.py
delete mode 100644 leetcode/add_binary/playground.ipynb
create mode 100644 leetcode/add_binary/playground.py
delete mode 100644 leetcode/balanced_binary_tree/playground.ipynb
create mode 100644 leetcode/balanced_binary_tree/playground.py
delete mode 100644 leetcode/basic_calculator/playground.ipynb
create mode 100644 leetcode/basic_calculator/playground.py
delete mode 100644 leetcode/best_time_to_buy_and_sell_stock/playground.ipynb
create mode 100644 leetcode/best_time_to_buy_and_sell_stock/playground.py
delete mode 100644 leetcode/binary_search/playground.ipynb
create mode 100644 leetcode/binary_search/playground.py
delete mode 100644 leetcode/binary_tree_level_order_traversal/playground.ipynb
create mode 100644 leetcode/binary_tree_level_order_traversal/playground.py
delete mode 100644 leetcode/binary_tree_right_side_view/playground.ipynb
create mode 100644 leetcode/binary_tree_right_side_view/playground.py
delete mode 100644 leetcode/climbing_stairs/playground.ipynb
create mode 100644 leetcode/climbing_stairs/playground.py
delete mode 100644 leetcode/clone_graph/playground.ipynb
create mode 100644 leetcode/clone_graph/playground.py
delete mode 100644 leetcode/coin_change/playground.ipynb
create mode 100644 leetcode/coin_change/playground.py
delete mode 100644 leetcode/combination_sum/playground.ipynb
create mode 100644 leetcode/combination_sum/playground.py
delete mode 100644 leetcode/container_with_most_water/playground.ipynb
create mode 100644 leetcode/container_with_most_water/playground.py
delete mode 100644 leetcode/contains_duplicate/playground.ipynb
create mode 100644 leetcode/contains_duplicate/playground.py
delete mode 100644 leetcode/course_schedule/playground.ipynb
create mode 100644 leetcode/course_schedule/playground.py
delete mode 100644 leetcode/diameter_of_binary_tree/playground.ipynb
create mode 100644 leetcode/diameter_of_binary_tree/playground.py
delete mode 100644 leetcode/evaluate_reverse_polish_notation/playground.ipynb
create mode 100644 leetcode/evaluate_reverse_polish_notation/playground.py
delete mode 100644 leetcode/find_median_from_data_stream/playground.ipynb
create mode 100644 leetcode/find_median_from_data_stream/playground.py
delete mode 100644 leetcode/first_bad_version/playground.ipynb
create mode 100644 leetcode/first_bad_version/playground.py
delete mode 100644 leetcode/flood_fill/playground.ipynb
create mode 100644 leetcode/flood_fill/playground.py
delete mode 100644 leetcode/implement_queue_using_stacks/playground.ipynb
create mode 100644 leetcode/implement_queue_using_stacks/playground.py
delete mode 100644 leetcode/implement_trie_prefix_tree/playground.ipynb
create mode 100644 leetcode/implement_trie_prefix_tree/playground.py
delete mode 100644 leetcode/insert_interval/playground.ipynb
create mode 100644 leetcode/insert_interval/playground.py
delete mode 100644 leetcode/invert_binary_tree/playground.ipynb
create mode 100644 leetcode/invert_binary_tree/playground.py
delete mode 100644 leetcode/k_closest_points_to_origin/playground.ipynb
create mode 100644 leetcode/k_closest_points_to_origin/playground.py
delete mode 100644 leetcode/kth_smallest_element_in_a_bst/playground.ipynb
create mode 100644 leetcode/kth_smallest_element_in_a_bst/playground.py
delete mode 100644 leetcode/largest_rectangle_in_histogram/playground.ipynb
create mode 100644 leetcode/largest_rectangle_in_histogram/playground.py
delete mode 100644 leetcode/linked_list_cycle/playground.ipynb
create mode 100644 leetcode/linked_list_cycle/playground.py
delete mode 100644 leetcode/longest_palindrome/playground.ipynb
create mode 100644 leetcode/longest_palindrome/playground.py
delete mode 100644 leetcode/longest_palindromic_substring/playground.ipynb
create mode 100644 leetcode/longest_palindromic_substring/playground.py
delete mode 100644 leetcode/longest_substring_without_repeating_characters/playground.ipynb
create mode 100644 leetcode/longest_substring_without_repeating_characters/playground.py
delete mode 100644 leetcode/lowest_common_ancestor_of_a_binary_search_tree/playground.ipynb
create mode 100644 leetcode/lowest_common_ancestor_of_a_binary_search_tree/playground.py
delete mode 100644 leetcode/lowest_common_ancestor_of_a_binary_tree/playground.ipynb
create mode 100644 leetcode/lowest_common_ancestor_of_a_binary_tree/playground.py
delete mode 100644 leetcode/lru_cache/playground.ipynb
create mode 100644 leetcode/lru_cache/playground.py
delete mode 100644 leetcode/majority_element/playground.ipynb
create mode 100644 leetcode/majority_element/playground.py
delete mode 100644 leetcode/maximum_depth_of_binary_tree/playground.ipynb
create mode 100644 leetcode/maximum_depth_of_binary_tree/playground.py
delete mode 100644 leetcode/maximum_profit_in_job_scheduling/playground.ipynb
create mode 100644 leetcode/maximum_profit_in_job_scheduling/playground.py
delete mode 100644 leetcode/maximum_subarray/playground.ipynb
create mode 100644 leetcode/maximum_subarray/playground.py
delete mode 100644 leetcode/merge_intervals/playground.ipynb
create mode 100644 leetcode/merge_intervals/playground.py
delete mode 100644 leetcode/merge_k_sorted_lists/playground.ipynb
create mode 100644 leetcode/merge_k_sorted_lists/playground.py
delete mode 100644 leetcode/merge_two_sorted_lists/playground.ipynb
create mode 100644 leetcode/merge_two_sorted_lists/playground.py
delete mode 100644 leetcode/middle_of_the_linked_list/playground.ipynb
create mode 100644 leetcode/middle_of_the_linked_list/playground.py
delete mode 100644 leetcode/min_stack/playground.ipynb
create mode 100644 leetcode/min_stack/playground.py
delete mode 100644 leetcode/minimum_height_trees/playground.ipynb
create mode 100644 leetcode/minimum_height_trees/playground.py
delete mode 100644 leetcode/minimum_window_substring/playground.ipynb
create mode 100644 leetcode/minimum_window_substring/playground.py
delete mode 100644 leetcode/number_of_islands/playground.ipynb
create mode 100644 leetcode/number_of_islands/playground.py
delete mode 100644 leetcode/partition_equal_subset_sum/playground.ipynb
create mode 100644 leetcode/partition_equal_subset_sum/playground.py
delete mode 100644 leetcode/permutations/playground.ipynb
create mode 100644 leetcode/permutations/playground.py
delete mode 100644 leetcode/product_of_array_except_self/playground.ipynb
create mode 100644 leetcode/product_of_array_except_self/playground.py
delete mode 100644 leetcode/ransom_note/playground.ipynb
create mode 100644 leetcode/ransom_note/playground.py
delete mode 100644 leetcode/reverse_linked_list/playground.ipynb
create mode 100644 leetcode/reverse_linked_list/playground.py
delete mode 100644 leetcode/reverse_linked_list_ii/playground.ipynb
create mode 100644 leetcode/reverse_linked_list_ii/playground.py
delete mode 100644 leetcode/rotting_oranges/playground.ipynb
create mode 100644 leetcode/rotting_oranges/playground.py
delete mode 100644 leetcode/search_in_rotated_sorted_array/playground.ipynb
create mode 100644 leetcode/search_in_rotated_sorted_array/playground.py
delete mode 100644 leetcode/serialize_and_deserialize_binary_tree/playground.ipynb
create mode 100644 leetcode/serialize_and_deserialize_binary_tree/playground.py
delete mode 100644 leetcode/sort_colors/playground.ipynb
create mode 100644 leetcode/sort_colors/playground.py
delete mode 100644 leetcode/spiral_matrix/playground.ipynb
create mode 100644 leetcode/spiral_matrix/playground.py
delete mode 100644 leetcode/string_to_integer_atoi/playground.ipynb
create mode 100644 leetcode/string_to_integer_atoi/playground.py
delete mode 100644 leetcode/task_scheduler/playground.ipynb
create mode 100644 leetcode/task_scheduler/playground.py
delete mode 100644 leetcode/three_sum/playground.ipynb
create mode 100644 leetcode/three_sum/playground.py
delete mode 100644 leetcode/time_based_key_value_store/playground.ipynb
create mode 100644 leetcode/time_based_key_value_store/playground.py
delete mode 100644 leetcode/trapping_rain_water/playground.ipynb
create mode 100644 leetcode/trapping_rain_water/playground.py
delete mode 100644 leetcode/two_sum/playground.ipynb
create mode 100644 leetcode/two_sum/playground.py
delete mode 100644 leetcode/valid_anagram/playground.ipynb
create mode 100644 leetcode/valid_anagram/playground.py
delete mode 100644 leetcode/valid_palindrome/playground.ipynb
create mode 100644 leetcode/valid_palindrome/playground.py
delete mode 100644 leetcode/valid_parentheses/playground.ipynb
create mode 100644 leetcode/valid_parentheses/playground.py
delete mode 100644 leetcode/validate_binary_search_tree/playground.ipynb
create mode 100644 leetcode/validate_binary_search_tree/playground.py
delete mode 100644 leetcode/word_break/playground.ipynb
create mode 100644 leetcode/word_break/playground.py
delete mode 100644 leetcode/word_ladder/playground.ipynb
create mode 100644 leetcode/word_ladder/playground.py
delete mode 100644 leetcode/zero_one_matrix/playground.ipynb
create mode 100644 leetcode/zero_one_matrix/playground.py
diff --git a/.codecov.yml b/.codecov.yml
index 7c00c0a..c11c152 100644
--- a/.codecov.yml
+++ b/.codecov.yml
@@ -1,4 +1,6 @@
coverage:
+ ignore:
+ - "**/playground.py"
status:
project:
default:
diff --git a/.github/workflows/ci-pre-commit.yml b/.github/workflows/ci-pre-commit.yml
index 2e8ee70..2ff49f4 100644
--- a/.github/workflows/ci-pre-commit.yml
+++ b/.github/workflows/ci-pre-commit.yml
@@ -9,6 +9,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+ with:
+ fetch-depth: 0
+ submodules: recursive
+ token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 5123e0d..23a8453 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -22,6 +22,17 @@ repos:
id: gitleaks
- repo: local
hooks:
+ - id: sync-submodules
+ name: Sync git submodules
+ entry: bash -c 'output=$(git submodule update --init --recursive --remote 2>&1); [ -z "$output" ]'
+ language: system
+ always_run: true
+ pass_filenames: false
+ - id: nb-to-py
+ name: convert notebooks to python
+ entry: make nb-to-py
+ language: system
+ pass_filenames: false
- id: lint
name: lint
entry: make lint
diff --git a/Makefile b/Makefile
index 0f97dae..377ff6d 100644
--- a/Makefile
+++ b/Makefile
@@ -77,6 +77,13 @@ p-gen:
p-del:
rm -rf leetcode/$(PROBLEM)
+# Convert all notebooks to .py files and delete .ipynb for better version control
+nb-to-py:
+ @echo "Converting all .ipynb files in leetcode/ to .py files..."
+ @find leetcode -name "*.ipynb" -exec poetry run jupytext --to py:percent {} \;
+ @find leetcode -name "*.ipynb" -delete
+ @echo "Conversion complete. All .ipynb files converted to .py and deleted."
+
# Generate All Problems - useful for people who fork this repo
gen-all-problems:
@echo "This will DELETE all existing problems and regenerate from JSON templates."
diff --git a/leetcode/accounts_merge/playground.ipynb b/leetcode/accounts_merge/playground.ipynb
deleted file mode 100644
index f0dcd43..0000000
--- a/leetcode/accounts_merge/playground.ipynb
+++ /dev/null
@@ -1,102 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": 1,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_accounts_merge, run_accounts_merge\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "accounts = [\n",
- " [\"John\", \"johnsmith@mail.com\", \"john_newyork@mail.com\"],\n",
- " [\"John\", \"johnsmith@mail.com\", \"john00@mail.com\"],\n",
- " [\"Mary\", \"mary@mail.com\"],\n",
- " [\"John\", \"johnnybravo@mail.com\"],\n",
- "]\n",
- "expected = [\n",
- " [\"John\", \"john00@mail.com\", \"john_newyork@mail.com\", \"johnsmith@mail.com\"],\n",
- " [\"Mary\", \"mary@mail.com\"],\n",
- " [\"John\", \"johnnybravo@mail.com\"],\n",
- "]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "id": "run",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "[['John', 'john00@mail.com', 'john_newyork@mail.com', 'johnsmith@mail.com'],\n",
- " ['Mary', 'mary@mail.com'],\n",
- " ['John', 'johnnybravo@mail.com']]"
- ]
- },
- "execution_count": 3,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "result = run_accounts_merge(Solution, accounts)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "id": "assert",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "True"
- ]
- },
- "execution_count": 4,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "assert_accounts_merge(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/accounts_merge/playground.py b/leetcode/accounts_merge/playground.py
new file mode 100644
index 0000000..d2ee36c
--- /dev/null
+++ b/leetcode/accounts_merge/playground.py
@@ -0,0 +1,38 @@
+# ---
+# 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_accounts_merge, run_accounts_merge
+from solution import Solution
+
+# %%
+# Example test case
+accounts = [
+ ["John", "johnsmith@mail.com", "john_newyork@mail.com"],
+ ["John", "johnsmith@mail.com", "john00@mail.com"],
+ ["Mary", "mary@mail.com"],
+ ["John", "johnnybravo@mail.com"],
+]
+expected = [
+ ["John", "john00@mail.com", "john_newyork@mail.com", "johnsmith@mail.com"],
+ ["Mary", "mary@mail.com"],
+ ["John", "johnnybravo@mail.com"],
+]
+
+# %%
+result = run_accounts_merge(Solution, accounts)
+result
+
+# %%
+assert_accounts_merge(result, expected)
diff --git a/leetcode/add_binary/playground.ipynb b/leetcode/add_binary/playground.ipynb
deleted file mode 100644
index 0b2a93d..0000000
--- a/leetcode/add_binary/playground.ipynb
+++ /dev/null
@@ -1,69 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_add_binary, run_add_binary\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "a = \"11\"\n",
- "b = \"1\"\n",
- "expected = \"100\""
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_add_binary(Solution, a, b)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_add_binary(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/add_binary/playground.py b/leetcode/add_binary/playground.py
new file mode 100644
index 0000000..41e3fdd
--- /dev/null
+++ b/leetcode/add_binary/playground.py
@@ -0,0 +1,30 @@
+# ---
+# 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_add_binary, run_add_binary
+from solution import Solution
+
+# %%
+# Example test case
+a = "11"
+b = "1"
+expected = "100"
+
+# %%
+result = run_add_binary(Solution, a, b)
+result
+
+# %%
+assert_add_binary(result, expected)
diff --git a/leetcode/balanced_binary_tree/playground.ipynb b/leetcode/balanced_binary_tree/playground.ipynb
deleted file mode 100644
index e115cdb..0000000
--- a/leetcode/balanced_binary_tree/playground.ipynb
+++ /dev/null
@@ -1,183 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": 1,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_is_balanced, run_is_balanced\n",
- "from solution import Solution\n",
- "\n",
- "from leetcode_py import TreeNode"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "root_list: list[int | None] = [3, 9, 20, None, None, 15, 7]\n",
- "expected = True"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "id": "run",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "True"
- ]
- },
- "execution_count": 3,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "result = run_is_balanced(Solution, root_list)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "id": "c01db53b",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text/plain": [
- "TreeNode([3, 9, 20, None, None, 15, 7])"
- ]
- },
- "execution_count": 5,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "root = TreeNode.from_list(root_list)\n",
- "root"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "id": "assert",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "True"
- ]
- },
- "execution_count": 4,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "assert_is_balanced(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/balanced_binary_tree/playground.py b/leetcode/balanced_binary_tree/playground.py
new file mode 100644
index 0000000..900c979
--- /dev/null
+++ b/leetcode/balanced_binary_tree/playground.py
@@ -0,0 +1,35 @@
+# ---
+# 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_is_balanced, run_is_balanced
+from solution import Solution
+
+from leetcode_py import TreeNode
+
+# %%
+# Example test case
+root_list: list[int | None] = [3, 9, 20, None, None, 15, 7]
+expected = True
+
+# %%
+result = run_is_balanced(Solution, root_list)
+result
+
+# %%
+root = TreeNode.from_list(root_list)
+root
+
+# %%
+assert_is_balanced(result, expected)
diff --git a/leetcode/basic_calculator/playground.ipynb b/leetcode/basic_calculator/playground.ipynb
deleted file mode 100644
index d7681b7..0000000
--- a/leetcode/basic_calculator/playground.ipynb
+++ /dev/null
@@ -1,91 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": 1,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_calculate, run_calculate\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "s = \"(1+(4+5+2)-3)+(6+8)\"\n",
- "expected = 23"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "id": "run",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "23"
- ]
- },
- "execution_count": 3,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "result = run_calculate(Solution, s)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "id": "assert",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "True"
- ]
- },
- "execution_count": 4,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "assert_calculate(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/basic_calculator/playground.py b/leetcode/basic_calculator/playground.py
new file mode 100644
index 0000000..261975f
--- /dev/null
+++ b/leetcode/basic_calculator/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_calculate, run_calculate
+from solution import Solution
+
+# %%
+# Example test case
+s = "(1+(4+5+2)-3)+(6+8)"
+expected = 23
+
+# %%
+result = run_calculate(Solution, s)
+result
+
+# %%
+assert_calculate(result, expected)
diff --git a/leetcode/best_time_to_buy_and_sell_stock/playground.ipynb b/leetcode/best_time_to_buy_and_sell_stock/playground.ipynb
deleted file mode 100644
index 81034bf..0000000
--- a/leetcode/best_time_to_buy_and_sell_stock/playground.ipynb
+++ /dev/null
@@ -1,91 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": 1,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_max_profit, run_max_profit\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "prices = [7, 1, 5, 3, 6, 4]\n",
- "expected = 5"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "id": "run",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "5"
- ]
- },
- "execution_count": 3,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "result = run_max_profit(Solution, prices)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "id": "assert",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "True"
- ]
- },
- "execution_count": 4,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "assert_max_profit(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/best_time_to_buy_and_sell_stock/playground.py b/leetcode/best_time_to_buy_and_sell_stock/playground.py
new file mode 100644
index 0000000..e643984
--- /dev/null
+++ b/leetcode/best_time_to_buy_and_sell_stock/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_max_profit, run_max_profit
+from solution import Solution
+
+# %%
+# Example test case
+prices = [7, 1, 5, 3, 6, 4]
+expected = 5
+
+# %%
+result = run_max_profit(Solution, prices)
+result
+
+# %%
+assert_max_profit(result, expected)
diff --git a/leetcode/binary_search/playground.ipynb b/leetcode/binary_search/playground.ipynb
deleted file mode 100644
index 9c1a608..0000000
--- a/leetcode/binary_search/playground.ipynb
+++ /dev/null
@@ -1,69 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_search, run_search\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "nums = [-1, 0, 3, 5, 9, 12]\n",
- "target = 9\n",
- "expected = 4"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_search(Solution, nums, target)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_search(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/binary_search/playground.py b/leetcode/binary_search/playground.py
new file mode 100644
index 0000000..02af2a1
--- /dev/null
+++ b/leetcode/binary_search/playground.py
@@ -0,0 +1,31 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_search, run_search
+from solution import Solution
+
+# %%
+# Example test case
+nums = [-1, 0, 3, 5, 9, 12]
+target = 9
+expected = 4
+
+# %%
+result = run_search(Solution, nums, target)
+result
+
+# %%
+assert_search(result, expected)
diff --git a/leetcode/binary_tree_level_order_traversal/playground.ipynb b/leetcode/binary_tree_level_order_traversal/playground.ipynb
deleted file mode 100644
index 9c98b39..0000000
--- a/leetcode/binary_tree_level_order_traversal/playground.ipynb
+++ /dev/null
@@ -1,70 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_level_order, run_level_order\n",
- "from solution import Solution\n",
- "\n",
- "from leetcode_py import TreeNode"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "root_list: list[int | None] = [3, 9, 20, None, None, 15, 7]\n",
- "expected = [[3], [9, 20], [15, 7]]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_level_order(Solution, root_list)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_level_order(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/binary_tree_level_order_traversal/playground.py b/leetcode/binary_tree_level_order_traversal/playground.py
new file mode 100644
index 0000000..42a84cd
--- /dev/null
+++ b/leetcode/binary_tree_level_order_traversal/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_level_order, run_level_order
+from solution import Solution
+
+# %%
+# Example test case
+root_list: list[int | None] = [3, 9, 20, None, None, 15, 7]
+expected = [[3], [9, 20], [15, 7]]
+
+# %%
+result = run_level_order(Solution, root_list)
+result
+
+# %%
+assert_level_order(result, expected)
diff --git a/leetcode/binary_tree_right_side_view/playground.ipynb b/leetcode/binary_tree_right_side_view/playground.ipynb
deleted file mode 100644
index 9187c4f..0000000
--- a/leetcode/binary_tree_right_side_view/playground.ipynb
+++ /dev/null
@@ -1,183 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": 1,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_right_side_view, run_right_side_view\n",
- "from solution import Solution\n",
- "\n",
- "from leetcode_py import TreeNode"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "root_list: list[int | None] = [1, 2, 3, None, 5, None, 4]\n",
- "expected = [1, 3, 4]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "id": "6ba11550",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text/plain": [
- "TreeNode([1, 2, 3, None, 5, None, 4])"
- ]
- },
- "execution_count": 3,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "root = TreeNode.from_list(root_list)\n",
- "root"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "id": "run",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "[1, 3, 4]"
- ]
- },
- "execution_count": 4,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "result = run_right_side_view(Solution, root_list)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "id": "assert",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "True"
- ]
- },
- "execution_count": 5,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "assert_right_side_view(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/binary_tree_right_side_view/playground.py b/leetcode/binary_tree_right_side_view/playground.py
new file mode 100644
index 0000000..bbef9b5
--- /dev/null
+++ b/leetcode/binary_tree_right_side_view/playground.py
@@ -0,0 +1,36 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_right_side_view, run_right_side_view
+from solution import Solution
+
+from leetcode_py import TreeNode
+
+# %%
+# Example test case
+root_list: list[int | None] = [1, 2, 3, None, 5, None, 4]
+expected = [1, 3, 4]
+
+# %%
+root = TreeNode.from_list(root_list)
+root
+
+# %%
+result = run_right_side_view(Solution, root_list)
+result
+
+# %%
+assert_right_side_view(result, expected)
diff --git a/leetcode/binary_tree_right_side_view/test_solution.py b/leetcode/binary_tree_right_side_view/test_solution.py
index 2a1ca50..871ecef 100644
--- a/leetcode/binary_tree_right_side_view/test_solution.py
+++ b/leetcode/binary_tree_right_side_view/test_solution.py
@@ -3,7 +3,7 @@
from leetcode_py.test_utils import logged_test
from .helpers import assert_right_side_view, run_right_side_view
-from .solution import Solution
+from .solution import Solution, SolutionBFS, SolutionDFS
class TestBinaryTreeRightSideView:
@@ -11,6 +11,7 @@ def setup_method(self):
self.solution = Solution()
@logged_test
+ @pytest.mark.parametrize("solution_class", [Solution, SolutionDFS, SolutionBFS])
@pytest.mark.parametrize(
"root_list, expected",
[
@@ -30,6 +31,8 @@ def setup_method(self):
([10, 5, 15, None, 6, 12, 20], [10, 15, 20]),
],
)
- def test_right_side_view(self, root_list: list[int | None], expected: list[int]):
- result = run_right_side_view(Solution, root_list)
+ def test_right_side_view(
+ self, solution_class: type, root_list: list[int | None], expected: list[int]
+ ):
+ result = run_right_side_view(solution_class, root_list)
assert_right_side_view(result, expected)
diff --git a/leetcode/climbing_stairs/playground.ipynb b/leetcode/climbing_stairs/playground.ipynb
deleted file mode 100644
index 6fd5d25..0000000
--- a/leetcode/climbing_stairs/playground.ipynb
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_climb_stairs, run_climb_stairs\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "n = 3\n",
- "expected = 3"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_climb_stairs(Solution, n)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_climb_stairs(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/climbing_stairs/playground.py b/leetcode/climbing_stairs/playground.py
new file mode 100644
index 0000000..51601a5
--- /dev/null
+++ b/leetcode/climbing_stairs/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_climb_stairs, run_climb_stairs
+from solution import Solution
+
+# %%
+# Example test case
+n = 3
+expected = 3
+
+# %%
+result = run_climb_stairs(Solution, n)
+result
+
+# %%
+assert_climb_stairs(result, expected)
diff --git a/leetcode/clone_graph/playground.ipynb b/leetcode/clone_graph/playground.ipynb
deleted file mode 100644
index bb2a422..0000000
--- a/leetcode/clone_graph/playground.ipynb
+++ /dev/null
@@ -1,69 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_clone_graph, run_clone_graph\n",
- "from solution import Solution\n",
- "\n",
- "from leetcode_py import GraphNode"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "adj_list = [[2, 4], [1, 3], [2, 4], [1, 3]]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_clone_graph(Solution, adj_list)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_clone_graph(result, adj_list)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/clone_graph/playground.py b/leetcode/clone_graph/playground.py
new file mode 100644
index 0000000..509f051
--- /dev/null
+++ b/leetcode/clone_graph/playground.py
@@ -0,0 +1,29 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_clone_graph, run_clone_graph
+from solution import Solution
+
+# %%
+# Example test case
+adj_list = [[2, 4], [1, 3], [2, 4], [1, 3]]
+
+# %%
+result = run_clone_graph(Solution, adj_list)
+result
+
+# %%
+assert_clone_graph(result, adj_list)
diff --git a/leetcode/coin_change/playground.ipynb b/leetcode/coin_change/playground.ipynb
deleted file mode 100644
index 580d39c..0000000
--- a/leetcode/coin_change/playground.ipynb
+++ /dev/null
@@ -1,69 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_coin_change, run_coin_change\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "coins = [1, 2, 5]\n",
- "amount = 11\n",
- "expected = 3"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_coin_change(Solution, coins, amount)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_coin_change(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/coin_change/playground.py b/leetcode/coin_change/playground.py
new file mode 100644
index 0000000..99c925d
--- /dev/null
+++ b/leetcode/coin_change/playground.py
@@ -0,0 +1,31 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_coin_change, run_coin_change
+from solution import Solution
+
+# %%
+# Example test case
+coins = [1, 2, 5]
+amount = 11
+expected = 3
+
+# %%
+result = run_coin_change(Solution, coins, amount)
+result
+
+# %%
+assert_coin_change(result, expected)
diff --git a/leetcode/combination_sum/playground.ipynb b/leetcode/combination_sum/playground.ipynb
deleted file mode 100644
index ac0711f..0000000
--- a/leetcode/combination_sum/playground.ipynb
+++ /dev/null
@@ -1,69 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_combination_sum, run_combination_sum\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "candidates = [2, 3, 6, 7]\n",
- "target = 7\n",
- "expected = [[2, 2, 3], [7]]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_combination_sum(Solution, candidates, target)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_combination_sum(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/combination_sum/playground.py b/leetcode/combination_sum/playground.py
new file mode 100644
index 0000000..c971550
--- /dev/null
+++ b/leetcode/combination_sum/playground.py
@@ -0,0 +1,31 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_combination_sum, run_combination_sum
+from solution import Solution
+
+# %%
+# Example test case
+candidates = [2, 3, 6, 7]
+target = 7
+expected = [[2, 2, 3], [7]]
+
+# %%
+result = run_combination_sum(Solution, candidates, target)
+result
+
+# %%
+assert_combination_sum(result, expected)
diff --git a/leetcode/container_with_most_water/playground.ipynb b/leetcode/container_with_most_water/playground.ipynb
deleted file mode 100644
index a95df0a..0000000
--- a/leetcode/container_with_most_water/playground.ipynb
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_max_area, run_max_area\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "height = [1, 8, 6, 2, 5, 4, 8, 3, 7]\n",
- "expected = 49"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_max_area(Solution, height)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_max_area(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/container_with_most_water/playground.py b/leetcode/container_with_most_water/playground.py
new file mode 100644
index 0000000..6d9f266
--- /dev/null
+++ b/leetcode/container_with_most_water/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_max_area, run_max_area
+from solution import Solution
+
+# %%
+# Example test case
+height = [1, 8, 6, 2, 5, 4, 8, 3, 7]
+expected = 49
+
+# %%
+result = run_max_area(Solution, height)
+result
+
+# %%
+assert_max_area(result, expected)
diff --git a/leetcode/contains_duplicate/playground.ipynb b/leetcode/contains_duplicate/playground.ipynb
deleted file mode 100644
index f43d0de..0000000
--- a/leetcode/contains_duplicate/playground.ipynb
+++ /dev/null
@@ -1,91 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": 1,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_contains_duplicate, run_contains_duplicate\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "nums = [1, 2, 3, 1]\n",
- "expected = True"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "id": "run",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "True"
- ]
- },
- "execution_count": 3,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "result = run_contains_duplicate(Solution, nums)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "id": "assert",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "True"
- ]
- },
- "execution_count": 4,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "assert_contains_duplicate(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/contains_duplicate/playground.py b/leetcode/contains_duplicate/playground.py
new file mode 100644
index 0000000..84b6064
--- /dev/null
+++ b/leetcode/contains_duplicate/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_contains_duplicate, run_contains_duplicate
+from solution import Solution
+
+# %%
+# Example test case
+nums = [1, 2, 3, 1]
+expected = True
+
+# %%
+result = run_contains_duplicate(Solution, nums)
+result
+
+# %%
+assert_contains_duplicate(result, expected)
diff --git a/leetcode/course_schedule/playground.ipynb b/leetcode/course_schedule/playground.ipynb
deleted file mode 100644
index 2dfeb00..0000000
--- a/leetcode/course_schedule/playground.ipynb
+++ /dev/null
@@ -1,69 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_can_finish, run_can_finish\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "num_courses = 2\n",
- "prerequisites = [[1, 0]]\n",
- "expected = True"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_can_finish(Solution, num_courses, prerequisites)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_can_finish(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/course_schedule/playground.py b/leetcode/course_schedule/playground.py
new file mode 100644
index 0000000..f1e4aef
--- /dev/null
+++ b/leetcode/course_schedule/playground.py
@@ -0,0 +1,31 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_can_finish, run_can_finish
+from solution import Solution
+
+# %%
+# Example test case
+num_courses = 2
+prerequisites = [[1, 0]]
+expected = True
+
+# %%
+result = run_can_finish(Solution, num_courses, prerequisites)
+result
+
+# %%
+assert_can_finish(result, expected)
diff --git a/leetcode/diameter_of_binary_tree/playground.ipynb b/leetcode/diameter_of_binary_tree/playground.ipynb
deleted file mode 100644
index d401bcf..0000000
--- a/leetcode/diameter_of_binary_tree/playground.ipynb
+++ /dev/null
@@ -1,70 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_diameter_of_binary_tree, run_diameter_of_binary_tree\n",
- "from solution import Solution\n",
- "\n",
- "from leetcode_py import TreeNode"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "root_list: list[int | None] = [1, 2, 3, 4, 5]\n",
- "expected = 3"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_diameter_of_binary_tree(Solution, root_list)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_diameter_of_binary_tree(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/diameter_of_binary_tree/playground.py b/leetcode/diameter_of_binary_tree/playground.py
new file mode 100644
index 0000000..afd819a
--- /dev/null
+++ b/leetcode/diameter_of_binary_tree/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_diameter_of_binary_tree, run_diameter_of_binary_tree
+from solution import Solution
+
+# %%
+# Example test case
+root_list: list[int | None] = [1, 2, 3, 4, 5]
+expected = 3
+
+# %%
+result = run_diameter_of_binary_tree(Solution, root_list)
+result
+
+# %%
+assert_diameter_of_binary_tree(result, expected)
diff --git a/leetcode/evaluate_reverse_polish_notation/playground.ipynb b/leetcode/evaluate_reverse_polish_notation/playground.ipynb
deleted file mode 100644
index 01fd8b8..0000000
--- a/leetcode/evaluate_reverse_polish_notation/playground.ipynb
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_eval_rpn, run_eval_rpn\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "tokens = [\"2\", \"1\", \"+\", \"3\", \"*\"]\n",
- "expected = 9"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_eval_rpn(Solution, tokens)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_eval_rpn(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/evaluate_reverse_polish_notation/playground.py b/leetcode/evaluate_reverse_polish_notation/playground.py
new file mode 100644
index 0000000..8ecfa9f
--- /dev/null
+++ b/leetcode/evaluate_reverse_polish_notation/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_eval_rpn, run_eval_rpn
+from solution import Solution
+
+# %%
+# Example test case
+tokens = ["2", "1", "+", "3", "*"]
+expected = 9
+
+# %%
+result = run_eval_rpn(Solution, tokens)
+result
+
+# %%
+assert_eval_rpn(result, expected)
diff --git a/leetcode/find_median_from_data_stream/playground.ipynb b/leetcode/find_median_from_data_stream/playground.ipynb
deleted file mode 100644
index 3a72e85..0000000
--- a/leetcode/find_median_from_data_stream/playground.ipynb
+++ /dev/null
@@ -1,70 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_median_finder, run_median_finder\n",
- "from solution import MedianFinder"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "operations = [\"MedianFinder\", \"addNum\", \"addNum\", \"findMedian\", \"addNum\", \"findMedian\"]\n",
- "inputs = [[], [1], [2], [], [3], []]\n",
- "expected = [None, None, None, 1.5, None, 2.0]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result, mf = run_median_finder(MedianFinder, operations, inputs)\n",
- "print(result)\n",
- "mf"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_median_finder(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/find_median_from_data_stream/playground.py b/leetcode/find_median_from_data_stream/playground.py
new file mode 100644
index 0000000..351a75a
--- /dev/null
+++ b/leetcode/find_median_from_data_stream/playground.py
@@ -0,0 +1,32 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_median_finder, run_median_finder
+from solution import MedianFinder
+
+# %%
+# Example test case
+operations = ["MedianFinder", "addNum", "addNum", "findMedian", "addNum", "findMedian"]
+inputs = [[], [1], [2], [], [3], []]
+expected = [None, None, None, 1.5, None, 2.0]
+
+# %%
+result, mf = run_median_finder(MedianFinder, operations, inputs)
+print(result)
+mf
+
+# %%
+assert_median_finder(result, expected)
diff --git a/leetcode/first_bad_version/playground.ipynb b/leetcode/first_bad_version/playground.ipynb
deleted file mode 100644
index eff1efe..0000000
--- a/leetcode/first_bad_version/playground.ipynb
+++ /dev/null
@@ -1,69 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_first_bad_version, run_first_bad_version\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "n = 5\n",
- "bad = 4\n",
- "expected = 4"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_first_bad_version(Solution, n, bad)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_first_bad_version(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/first_bad_version/playground.py b/leetcode/first_bad_version/playground.py
new file mode 100644
index 0000000..34af8a1
--- /dev/null
+++ b/leetcode/first_bad_version/playground.py
@@ -0,0 +1,31 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_first_bad_version, run_first_bad_version
+from solution import Solution
+
+# %%
+# Example test case
+n = 5
+bad = 4
+expected = 4
+
+# %%
+result = run_first_bad_version(Solution, n, bad)
+result
+
+# %%
+assert_first_bad_version(result, expected)
diff --git a/leetcode/flood_fill/playground.ipynb b/leetcode/flood_fill/playground.ipynb
deleted file mode 100644
index 583f7a1..0000000
--- a/leetcode/flood_fill/playground.ipynb
+++ /dev/null
@@ -1,71 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_flood_fill, run_flood_fill\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "image = [[1, 1, 1], [1, 1, 0], [1, 0, 1]]\n",
- "sr = 1\n",
- "sc = 1\n",
- "color = 2\n",
- "expected = [[2, 2, 2], [2, 2, 0], [2, 0, 1]]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_flood_fill(Solution, image, sr, sc, color)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_flood_fill(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/flood_fill/playground.py b/leetcode/flood_fill/playground.py
new file mode 100644
index 0000000..674fb9c
--- /dev/null
+++ b/leetcode/flood_fill/playground.py
@@ -0,0 +1,33 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_flood_fill, run_flood_fill
+from solution import Solution
+
+# %%
+# Example test case
+image = [[1, 1, 1], [1, 1, 0], [1, 0, 1]]
+sr = 1
+sc = 1
+color = 2
+expected = [[2, 2, 2], [2, 2, 0], [2, 0, 1]]
+
+# %%
+result = run_flood_fill(Solution, image, sr, sc, color)
+result
+
+# %%
+assert_flood_fill(result, expected)
diff --git a/leetcode/implement_queue_using_stacks/playground.ipynb b/leetcode/implement_queue_using_stacks/playground.ipynb
deleted file mode 100644
index 735a590..0000000
--- a/leetcode/implement_queue_using_stacks/playground.ipynb
+++ /dev/null
@@ -1,70 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_my_queue, run_my_queue\n",
- "from solution import MyQueue"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "operations = [\"MyQueue\", \"push\", \"push\", \"peek\", \"pop\", \"empty\"]\n",
- "inputs = [[], [1], [2], [], [], []]\n",
- "expected = [None, None, None, 1, 1, False]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result, queue = run_my_queue(MyQueue, operations, inputs)\n",
- "print(result)\n",
- "queue"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_my_queue(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/implement_queue_using_stacks/playground.py b/leetcode/implement_queue_using_stacks/playground.py
new file mode 100644
index 0000000..834b6b8
--- /dev/null
+++ b/leetcode/implement_queue_using_stacks/playground.py
@@ -0,0 +1,32 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_my_queue, run_my_queue
+from solution import MyQueue
+
+# %%
+# Example test case
+operations = ["MyQueue", "push", "push", "peek", "pop", "empty"]
+inputs = [[], [1], [2], [], [], []]
+expected = [None, None, None, 1, 1, False]
+
+# %%
+result, queue = run_my_queue(MyQueue, operations, inputs)
+print(result)
+queue
+
+# %%
+assert_my_queue(result, expected)
diff --git a/leetcode/implement_trie_prefix_tree/playground.ipynb b/leetcode/implement_trie_prefix_tree/playground.ipynb
deleted file mode 100644
index c509af4..0000000
--- a/leetcode/implement_trie_prefix_tree/playground.ipynb
+++ /dev/null
@@ -1,204 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": 1,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_trie_operations, run_trie_operations\n",
- "from solution import Trie"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "operations = [\"Trie\", \"insert\", \"search\", \"search\", \"starts_with\", \"insert\", \"search\"]\n",
- "inputs = [[], [\"apple\"], [\"apple\"], [\"app\"], [\"app\"], [\"app\"], [\"app\"]]\n",
- "expected = [None, None, True, False, True, None, True]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "id": "run",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[None, None, True, False, True, None, True]\n"
- ]
- },
- {
- "data": {
- "text/html": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text/plain": [
- ""
- ]
- },
- "execution_count": 3,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "result, trie = run_trie_operations(Trie, operations, inputs)\n",
- "print(result)\n",
- "trie"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "id": "assert",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "True"
- ]
- },
- "execution_count": 4,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "assert_trie_operations(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/implement_trie_prefix_tree/playground.py b/leetcode/implement_trie_prefix_tree/playground.py
new file mode 100644
index 0000000..815d6f6
--- /dev/null
+++ b/leetcode/implement_trie_prefix_tree/playground.py
@@ -0,0 +1,32 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_trie_operations, run_trie_operations
+from solution import Trie
+
+# %%
+# Example test case
+operations = ["Trie", "insert", "search", "search", "starts_with", "insert", "search"]
+inputs = [[], ["apple"], ["apple"], ["app"], ["app"], ["app"], ["app"]]
+expected = [None, None, True, False, True, None, True]
+
+# %%
+result, trie = run_trie_operations(Trie, operations, inputs)
+print(result)
+trie
+
+# %%
+assert_trie_operations(result, expected)
diff --git a/leetcode/insert_interval/playground.ipynb b/leetcode/insert_interval/playground.ipynb
deleted file mode 100644
index 0e8d78f..0000000
--- a/leetcode/insert_interval/playground.ipynb
+++ /dev/null
@@ -1,69 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_insert, run_insert\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "intervals = [[1, 3], [6, 9]]\n",
- "new_interval = [2, 5]\n",
- "expected = [[1, 5], [6, 9]]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_insert(Solution, intervals, new_interval)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_insert(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/insert_interval/playground.py b/leetcode/insert_interval/playground.py
new file mode 100644
index 0000000..d895d17
--- /dev/null
+++ b/leetcode/insert_interval/playground.py
@@ -0,0 +1,31 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_insert, run_insert
+from solution import Solution
+
+# %%
+# Example test case
+intervals = [[1, 3], [6, 9]]
+new_interval = [2, 5]
+expected = [[1, 5], [6, 9]]
+
+# %%
+result = run_insert(Solution, intervals, new_interval)
+result
+
+# %%
+assert_insert(result, expected)
diff --git a/leetcode/invert_binary_tree/playground.ipynb b/leetcode/invert_binary_tree/playground.ipynb
deleted file mode 100644
index ba35a6c..0000000
--- a/leetcode/invert_binary_tree/playground.ipynb
+++ /dev/null
@@ -1,185 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": 5,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_invert_tree, run_invert_tree\n",
- "from solution import Solution\n",
- "\n",
- "from leetcode_py import TreeNode"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 6,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "root_list: list[int | None] = [4, 2, 7, 1, 3, 6, 9]\n",
- "expected_list: list[int | None] = [4, 7, 2, 9, 6, 3, 1]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 7,
- "id": "run",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text/plain": [
- "TreeNode([4, 7, 2, 9, 6, 3, 1])"
- ]
- },
- "execution_count": 7,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "result = run_invert_tree(Solution, root_list)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "id": "assert",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "True"
- ]
- },
- "execution_count": 4,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "assert_invert_tree(result, expected_list)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/invert_binary_tree/playground.py b/leetcode/invert_binary_tree/playground.py
new file mode 100644
index 0000000..2805ae6
--- /dev/null
+++ b/leetcode/invert_binary_tree/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_invert_tree, run_invert_tree
+from solution import Solution
+
+# %%
+# Example test case
+root_list: list[int | None] = [4, 2, 7, 1, 3, 6, 9]
+expected_list: list[int | None] = [4, 7, 2, 9, 6, 3, 1]
+
+# %%
+result = run_invert_tree(Solution, root_list)
+result
+
+# %%
+assert_invert_tree(result, expected_list)
diff --git a/leetcode/invert_binary_tree/test_solution.py b/leetcode/invert_binary_tree/test_solution.py
index f20e784..9e40afb 100644
--- a/leetcode/invert_binary_tree/test_solution.py
+++ b/leetcode/invert_binary_tree/test_solution.py
@@ -3,7 +3,7 @@
from leetcode_py.test_utils import logged_test
from .helpers import assert_invert_tree, run_invert_tree
-from .solution import Solution
+from .solution import Solution, SolutionBFS, SolutionDFS
class TestInvertBinaryTree:
@@ -11,6 +11,7 @@ def setup_method(self):
self.solution = Solution()
@logged_test
+ @pytest.mark.parametrize("solution_class", [Solution, SolutionDFS, SolutionBFS])
@pytest.mark.parametrize(
"root_list, expected_list",
[
@@ -31,6 +32,8 @@ def setup_method(self):
([1, 2, 3, None, 4, None, 5], [1, 3, 2, 5, None, 4]),
],
)
- def test_invert_tree(self, root_list: list[int | None], expected_list: list[int | None]):
- result = run_invert_tree(Solution, root_list)
+ def test_invert_tree(
+ self, solution_class: type, root_list: list[int | None], expected_list: list[int | None]
+ ):
+ result = run_invert_tree(solution_class, root_list)
assert_invert_tree(result, expected_list)
diff --git a/leetcode/k_closest_points_to_origin/playground.ipynb b/leetcode/k_closest_points_to_origin/playground.ipynb
deleted file mode 100644
index fce66ec..0000000
--- a/leetcode/k_closest_points_to_origin/playground.ipynb
+++ /dev/null
@@ -1,69 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_k_closest, run_k_closest\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "points = [[1, 3], [-2, 2]]\n",
- "k = 1\n",
- "expected = [[-2, 2]]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_k_closest(Solution, points, k)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_k_closest(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/k_closest_points_to_origin/playground.py b/leetcode/k_closest_points_to_origin/playground.py
new file mode 100644
index 0000000..5efc6f0
--- /dev/null
+++ b/leetcode/k_closest_points_to_origin/playground.py
@@ -0,0 +1,31 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_k_closest, run_k_closest
+from solution import Solution
+
+# %%
+# Example test case
+points = [[1, 3], [-2, 2]]
+k = 1
+expected = [[-2, 2]]
+
+# %%
+result = run_k_closest(Solution, points, k)
+result
+
+# %%
+assert_k_closest(result, expected)
diff --git a/leetcode/kth_smallest_element_in_a_bst/playground.ipynb b/leetcode/kth_smallest_element_in_a_bst/playground.ipynb
deleted file mode 100644
index b65acaf..0000000
--- a/leetcode/kth_smallest_element_in_a_bst/playground.ipynb
+++ /dev/null
@@ -1,71 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_kth_smallest, run_kth_smallest\n",
- "from solution import Solution\n",
- "\n",
- "from leetcode_py import TreeNode"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "root_list = [3, 1, 4, None, 2]\n",
- "k = 1\n",
- "expected = 1"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_kth_smallest(Solution, root_list, k)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_kth_smallest(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/kth_smallest_element_in_a_bst/playground.py b/leetcode/kth_smallest_element_in_a_bst/playground.py
new file mode 100644
index 0000000..6cff3f7
--- /dev/null
+++ b/leetcode/kth_smallest_element_in_a_bst/playground.py
@@ -0,0 +1,31 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_kth_smallest, run_kth_smallest
+from solution import Solution
+
+# %%
+# Example test case
+root_list = [3, 1, 4, None, 2]
+k = 1
+expected = 1
+
+# %%
+result = run_kth_smallest(Solution, root_list, k)
+result
+
+# %%
+assert_kth_smallest(result, expected)
diff --git a/leetcode/largest_rectangle_in_histogram/playground.ipynb b/leetcode/largest_rectangle_in_histogram/playground.ipynb
deleted file mode 100644
index 8470983..0000000
--- a/leetcode/largest_rectangle_in_histogram/playground.ipynb
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_largest_rectangle_area, run_largest_rectangle_area\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "heights = [2, 1, 5, 6, 2, 3]\n",
- "expected = 10"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_largest_rectangle_area(Solution, heights)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_largest_rectangle_area(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/largest_rectangle_in_histogram/playground.py b/leetcode/largest_rectangle_in_histogram/playground.py
new file mode 100644
index 0000000..16761db
--- /dev/null
+++ b/leetcode/largest_rectangle_in_histogram/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_largest_rectangle_area, run_largest_rectangle_area
+from solution import Solution
+
+# %%
+# Example test case
+heights = [2, 1, 5, 6, 2, 3]
+expected = 10
+
+# %%
+result = run_largest_rectangle_area(Solution, heights)
+result
+
+# %%
+assert_largest_rectangle_area(result, expected)
diff --git a/leetcode/linked_list_cycle/playground.ipynb b/leetcode/linked_list_cycle/playground.ipynb
deleted file mode 100644
index f4adc95..0000000
--- a/leetcode/linked_list_cycle/playground.ipynb
+++ /dev/null
@@ -1,177 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": 1,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_has_cycle, create_cycle_list, run_has_cycle\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "values = [3, 2, 0, -4]\n",
- "pos = 1\n",
- "expected = True"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "id": "66f97343",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
- ],
- "text/plain": [
- "ListNode([3, 2, 0, -4])"
- ]
- },
- "execution_count": 5,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "head = create_cycle_list(values, pos)\n",
- "head"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "id": "run",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "True"
- ]
- },
- "execution_count": 3,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "result = run_has_cycle(Solution, values, pos)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "id": "assert",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "True"
- ]
- },
- "execution_count": 4,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "assert_has_cycle(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/linked_list_cycle/playground.py b/leetcode/linked_list_cycle/playground.py
new file mode 100644
index 0000000..b19e7f6
--- /dev/null
+++ b/leetcode/linked_list_cycle/playground.py
@@ -0,0 +1,35 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_has_cycle, create_cycle_list, run_has_cycle
+from solution import Solution
+
+# %%
+# Example test case
+values = [3, 2, 0, -4]
+pos = 1
+expected = True
+
+# %%
+head = create_cycle_list(values, pos)
+head
+
+# %%
+result = run_has_cycle(Solution, values, pos)
+result
+
+# %%
+assert_has_cycle(result, expected)
diff --git a/leetcode/longest_palindrome/playground.ipynb b/leetcode/longest_palindrome/playground.ipynb
deleted file mode 100644
index 31ff59e..0000000
--- a/leetcode/longest_palindrome/playground.ipynb
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_longest_palindrome, run_longest_palindrome\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "s = \"abccccdd\"\n",
- "expected = 7"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_longest_palindrome(Solution, s)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_longest_palindrome(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/longest_palindrome/playground.py b/leetcode/longest_palindrome/playground.py
new file mode 100644
index 0000000..d84ed13
--- /dev/null
+++ b/leetcode/longest_palindrome/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_longest_palindrome, run_longest_palindrome
+from solution import Solution
+
+# %%
+# Example test case
+s = "abccccdd"
+expected = 7
+
+# %%
+result = run_longest_palindrome(Solution, s)
+result
+
+# %%
+assert_longest_palindrome(result, expected)
diff --git a/leetcode/longest_palindromic_substring/playground.ipynb b/leetcode/longest_palindromic_substring/playground.ipynb
deleted file mode 100644
index be01046..0000000
--- a/leetcode/longest_palindromic_substring/playground.ipynb
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_longest_palindrome, run_longest_palindrome\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "s = \"babad\"\n",
- "expected = {\"bab\", \"aba\"}"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_longest_palindrome(Solution, s)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_longest_palindrome(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/longest_palindromic_substring/playground.py b/leetcode/longest_palindromic_substring/playground.py
new file mode 100644
index 0000000..ee1069b
--- /dev/null
+++ b/leetcode/longest_palindromic_substring/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_longest_palindrome, run_longest_palindrome
+from solution import Solution
+
+# %%
+# Example test case
+s = "babad"
+expected = {"bab", "aba"}
+
+# %%
+result = run_longest_palindrome(Solution, s)
+result
+
+# %%
+assert_longest_palindrome(result, expected)
diff --git a/leetcode/longest_palindromic_substring/test_solution.py b/leetcode/longest_palindromic_substring/test_solution.py
index 832e8fa..0cd1994 100644
--- a/leetcode/longest_palindromic_substring/test_solution.py
+++ b/leetcode/longest_palindromic_substring/test_solution.py
@@ -3,7 +3,7 @@
from leetcode_py.test_utils import logged_test
from .helpers import assert_longest_palindrome, run_longest_palindrome
-from .solution import Solution
+from .solution import Solution, SolutionManacher
class TestLongestPalindromicSubstring:
@@ -11,6 +11,7 @@ def setup_method(self):
self.solution = Solution()
@logged_test
+ @pytest.mark.parametrize("solution_class", [Solution, SolutionManacher])
@pytest.mark.parametrize(
"s, expected",
[
@@ -28,6 +29,6 @@ def setup_method(self):
("abcba", {"abcba"}),
],
)
- def test_longest_palindrome(self, s: str, expected: set[str]):
- result = run_longest_palindrome(Solution, s)
+ def test_longest_palindrome(self, solution_class: type, s: str, expected: set[str]):
+ result = run_longest_palindrome(solution_class, s)
assert_longest_palindrome(result, expected)
diff --git a/leetcode/longest_substring_without_repeating_characters/playground.ipynb b/leetcode/longest_substring_without_repeating_characters/playground.ipynb
deleted file mode 100644
index 0c23372..0000000
--- a/leetcode/longest_substring_without_repeating_characters/playground.ipynb
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_length_of_longest_substring, run_length_of_longest_substring\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "s = \"abcabcbb\"\n",
- "expected = 3"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_length_of_longest_substring(Solution, s)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_length_of_longest_substring(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/longest_substring_without_repeating_characters/playground.py b/leetcode/longest_substring_without_repeating_characters/playground.py
new file mode 100644
index 0000000..e2b9bf4
--- /dev/null
+++ b/leetcode/longest_substring_without_repeating_characters/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_length_of_longest_substring, run_length_of_longest_substring
+from solution import Solution
+
+# %%
+# Example test case
+s = "abcabcbb"
+expected = 3
+
+# %%
+result = run_length_of_longest_substring(Solution, s)
+result
+
+# %%
+assert_length_of_longest_substring(result, expected)
diff --git a/leetcode/lowest_common_ancestor_of_a_binary_search_tree/playground.ipynb b/leetcode/lowest_common_ancestor_of_a_binary_search_tree/playground.ipynb
deleted file mode 100644
index 6f5c85e..0000000
--- a/leetcode/lowest_common_ancestor_of_a_binary_search_tree/playground.ipynb
+++ /dev/null
@@ -1,72 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_lowest_common_ancestor, run_lowest_common_ancestor\n",
- "from solution import Solution\n",
- "\n",
- "from leetcode_py import TreeNode"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "root_list = [6, 2, 8, 0, 4, 7, 9, None, None, 3, 5]\n",
- "p_val = 2\n",
- "q_val = 8\n",
- "expected_val = 6"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_lowest_common_ancestor(Solution, root_list, p_val, q_val)\n",
- "result.val if result else None"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_lowest_common_ancestor(result, expected_val)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/lowest_common_ancestor_of_a_binary_search_tree/playground.py b/leetcode/lowest_common_ancestor_of_a_binary_search_tree/playground.py
new file mode 100644
index 0000000..1e7eb79
--- /dev/null
+++ b/leetcode/lowest_common_ancestor_of_a_binary_search_tree/playground.py
@@ -0,0 +1,32 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_lowest_common_ancestor, run_lowest_common_ancestor
+from solution import Solution
+
+# %%
+# Example test case
+root_list = [6, 2, 8, 0, 4, 7, 9, None, None, 3, 5]
+p_val = 2
+q_val = 8
+expected_val = 6
+
+# %%
+result = run_lowest_common_ancestor(Solution, root_list, p_val, q_val)
+result.val if result else None
+
+# %%
+assert_lowest_common_ancestor(result, expected_val)
diff --git a/leetcode/lowest_common_ancestor_of_a_binary_tree/playground.ipynb b/leetcode/lowest_common_ancestor_of_a_binary_tree/playground.ipynb
deleted file mode 100644
index 0251030..0000000
--- a/leetcode/lowest_common_ancestor_of_a_binary_tree/playground.ipynb
+++ /dev/null
@@ -1,72 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_lowest_common_ancestor, run_lowest_common_ancestor\n",
- "from solution import Solution\n",
- "\n",
- "from leetcode_py import TreeNode"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "root_list = [3, 5, 1, 6, 2, 0, 8, None, None, 7, 4]\n",
- "p_val = 5\n",
- "q_val = 1\n",
- "expected_val = 3"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_lowest_common_ancestor(Solution, root_list, p_val, q_val)\n",
- "result.val"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_lowest_common_ancestor(result, expected_val)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/lowest_common_ancestor_of_a_binary_tree/playground.py b/leetcode/lowest_common_ancestor_of_a_binary_tree/playground.py
new file mode 100644
index 0000000..39884fc
--- /dev/null
+++ b/leetcode/lowest_common_ancestor_of_a_binary_tree/playground.py
@@ -0,0 +1,32 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_lowest_common_ancestor, run_lowest_common_ancestor
+from solution import Solution
+
+# %%
+# Example test case
+root_list = [3, 5, 1, 6, 2, 0, 8, None, None, 7, 4]
+p_val = 5
+q_val = 1
+expected_val = 3
+
+# %%
+result = run_lowest_common_ancestor(Solution, root_list, p_val, q_val)
+result.val
+
+# %%
+assert_lowest_common_ancestor(result, expected_val)
diff --git a/leetcode/lru_cache/playground.ipynb b/leetcode/lru_cache/playground.ipynb
deleted file mode 100644
index 687c6f1..0000000
--- a/leetcode/lru_cache/playground.ipynb
+++ /dev/null
@@ -1,100 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": 1,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_lru_cache, run_lru_cache\n",
- "from solution import LRUCache"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "operations = [\"LRUCache\", \"put\", \"put\", \"get\", \"put\", \"get\", \"put\", \"get\", \"get\", \"get\"]\n",
- "inputs = [[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]\n",
- "expected = [None, None, None, 1, None, -1, None, -1, 3, 4]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "id": "run",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[None, None, None, 1, None, -1, None, -1, 3, 4]\n"
- ]
- },
- {
- "data": {
- "text/plain": [
- "OrderedDict([(3, 3), (4, 4)])"
- ]
- },
- "execution_count": 5,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "result, cache = run_lru_cache(LRUCache, operations, inputs)\n",
- "print(result)\n",
- "cache.cache"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "id": "assert",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "True"
- ]
- },
- "execution_count": 4,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "assert_lru_cache(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/lru_cache/playground.py b/leetcode/lru_cache/playground.py
new file mode 100644
index 0000000..6269d30
--- /dev/null
+++ b/leetcode/lru_cache/playground.py
@@ -0,0 +1,32 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_lru_cache, run_lru_cache
+from solution import LRUCache
+
+# %%
+# Example test case
+operations = ["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
+inputs = [[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
+expected = [None, None, None, 1, None, -1, None, -1, 3, 4]
+
+# %%
+result, cache = run_lru_cache(LRUCache, operations, inputs)
+print(result)
+cache.cache
+
+# %%
+assert_lru_cache(result, expected)
diff --git a/leetcode/lru_cache/test_solution.py b/leetcode/lru_cache/test_solution.py
index 0fcaa3d..db70723 100644
--- a/leetcode/lru_cache/test_solution.py
+++ b/leetcode/lru_cache/test_solution.py
@@ -3,12 +3,13 @@
from leetcode_py.test_utils import logged_test
from .helpers import assert_lru_cache, run_lru_cache
-from .solution import LRUCache
+from .solution import LRUCache, LRUCacheWithDoublyList
class TestLRUCache:
@logged_test
+ @pytest.mark.parametrize("solution_class", [LRUCache, LRUCacheWithDoublyList])
@pytest.mark.parametrize(
"operations, inputs, expected",
[
@@ -66,6 +67,12 @@ class TestLRUCache:
),
],
)
- def test_lru_cache(self, operations: list[str], inputs: list[list[int]], expected: list[int | None]):
- result, _ = run_lru_cache(LRUCache, operations, inputs)
+ def test_lru_cache(
+ self,
+ solution_class: type,
+ operations: list[str],
+ inputs: list[list[int]],
+ expected: list[int | None],
+ ):
+ result, _ = run_lru_cache(solution_class, operations, inputs)
assert_lru_cache(result, expected)
diff --git a/leetcode/majority_element/playground.ipynb b/leetcode/majority_element/playground.ipynb
deleted file mode 100644
index 969279e..0000000
--- a/leetcode/majority_element/playground.ipynb
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_majority_element, run_majority_element\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "nums = [3, 2, 3]\n",
- "expected = 3"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_majority_element(Solution, nums)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_majority_element(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/majority_element/playground.py b/leetcode/majority_element/playground.py
new file mode 100644
index 0000000..ac2bcd3
--- /dev/null
+++ b/leetcode/majority_element/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_majority_element, run_majority_element
+from solution import Solution
+
+# %%
+# Example test case
+nums = [3, 2, 3]
+expected = 3
+
+# %%
+result = run_majority_element(Solution, nums)
+result
+
+# %%
+assert_majority_element(result, expected)
diff --git a/leetcode/maximum_depth_of_binary_tree/playground.ipynb b/leetcode/maximum_depth_of_binary_tree/playground.ipynb
deleted file mode 100644
index 53406b7..0000000
--- a/leetcode/maximum_depth_of_binary_tree/playground.ipynb
+++ /dev/null
@@ -1,70 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_max_depth, run_max_depth\n",
- "from solution import Solution\n",
- "\n",
- "from leetcode_py import TreeNode"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "root_list = [3, 9, 20, None, None, 15, 7]\n",
- "expected = 3"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_max_depth(Solution, root_list)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_max_depth(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/maximum_depth_of_binary_tree/playground.py b/leetcode/maximum_depth_of_binary_tree/playground.py
new file mode 100644
index 0000000..e2f6ebf
--- /dev/null
+++ b/leetcode/maximum_depth_of_binary_tree/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_max_depth, run_max_depth
+from solution import Solution
+
+# %%
+# Example test case
+root_list = [3, 9, 20, None, None, 15, 7]
+expected = 3
+
+# %%
+result = run_max_depth(Solution, root_list)
+result
+
+# %%
+assert_max_depth(result, expected)
diff --git a/leetcode/maximum_profit_in_job_scheduling/playground.ipynb b/leetcode/maximum_profit_in_job_scheduling/playground.ipynb
deleted file mode 100644
index cf2e659..0000000
--- a/leetcode/maximum_profit_in_job_scheduling/playground.ipynb
+++ /dev/null
@@ -1,70 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_job_scheduling, run_job_scheduling\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "start_time = [1, 2, 3, 3]\n",
- "end_time = [3, 4, 5, 6]\n",
- "profit = [50, 10, 40, 70]\n",
- "expected = 120"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_job_scheduling(Solution, start_time, end_time, profit)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_job_scheduling(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/maximum_profit_in_job_scheduling/playground.py b/leetcode/maximum_profit_in_job_scheduling/playground.py
new file mode 100644
index 0000000..777d927
--- /dev/null
+++ b/leetcode/maximum_profit_in_job_scheduling/playground.py
@@ -0,0 +1,32 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_job_scheduling, run_job_scheduling
+from solution import Solution
+
+# %%
+# Example test case
+start_time = [1, 2, 3, 3]
+end_time = [3, 4, 5, 6]
+profit = [50, 10, 40, 70]
+expected = 120
+
+# %%
+result = run_job_scheduling(Solution, start_time, end_time, profit)
+result
+
+# %%
+assert_job_scheduling(result, expected)
diff --git a/leetcode/maximum_subarray/playground.ipynb b/leetcode/maximum_subarray/playground.ipynb
deleted file mode 100644
index bd4f64e..0000000
--- a/leetcode/maximum_subarray/playground.ipynb
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_max_sub_array, run_max_sub_array\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4]\n",
- "expected = 6"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_max_sub_array(Solution, nums)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_max_sub_array(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/maximum_subarray/playground.py b/leetcode/maximum_subarray/playground.py
new file mode 100644
index 0000000..4c514a9
--- /dev/null
+++ b/leetcode/maximum_subarray/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_max_sub_array, run_max_sub_array
+from solution import Solution
+
+# %%
+# Example test case
+nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
+expected = 6
+
+# %%
+result = run_max_sub_array(Solution, nums)
+result
+
+# %%
+assert_max_sub_array(result, expected)
diff --git a/leetcode/merge_intervals/playground.ipynb b/leetcode/merge_intervals/playground.ipynb
deleted file mode 100644
index f5c7c1e..0000000
--- a/leetcode/merge_intervals/playground.ipynb
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_merge, run_merge\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "intervals = [[1, 3], [2, 6], [8, 10], [15, 18]]\n",
- "expected = [[1, 6], [8, 10], [15, 18]]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_merge(Solution, intervals)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_merge(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/merge_intervals/playground.py b/leetcode/merge_intervals/playground.py
new file mode 100644
index 0000000..0c3c6b0
--- /dev/null
+++ b/leetcode/merge_intervals/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_merge, run_merge
+from solution import Solution
+
+# %%
+# Example test case
+intervals = [[1, 3], [2, 6], [8, 10], [15, 18]]
+expected = [[1, 6], [8, 10], [15, 18]]
+
+# %%
+result = run_merge(Solution, intervals)
+result
+
+# %%
+assert_merge(result, expected)
diff --git a/leetcode/merge_k_sorted_lists/playground.ipynb b/leetcode/merge_k_sorted_lists/playground.ipynb
deleted file mode 100644
index 44dff96..0000000
--- a/leetcode/merge_k_sorted_lists/playground.ipynb
+++ /dev/null
@@ -1,70 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_merge_k_lists, run_merge_k_lists\n",
- "from solution import Solution\n",
- "\n",
- "from leetcode_py import ListNode"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "lists_data = [[1, 4, 5], [1, 3, 4], [2, 6]]\n",
- "expected_data = [1, 1, 2, 3, 4, 4, 5, 6]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_merge_k_lists(Solution, lists_data)\n",
- "ListNode[int].to_list(result) if result else []"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_merge_k_lists(result, expected_data)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/merge_k_sorted_lists/playground.py b/leetcode/merge_k_sorted_lists/playground.py
new file mode 100644
index 0000000..f30a2ad
--- /dev/null
+++ b/leetcode/merge_k_sorted_lists/playground.py
@@ -0,0 +1,32 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_merge_k_lists, run_merge_k_lists
+from solution import Solution
+
+from leetcode_py import ListNode
+
+# %%
+# Example test case
+lists_data = [[1, 4, 5], [1, 3, 4], [2, 6]]
+expected_data = [1, 1, 2, 3, 4, 4, 5, 6]
+
+# %%
+result = run_merge_k_lists(Solution, lists_data)
+ListNode[int].to_list(result) if result else []
+
+# %%
+assert_merge_k_lists(result, expected_data)
diff --git a/leetcode/merge_two_sorted_lists/playground.ipynb b/leetcode/merge_two_sorted_lists/playground.ipynb
deleted file mode 100644
index 0ec2f71..0000000
--- a/leetcode/merge_two_sorted_lists/playground.ipynb
+++ /dev/null
@@ -1,71 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_merge_two_lists, run_merge_two_lists\n",
- "from solution import Solution\n",
- "\n",
- "from leetcode_py import ListNode"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "list1_vals = [1, 2, 4]\n",
- "list2_vals = [1, 3, 4]\n",
- "expected_vals = [1, 1, 2, 3, 4, 4]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_merge_two_lists(Solution, list1_vals, list2_vals)\n",
- "ListNode[int].to_list(result) if result else []"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_merge_two_lists(result, expected_vals)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/merge_two_sorted_lists/playground.py b/leetcode/merge_two_sorted_lists/playground.py
new file mode 100644
index 0000000..2d47603
--- /dev/null
+++ b/leetcode/merge_two_sorted_lists/playground.py
@@ -0,0 +1,33 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_merge_two_lists, run_merge_two_lists
+from solution import Solution
+
+from leetcode_py import ListNode
+
+# %%
+# Example test case
+list1_vals = [1, 2, 4]
+list2_vals = [1, 3, 4]
+expected_vals = [1, 1, 2, 3, 4, 4]
+
+# %%
+result = run_merge_two_lists(Solution, list1_vals, list2_vals)
+ListNode[int].to_list(result) if result else []
+
+# %%
+assert_merge_two_lists(result, expected_vals)
diff --git a/leetcode/middle_of_the_linked_list/playground.ipynb b/leetcode/middle_of_the_linked_list/playground.ipynb
deleted file mode 100644
index d078f51..0000000
--- a/leetcode/middle_of_the_linked_list/playground.ipynb
+++ /dev/null
@@ -1,70 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_middle_node, run_middle_node\n",
- "from solution import Solution\n",
- "\n",
- "from leetcode_py import ListNode"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "head_list = [1, 2, 3, 4, 5]\n",
- "expected_list = [3, 4, 5]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_middle_node(Solution, head_list)\n",
- "ListNode[int].to_list(result) if result else []"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_middle_node(result, expected_list)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/middle_of_the_linked_list/playground.py b/leetcode/middle_of_the_linked_list/playground.py
new file mode 100644
index 0000000..a81e5a1
--- /dev/null
+++ b/leetcode/middle_of_the_linked_list/playground.py
@@ -0,0 +1,32 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_middle_node, run_middle_node
+from solution import Solution
+
+from leetcode_py import ListNode
+
+# %%
+# Example test case
+head_list = [1, 2, 3, 4, 5]
+expected_list = [3, 4, 5]
+
+# %%
+result = run_middle_node(Solution, head_list)
+ListNode[int].to_list(result) if result else []
+
+# %%
+assert_middle_node(result, expected_list)
diff --git a/leetcode/min_stack/playground.ipynb b/leetcode/min_stack/playground.ipynb
deleted file mode 100644
index 0d24cc7..0000000
--- a/leetcode/min_stack/playground.ipynb
+++ /dev/null
@@ -1,69 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_min_stack_operations, run_min_stack_operations\n",
- "from solution import MinStack"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "operations = [\"MinStack\", \"push\", \"push\", \"push\", \"getMin\", \"pop\", \"top\", \"getMin\"]\n",
- "inputs = [[], [-2], [0], [-3], [], [], [], []]\n",
- "expected = [None, None, None, None, -3, None, 0, -2]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_min_stack_operations(MinStack, operations, inputs)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_min_stack_operations(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/min_stack/playground.py b/leetcode/min_stack/playground.py
new file mode 100644
index 0000000..a331ae1
--- /dev/null
+++ b/leetcode/min_stack/playground.py
@@ -0,0 +1,31 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_min_stack_operations, run_min_stack_operations
+from solution import MinStack
+
+# %%
+# Example test case
+operations = ["MinStack", "push", "push", "push", "getMin", "pop", "top", "getMin"]
+inputs = [[], [-2], [0], [-3], [], [], [], []]
+expected = [None, None, None, None, -3, None, 0, -2]
+
+# %%
+result = run_min_stack_operations(MinStack, operations, inputs)
+result
+
+# %%
+assert_min_stack_operations(result, expected)
diff --git a/leetcode/minimum_height_trees/playground.ipynb b/leetcode/minimum_height_trees/playground.ipynb
deleted file mode 100644
index 8cf7734..0000000
--- a/leetcode/minimum_height_trees/playground.ipynb
+++ /dev/null
@@ -1,69 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_find_min_height_trees, run_find_min_height_trees\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "n = 4\n",
- "edges = [[1, 0], [1, 2], [1, 3]]\n",
- "expected = [1]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_find_min_height_trees(Solution, n, edges)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_find_min_height_trees(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/minimum_height_trees/playground.py b/leetcode/minimum_height_trees/playground.py
new file mode 100644
index 0000000..32fdfbd
--- /dev/null
+++ b/leetcode/minimum_height_trees/playground.py
@@ -0,0 +1,31 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_find_min_height_trees, run_find_min_height_trees
+from solution import Solution
+
+# %%
+# Example test case
+n = 4
+edges = [[1, 0], [1, 2], [1, 3]]
+expected = [1]
+
+# %%
+result = run_find_min_height_trees(Solution, n, edges)
+result
+
+# %%
+assert_find_min_height_trees(result, expected)
diff --git a/leetcode/minimum_window_substring/playground.ipynb b/leetcode/minimum_window_substring/playground.ipynb
deleted file mode 100644
index c35e737..0000000
--- a/leetcode/minimum_window_substring/playground.ipynb
+++ /dev/null
@@ -1,69 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_min_window, run_min_window\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "s = \"ADOBECODEBANC\"\n",
- "t = \"ABC\"\n",
- "expected = \"BANC\""
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_min_window(Solution, s, t)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_min_window(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/minimum_window_substring/playground.py b/leetcode/minimum_window_substring/playground.py
new file mode 100644
index 0000000..89b19b0
--- /dev/null
+++ b/leetcode/minimum_window_substring/playground.py
@@ -0,0 +1,31 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_min_window, run_min_window
+from solution import Solution
+
+# %%
+# Example test case
+s = "ADOBECODEBANC"
+t = "ABC"
+expected = "BANC"
+
+# %%
+result = run_min_window(Solution, s, t)
+result
+
+# %%
+assert_min_window(result, expected)
diff --git a/leetcode/number_of_islands/playground.ipynb b/leetcode/number_of_islands/playground.ipynb
deleted file mode 100644
index 57ebc3f..0000000
--- a/leetcode/number_of_islands/playground.ipynb
+++ /dev/null
@@ -1,73 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_num_islands, run_num_islands\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "grid = [\n",
- " [\"1\", \"1\", \"1\", \"1\", \"0\"],\n",
- " [\"1\", \"1\", \"0\", \"1\", \"0\"],\n",
- " [\"1\", \"1\", \"0\", \"0\", \"0\"],\n",
- " [\"0\", \"0\", \"0\", \"0\", \"0\"],\n",
- "]\n",
- "expected = 1"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_num_islands(Solution, grid)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_num_islands(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/number_of_islands/playground.py b/leetcode/number_of_islands/playground.py
new file mode 100644
index 0000000..8f12ebb
--- /dev/null
+++ b/leetcode/number_of_islands/playground.py
@@ -0,0 +1,35 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_num_islands, run_num_islands
+from solution import Solution
+
+# %%
+# Example test case
+grid = [
+ ["1", "1", "1", "1", "0"],
+ ["1", "1", "0", "1", "0"],
+ ["1", "1", "0", "0", "0"],
+ ["0", "0", "0", "0", "0"],
+]
+expected = 1
+
+# %%
+result = run_num_islands(Solution, grid)
+result
+
+# %%
+assert_num_islands(result, expected)
diff --git a/leetcode/partition_equal_subset_sum/playground.ipynb b/leetcode/partition_equal_subset_sum/playground.ipynb
deleted file mode 100644
index 5597f66..0000000
--- a/leetcode/partition_equal_subset_sum/playground.ipynb
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_can_partition, run_can_partition\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "nums = [1, 5, 11, 5]\n",
- "expected = True"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_can_partition(Solution, nums)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_can_partition(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/partition_equal_subset_sum/playground.py b/leetcode/partition_equal_subset_sum/playground.py
new file mode 100644
index 0000000..9bf8361
--- /dev/null
+++ b/leetcode/partition_equal_subset_sum/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_can_partition, run_can_partition
+from solution import Solution
+
+# %%
+# Example test case
+nums = [1, 5, 11, 5]
+expected = True
+
+# %%
+result = run_can_partition(Solution, nums)
+result
+
+# %%
+assert_can_partition(result, expected)
diff --git a/leetcode/partition_equal_subset_sum/test_solution.py b/leetcode/partition_equal_subset_sum/test_solution.py
index e826127..a480df5 100644
--- a/leetcode/partition_equal_subset_sum/test_solution.py
+++ b/leetcode/partition_equal_subset_sum/test_solution.py
@@ -3,7 +3,7 @@
from leetcode_py.test_utils import logged_test
from .helpers import assert_can_partition, run_can_partition
-from .solution import Solution
+from .solution import Solution, SolutionBitset
class TestPartitionEqualSubsetSum:
@@ -11,6 +11,7 @@ def setup_method(self):
self.solution = Solution()
@logged_test
+ @pytest.mark.parametrize("solution_class", [Solution, SolutionBitset])
@pytest.mark.parametrize(
"nums, expected",
[
@@ -31,6 +32,6 @@ def setup_method(self):
([4, 4, 4, 4, 4, 4], True),
],
)
- def test_can_partition(self, nums: list[int], expected: bool):
- result = run_can_partition(Solution, nums)
+ def test_can_partition(self, solution_class: type, nums: list[int], expected: bool):
+ result = run_can_partition(solution_class, nums)
assert_can_partition(result, expected)
diff --git a/leetcode/permutations/playground.ipynb b/leetcode/permutations/playground.ipynb
deleted file mode 100644
index 3df2f29..0000000
--- a/leetcode/permutations/playground.ipynb
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_permute, run_permute\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "nums = [1, 2, 3]\n",
- "expected = [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_permute(Solution, nums)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_permute(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/permutations/playground.py b/leetcode/permutations/playground.py
new file mode 100644
index 0000000..07de7dd
--- /dev/null
+++ b/leetcode/permutations/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_permute, run_permute
+from solution import Solution
+
+# %%
+# Example test case
+nums = [1, 2, 3]
+expected = [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
+
+# %%
+result = run_permute(Solution, nums)
+result
+
+# %%
+assert_permute(result, expected)
diff --git a/leetcode/product_of_array_except_self/playground.ipynb b/leetcode/product_of_array_except_self/playground.ipynb
deleted file mode 100644
index c96f1f3..0000000
--- a/leetcode/product_of_array_except_self/playground.ipynb
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_product_except_self, run_product_except_self\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "nums = [1, 2, 3, 4]\n",
- "expected = [24, 12, 8, 6]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_product_except_self(Solution, nums)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_product_except_self(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/product_of_array_except_self/playground.py b/leetcode/product_of_array_except_self/playground.py
new file mode 100644
index 0000000..f8a43ad
--- /dev/null
+++ b/leetcode/product_of_array_except_self/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_product_except_self, run_product_except_self
+from solution import Solution
+
+# %%
+# Example test case
+nums = [1, 2, 3, 4]
+expected = [24, 12, 8, 6]
+
+# %%
+result = run_product_except_self(Solution, nums)
+result
+
+# %%
+assert_product_except_self(result, expected)
diff --git a/leetcode/ransom_note/playground.ipynb b/leetcode/ransom_note/playground.ipynb
deleted file mode 100644
index 5982636..0000000
--- a/leetcode/ransom_note/playground.ipynb
+++ /dev/null
@@ -1,69 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_can_construct, run_can_construct\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "ransom_note = \"aa\"\n",
- "magazine = \"aab\"\n",
- "expected = True"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_can_construct(Solution, ransom_note, magazine)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_can_construct(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/ransom_note/playground.py b/leetcode/ransom_note/playground.py
new file mode 100644
index 0000000..86cbb15
--- /dev/null
+++ b/leetcode/ransom_note/playground.py
@@ -0,0 +1,31 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_can_construct, run_can_construct
+from solution import Solution
+
+# %%
+# Example test case
+ransom_note = "aa"
+magazine = "aab"
+expected = True
+
+# %%
+result = run_can_construct(Solution, ransom_note, magazine)
+result
+
+# %%
+assert_can_construct(result, expected)
diff --git a/leetcode/reverse_linked_list/playground.ipynb b/leetcode/reverse_linked_list/playground.ipynb
deleted file mode 100644
index b6a4171..0000000
--- a/leetcode/reverse_linked_list/playground.ipynb
+++ /dev/null
@@ -1,70 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_reverse_list, run_reverse_list\n",
- "from solution import Solution\n",
- "\n",
- "from leetcode_py import ListNode"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "head_list = [1, 2, 3, 4, 5]\n",
- "expected_list = [5, 4, 3, 2, 1]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_reverse_list(Solution, head_list)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_reverse_list(result, expected_list)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/reverse_linked_list/playground.py b/leetcode/reverse_linked_list/playground.py
new file mode 100644
index 0000000..375048c
--- /dev/null
+++ b/leetcode/reverse_linked_list/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_reverse_list, run_reverse_list
+from solution import Solution
+
+# %%
+# Example test case
+head_list = [1, 2, 3, 4, 5]
+expected_list = [5, 4, 3, 2, 1]
+
+# %%
+result = run_reverse_list(Solution, head_list)
+result
+
+# %%
+assert_reverse_list(result, expected_list)
diff --git a/leetcode/reverse_linked_list_ii/playground.ipynb b/leetcode/reverse_linked_list_ii/playground.ipynb
deleted file mode 100644
index 0cd88a4..0000000
--- a/leetcode/reverse_linked_list_ii/playground.ipynb
+++ /dev/null
@@ -1,71 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_reverse_between, run_reverse_between\n",
- "from solution import Solution\n",
- "\n",
- "from leetcode_py import ListNode"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "head_list = [1, 2, 3, 4, 5]\n",
- "left, right = 2, 4\n",
- "expected_list = [1, 4, 3, 2, 5]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_reverse_between(Solution, head_list, left, right)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_reverse_between(result, expected_list)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/reverse_linked_list_ii/playground.py b/leetcode/reverse_linked_list_ii/playground.py
new file mode 100644
index 0000000..0ee9f36
--- /dev/null
+++ b/leetcode/reverse_linked_list_ii/playground.py
@@ -0,0 +1,31 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_reverse_between, run_reverse_between
+from solution import Solution
+
+# %%
+# Example test case
+head_list = [1, 2, 3, 4, 5]
+left, right = 2, 4
+expected_list = [1, 4, 3, 2, 5]
+
+# %%
+result = run_reverse_between(Solution, head_list, left, right)
+result
+
+# %%
+assert_reverse_between(result, expected_list)
diff --git a/leetcode/rotting_oranges/playground.ipynb b/leetcode/rotting_oranges/playground.ipynb
deleted file mode 100644
index fde0cf1..0000000
--- a/leetcode/rotting_oranges/playground.ipynb
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_oranges_rotting, run_oranges_rotting\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "grid = [[2, 1, 1], [1, 1, 0], [0, 1, 1]]\n",
- "expected = 4"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_oranges_rotting(Solution, grid)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_oranges_rotting(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/rotting_oranges/playground.py b/leetcode/rotting_oranges/playground.py
new file mode 100644
index 0000000..7f1f44e
--- /dev/null
+++ b/leetcode/rotting_oranges/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_oranges_rotting, run_oranges_rotting
+from solution import Solution
+
+# %%
+# Example test case
+grid = [[2, 1, 1], [1, 1, 0], [0, 1, 1]]
+expected = 4
+
+# %%
+result = run_oranges_rotting(Solution, grid)
+result
+
+# %%
+assert_oranges_rotting(result, expected)
diff --git a/leetcode/search_in_rotated_sorted_array/playground.ipynb b/leetcode/search_in_rotated_sorted_array/playground.ipynb
deleted file mode 100644
index 6dadf29..0000000
--- a/leetcode/search_in_rotated_sorted_array/playground.ipynb
+++ /dev/null
@@ -1,69 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_search, run_search\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "nums = [4, 5, 6, 7, 0, 1, 2]\n",
- "target = 0\n",
- "expected = 4"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_search(Solution, nums, target)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_search(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/search_in_rotated_sorted_array/playground.py b/leetcode/search_in_rotated_sorted_array/playground.py
new file mode 100644
index 0000000..1c72b5a
--- /dev/null
+++ b/leetcode/search_in_rotated_sorted_array/playground.py
@@ -0,0 +1,31 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_search, run_search
+from solution import Solution
+
+# %%
+# Example test case
+nums = [4, 5, 6, 7, 0, 1, 2]
+target = 0
+expected = 4
+
+# %%
+result = run_search(Solution, nums, target)
+result
+
+# %%
+assert_search(result, expected)
diff --git a/leetcode/serialize_and_deserialize_binary_tree/playground.ipynb b/leetcode/serialize_and_deserialize_binary_tree/playground.ipynb
deleted file mode 100644
index a1b0bf6..0000000
--- a/leetcode/serialize_and_deserialize_binary_tree/playground.ipynb
+++ /dev/null
@@ -1,69 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_serialize_deserialize, run_serialize_deserialize\n",
- "from solution import Codec\n",
- "\n",
- "from leetcode_py import TreeNode"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "root_list = [1, 2, 3, None, None, 4, 5]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_serialize_deserialize(Codec, root_list)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_serialize_deserialize(result, root_list)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/serialize_and_deserialize_binary_tree/playground.py b/leetcode/serialize_and_deserialize_binary_tree/playground.py
new file mode 100644
index 0000000..06cf1af
--- /dev/null
+++ b/leetcode/serialize_and_deserialize_binary_tree/playground.py
@@ -0,0 +1,29 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_serialize_deserialize, run_serialize_deserialize
+from solution import Codec
+
+# %%
+# Example test case
+root_list = [1, 2, 3, None, None, 4, 5]
+
+# %%
+result = run_serialize_deserialize(Codec, root_list)
+result
+
+# %%
+assert_serialize_deserialize(result, root_list)
diff --git a/leetcode/sort_colors/playground.ipynb b/leetcode/sort_colors/playground.ipynb
deleted file mode 100644
index b2f099f..0000000
--- a/leetcode/sort_colors/playground.ipynb
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_sort_colors, run_sort_colors\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "nums = [2, 0, 2, 1, 1, 0]\n",
- "expected = [0, 0, 1, 1, 2, 2]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_sort_colors(Solution, nums)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_sort_colors(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/sort_colors/playground.py b/leetcode/sort_colors/playground.py
new file mode 100644
index 0000000..9b2c154
--- /dev/null
+++ b/leetcode/sort_colors/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_sort_colors, run_sort_colors
+from solution import Solution
+
+# %%
+# Example test case
+nums = [2, 0, 2, 1, 1, 0]
+expected = [0, 0, 1, 1, 2, 2]
+
+# %%
+result = run_sort_colors(Solution, nums)
+result
+
+# %%
+assert_sort_colors(result, expected)
diff --git a/leetcode/spiral_matrix/playground.ipynb b/leetcode/spiral_matrix/playground.ipynb
deleted file mode 100644
index 0668a7e..0000000
--- a/leetcode/spiral_matrix/playground.ipynb
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_spiral_order, run_spiral_order\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]\n",
- "expected = [1, 2, 3, 6, 9, 8, 7, 4, 5]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_spiral_order(Solution, matrix)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_spiral_order(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/spiral_matrix/playground.py b/leetcode/spiral_matrix/playground.py
new file mode 100644
index 0000000..07f54ab
--- /dev/null
+++ b/leetcode/spiral_matrix/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_spiral_order, run_spiral_order
+from solution import Solution
+
+# %%
+# Example test case
+matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
+expected = [1, 2, 3, 6, 9, 8, 7, 4, 5]
+
+# %%
+result = run_spiral_order(Solution, matrix)
+result
+
+# %%
+assert_spiral_order(result, expected)
diff --git a/leetcode/string_to_integer_atoi/playground.ipynb b/leetcode/string_to_integer_atoi/playground.ipynb
deleted file mode 100644
index 82ecfb7..0000000
--- a/leetcode/string_to_integer_atoi/playground.ipynb
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_my_atoi, run_my_atoi\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "s = \"42\"\n",
- "expected = 42"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_my_atoi(Solution, s)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_my_atoi(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/string_to_integer_atoi/playground.py b/leetcode/string_to_integer_atoi/playground.py
new file mode 100644
index 0000000..c0656aa
--- /dev/null
+++ b/leetcode/string_to_integer_atoi/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_my_atoi, run_my_atoi
+from solution import Solution
+
+# %%
+# Example test case
+s = "42"
+expected = 42
+
+# %%
+result = run_my_atoi(Solution, s)
+result
+
+# %%
+assert_my_atoi(result, expected)
diff --git a/leetcode/task_scheduler/playground.ipynb b/leetcode/task_scheduler/playground.ipynb
deleted file mode 100644
index 3ad7d83..0000000
--- a/leetcode/task_scheduler/playground.ipynb
+++ /dev/null
@@ -1,69 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_least_interval, run_least_interval\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "tasks = [\"A\", \"A\", \"A\", \"B\", \"B\", \"B\"]\n",
- "n = 2\n",
- "expected = 8"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_least_interval(Solution, tasks, n)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_least_interval(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/task_scheduler/playground.py b/leetcode/task_scheduler/playground.py
new file mode 100644
index 0000000..e0bcc11
--- /dev/null
+++ b/leetcode/task_scheduler/playground.py
@@ -0,0 +1,31 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_least_interval, run_least_interval
+from solution import Solution
+
+# %%
+# Example test case
+tasks = ["A", "A", "A", "B", "B", "B"]
+n = 2
+expected = 8
+
+# %%
+result = run_least_interval(Solution, tasks, n)
+result
+
+# %%
+assert_least_interval(result, expected)
diff --git a/leetcode/three_sum/playground.ipynb b/leetcode/three_sum/playground.ipynb
deleted file mode 100644
index ddbc41b..0000000
--- a/leetcode/three_sum/playground.ipynb
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_three_sum, run_three_sum\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "nums = [-1, 0, 1, 2, -1, -4]\n",
- "expected = [[-1, -1, 2], [-1, 0, 1]]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_three_sum(Solution, nums)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_three_sum(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/three_sum/playground.py b/leetcode/three_sum/playground.py
new file mode 100644
index 0000000..818263e
--- /dev/null
+++ b/leetcode/three_sum/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_three_sum, run_three_sum
+from solution import Solution
+
+# %%
+# Example test case
+nums = [-1, 0, 1, 2, -1, -4]
+expected = [[-1, -1, 2], [-1, 0, 1]]
+
+# %%
+result = run_three_sum(Solution, nums)
+result
+
+# %%
+assert_three_sum(result, expected)
diff --git a/leetcode/time_based_key_value_store/playground.ipynb b/leetcode/time_based_key_value_store/playground.ipynb
deleted file mode 100644
index 28f407a..0000000
--- a/leetcode/time_based_key_value_store/playground.ipynb
+++ /dev/null
@@ -1,69 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_time_map_operations, run_time_map_operations\n",
- "from solution import TimeMap"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "operations = [\"TimeMap\", \"set\", \"get\", \"get\", \"set\", \"get\", \"get\"]\n",
- "inputs = [[], [\"foo\", \"bar\", 1], [\"foo\", 1], [\"foo\", 3], [\"foo\", \"bar2\", 4], [\"foo\", 4], [\"foo\", 5]]\n",
- "expected = [None, None, \"bar\", \"bar\", None, \"bar2\", \"bar2\"]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_time_map_operations(TimeMap, operations, inputs)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_time_map_operations(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/time_based_key_value_store/playground.py b/leetcode/time_based_key_value_store/playground.py
new file mode 100644
index 0000000..ead5892
--- /dev/null
+++ b/leetcode/time_based_key_value_store/playground.py
@@ -0,0 +1,31 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_time_map_operations, run_time_map_operations
+from solution import TimeMap
+
+# %%
+# Example test case
+operations = ["TimeMap", "set", "get", "get", "set", "get", "get"]
+inputs = [[], ["foo", "bar", 1], ["foo", 1], ["foo", 3], ["foo", "bar2", 4], ["foo", 4], ["foo", 5]]
+expected = [None, None, "bar", "bar", None, "bar2", "bar2"]
+
+# %%
+result = run_time_map_operations(TimeMap, operations, inputs)
+result
+
+# %%
+assert_time_map_operations(result, expected)
diff --git a/leetcode/trapping_rain_water/playground.ipynb b/leetcode/trapping_rain_water/playground.ipynb
deleted file mode 100644
index b4db37d..0000000
--- a/leetcode/trapping_rain_water/playground.ipynb
+++ /dev/null
@@ -1,91 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": 1,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_trap, run_trap\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "height = [0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1]\n",
- "expected = 6"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "id": "run",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "6"
- ]
- },
- "execution_count": 3,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "result = run_trap(Solution, height)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "id": "assert",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "True"
- ]
- },
- "execution_count": 4,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "assert_trap(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/trapping_rain_water/playground.py b/leetcode/trapping_rain_water/playground.py
new file mode 100644
index 0000000..749b303
--- /dev/null
+++ b/leetcode/trapping_rain_water/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_trap, run_trap
+from solution import Solution
+
+# %%
+# Example test case
+height = [0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1]
+expected = 6
+
+# %%
+result = run_trap(Solution, height)
+result
+
+# %%
+assert_trap(result, expected)
diff --git a/leetcode/two_sum/playground.ipynb b/leetcode/two_sum/playground.ipynb
deleted file mode 100644
index 1a6ec8b..0000000
--- a/leetcode/two_sum/playground.ipynb
+++ /dev/null
@@ -1,92 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": 1,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_two_sum, run_two_sum\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "nums = [2, 7, 11, 15]\n",
- "target = 9\n",
- "expected = [0, 1]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "id": "run",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "[0, 1]"
- ]
- },
- "execution_count": 3,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "result = run_two_sum(Solution, nums, target)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "id": "assert",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "True"
- ]
- },
- "execution_count": 4,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "assert_two_sum(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/two_sum/playground.py b/leetcode/two_sum/playground.py
new file mode 100644
index 0000000..79ef5d4
--- /dev/null
+++ b/leetcode/two_sum/playground.py
@@ -0,0 +1,31 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_two_sum, run_two_sum
+from solution import Solution
+
+# %%
+# Example test case
+nums = [2, 7, 11, 15]
+target = 9
+expected = [0, 1]
+
+# %%
+result = run_two_sum(Solution, nums, target)
+result
+
+# %%
+assert_two_sum(result, expected)
diff --git a/leetcode/valid_anagram/playground.ipynb b/leetcode/valid_anagram/playground.ipynb
deleted file mode 100644
index c178ebe..0000000
--- a/leetcode/valid_anagram/playground.ipynb
+++ /dev/null
@@ -1,92 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": 1,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_is_anagram, run_is_anagram\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "s = \"anagram\"\n",
- "t = \"nagaram\"\n",
- "expected = True"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "id": "run",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "True"
- ]
- },
- "execution_count": 3,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "result = run_is_anagram(Solution, s, t)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "id": "assert",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "True"
- ]
- },
- "execution_count": 4,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "assert_is_anagram(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/valid_anagram/playground.py b/leetcode/valid_anagram/playground.py
new file mode 100644
index 0000000..46bfe1d
--- /dev/null
+++ b/leetcode/valid_anagram/playground.py
@@ -0,0 +1,31 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_is_anagram, run_is_anagram
+from solution import Solution
+
+# %%
+# Example test case
+s = "anagram"
+t = "nagaram"
+expected = True
+
+# %%
+result = run_is_anagram(Solution, s, t)
+result
+
+# %%
+assert_is_anagram(result, expected)
diff --git a/leetcode/valid_palindrome/playground.ipynb b/leetcode/valid_palindrome/playground.ipynb
deleted file mode 100644
index c4c6bbc..0000000
--- a/leetcode/valid_palindrome/playground.ipynb
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_is_palindrome, run_is_palindrome\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "s = \"A man, a plan, a canal: Panama\"\n",
- "expected = True"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_is_palindrome(Solution, s)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_is_palindrome(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/valid_palindrome/playground.py b/leetcode/valid_palindrome/playground.py
new file mode 100644
index 0000000..64924c5
--- /dev/null
+++ b/leetcode/valid_palindrome/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_is_palindrome, run_is_palindrome
+from solution import Solution
+
+# %%
+# Example test case
+s = "A man, a plan, a canal: Panama"
+expected = True
+
+# %%
+result = run_is_palindrome(Solution, s)
+result
+
+# %%
+assert_is_palindrome(result, expected)
diff --git a/leetcode/valid_parentheses/playground.ipynb b/leetcode/valid_parentheses/playground.ipynb
deleted file mode 100644
index e5324f0..0000000
--- a/leetcode/valid_parentheses/playground.ipynb
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_is_valid, run_is_valid\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "s = \"()\"\n",
- "expected = True"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_is_valid(Solution, s)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_is_valid(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/valid_parentheses/playground.py b/leetcode/valid_parentheses/playground.py
new file mode 100644
index 0000000..7c64862
--- /dev/null
+++ b/leetcode/valid_parentheses/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_is_valid, run_is_valid
+from solution import Solution
+
+# %%
+# Example test case
+s = "()"
+expected = True
+
+# %%
+result = run_is_valid(Solution, s)
+result
+
+# %%
+assert_is_valid(result, expected)
diff --git a/leetcode/validate_binary_search_tree/playground.ipynb b/leetcode/validate_binary_search_tree/playground.ipynb
deleted file mode 100644
index a53e0f9..0000000
--- a/leetcode/validate_binary_search_tree/playground.ipynb
+++ /dev/null
@@ -1,70 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_is_valid_bst, run_is_valid_bst\n",
- "from solution import Solution\n",
- "\n",
- "from leetcode_py import TreeNode"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "root_list = [2, 1, 3]\n",
- "expected = True"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_is_valid_bst(Solution, root_list)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_is_valid_bst(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/validate_binary_search_tree/playground.py b/leetcode/validate_binary_search_tree/playground.py
new file mode 100644
index 0000000..bd7fd3c
--- /dev/null
+++ b/leetcode/validate_binary_search_tree/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_is_valid_bst, run_is_valid_bst
+from solution import Solution
+
+# %%
+# Example test case
+root_list = [2, 1, 3]
+expected = True
+
+# %%
+result = run_is_valid_bst(Solution, root_list)
+result
+
+# %%
+assert_is_valid_bst(result, expected)
diff --git a/leetcode/validate_binary_search_tree/test_solution.py b/leetcode/validate_binary_search_tree/test_solution.py
index 8e5eca0..2491911 100644
--- a/leetcode/validate_binary_search_tree/test_solution.py
+++ b/leetcode/validate_binary_search_tree/test_solution.py
@@ -3,7 +3,7 @@
from leetcode_py.test_utils import logged_test
from .helpers import assert_is_valid_bst, run_is_valid_bst
-from .solution import Solution
+from .solution import Solution, SolutionBFS, SolutionDFS
class TestValidateBinarySearchTree:
@@ -11,6 +11,7 @@ def setup_method(self):
self.solution = Solution()
@logged_test
+ @pytest.mark.parametrize("solution_class", [Solution, SolutionDFS, SolutionBFS])
@pytest.mark.parametrize(
"root_list, expected",
[
@@ -28,6 +29,6 @@ def setup_method(self):
([3, 1, 5, 0, 2, 4, 6], True),
],
)
- def test_is_valid_bst(self, root_list: list[int | None], expected: bool):
- result = run_is_valid_bst(Solution, root_list)
+ def test_is_valid_bst(self, solution_class: type, root_list: list[int | None], expected: bool):
+ result = run_is_valid_bst(solution_class, root_list)
assert_is_valid_bst(result, expected)
diff --git a/leetcode/word_break/playground.ipynb b/leetcode/word_break/playground.ipynb
deleted file mode 100644
index b606647..0000000
--- a/leetcode/word_break/playground.ipynb
+++ /dev/null
@@ -1,69 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_word_break, run_word_break\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "s = \"leetcode\"\n",
- "word_dict = [\"leet\", \"code\"]\n",
- "expected = True"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_word_break(Solution, s, word_dict)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_word_break(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/word_break/playground.py b/leetcode/word_break/playground.py
new file mode 100644
index 0000000..4ee7af7
--- /dev/null
+++ b/leetcode/word_break/playground.py
@@ -0,0 +1,31 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_word_break, run_word_break
+from solution import Solution
+
+# %%
+# Example test case
+s = "leetcode"
+word_dict = ["leet", "code"]
+expected = True
+
+# %%
+result = run_word_break(Solution, s, word_dict)
+result
+
+# %%
+assert_word_break(result, expected)
diff --git a/leetcode/word_ladder/playground.ipynb b/leetcode/word_ladder/playground.ipynb
deleted file mode 100644
index 863eedf..0000000
--- a/leetcode/word_ladder/playground.ipynb
+++ /dev/null
@@ -1,70 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_ladder_length, run_ladder_length\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "begin_word = \"hit\"\n",
- "end_word = \"cog\"\n",
- "word_list = [\"hot\", \"dot\", \"dog\", \"lot\", \"log\", \"cog\"]\n",
- "expected = 5"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "run",
- "metadata": {},
- "outputs": [],
- "source": [
- "result = run_ladder_length(Solution, begin_word, end_word, word_list)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "assert",
- "metadata": {},
- "outputs": [],
- "source": [
- "assert_ladder_length(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/word_ladder/playground.py b/leetcode/word_ladder/playground.py
new file mode 100644
index 0000000..a1dabdc
--- /dev/null
+++ b/leetcode/word_ladder/playground.py
@@ -0,0 +1,32 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_ladder_length, run_ladder_length
+from solution import Solution
+
+# %%
+# Example test case
+begin_word = "hit"
+end_word = "cog"
+word_list = ["hot", "dot", "dog", "lot", "log", "cog"]
+expected = 5
+
+# %%
+result = run_ladder_length(Solution, begin_word, end_word, word_list)
+result
+
+# %%
+assert_ladder_length(result, expected)
diff --git a/leetcode/zero_one_matrix/playground.ipynb b/leetcode/zero_one_matrix/playground.ipynb
deleted file mode 100644
index 6b3b709..0000000
--- a/leetcode/zero_one_matrix/playground.ipynb
+++ /dev/null
@@ -1,91 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": 1,
- "id": "imports",
- "metadata": {},
- "outputs": [],
- "source": [
- "from helpers import assert_update_matrix, run_update_matrix\n",
- "from solution import Solution"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "id": "setup",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Example test case\n",
- "mat = [[0, 0, 0], [0, 1, 0], [1, 1, 1]]\n",
- "expected = [[0, 0, 0], [0, 1, 0], [1, 2, 1]]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "id": "run",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "[[0, 0, 0], [0, 1, 0], [1, 2, 1]]"
- ]
- },
- "execution_count": 3,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "result = run_update_matrix(Solution, mat)\n",
- "result"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "id": "assert",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "True"
- ]
- },
- "execution_count": 4,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "assert_update_matrix(result, expected)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "leetcode-py-py3.13",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.13.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/leetcode/zero_one_matrix/playground.py b/leetcode/zero_one_matrix/playground.py
new file mode 100644
index 0000000..a727bed
--- /dev/null
+++ b/leetcode/zero_one_matrix/playground.py
@@ -0,0 +1,30 @@
+# ---
+# jupyter:
+# jupytext:
+# formats: ipynb,py:percent
+# 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_update_matrix, run_update_matrix
+from solution import Solution
+
+# %%
+# Example test case
+mat = [[0, 0, 0], [0, 1, 0], [1, 1, 1]]
+expected = [[0, 0, 0], [0, 1, 0], [1, 2, 1]]
+
+# %%
+result = run_update_matrix(Solution, mat)
+result
+
+# %%
+assert_update_matrix(result, expected)
diff --git a/poetry.lock b/poetry.lock
index 54bb124..9f49b72 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -61,6 +61,26 @@ files = [
astroid = ["astroid (>=2,<4)"]
test = ["astroid (>=2,<4)", "pytest", "pytest-cov", "pytest-xdist"]
+[[package]]
+name = "attrs"
+version = "25.3.0"
+description = "Classes Without Boilerplate"
+optional = false
+python-versions = ">=3.8"
+groups = ["dev"]
+files = [
+ {file = "attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3"},
+ {file = "attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b"},
+]
+
+[package.extras]
+benchmark = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"]
+cov = ["cloudpickle ; platform_python_implementation == \"CPython\"", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"]
+dev = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"]
+docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier"]
+tests = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"]
+tests-mypy = ["mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\""]
+
[[package]]
name = "autopep8"
version = "2.3.2"
@@ -600,6 +620,21 @@ files = [
[package.extras]
tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich ; python_version >= \"3.11\""]
+[[package]]
+name = "fastjsonschema"
+version = "2.21.2"
+description = "Fastest Python implementation of JSON schema"
+optional = false
+python-versions = "*"
+groups = ["dev"]
+files = [
+ {file = "fastjsonschema-2.21.2-py3-none-any.whl", hash = "sha256:1c797122d0a86c5cace2e54bf4e819c36223b552017172f32c5c024a6b77e463"},
+ {file = "fastjsonschema-2.21.2.tar.gz", hash = "sha256:b1eb43748041c880796cd077f1a07c3d94e93ae84bba5ed36800a33554ae05de"},
+]
+
+[package.extras]
+devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benchmark", "pytest-cache", "validictory"]
+
[[package]]
name = "filelock"
version = "3.19.1"
@@ -806,6 +841,43 @@ MarkupSafe = ">=2.0"
[package.extras]
i18n = ["Babel (>=2.7)"]
+[[package]]
+name = "jsonschema"
+version = "4.25.1"
+description = "An implementation of JSON Schema validation for Python"
+optional = false
+python-versions = ">=3.9"
+groups = ["dev"]
+files = [
+ {file = "jsonschema-4.25.1-py3-none-any.whl", hash = "sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63"},
+ {file = "jsonschema-4.25.1.tar.gz", hash = "sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85"},
+]
+
+[package.dependencies]
+attrs = ">=22.2.0"
+jsonschema-specifications = ">=2023.03.6"
+referencing = ">=0.28.4"
+rpds-py = ">=0.7.1"
+
+[package.extras]
+format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"]
+format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "rfc3987-syntax (>=1.1.0)", "uri-template", "webcolors (>=24.6.0)"]
+
+[[package]]
+name = "jsonschema-specifications"
+version = "2025.9.1"
+description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry"
+optional = false
+python-versions = ">=3.9"
+groups = ["dev"]
+files = [
+ {file = "jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe"},
+ {file = "jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d"},
+]
+
+[package.dependencies]
+referencing = ">=0.31.0"
+
[[package]]
name = "jupyter-client"
version = "8.6.3"
@@ -850,6 +922,35 @@ traitlets = ">=5.3"
docs = ["intersphinx-registry", "myst-parser", "pydata-sphinx-theme", "sphinx-autodoc-typehints", "sphinxcontrib-spelling", "traitlets"]
test = ["ipykernel", "pre-commit", "pytest (<9)", "pytest-cov", "pytest-timeout"]
+[[package]]
+name = "jupytext"
+version = "1.17.3"
+description = "Jupyter notebooks as Markdown documents, Julia, Python or R scripts"
+optional = false
+python-versions = ">=3.9"
+groups = ["dev"]
+files = [
+ {file = "jupytext-1.17.3-py3-none-any.whl", hash = "sha256:09b0a94cd904416e823a5ba9f41bd181031215b6fc682d2b5c18e68354feb17c"},
+ {file = "jupytext-1.17.3.tar.gz", hash = "sha256:8b6dae76d63c95cad47b493c38f0d9c74491fb621dcd0980abfcac4c8f168679"},
+]
+
+[package.dependencies]
+markdown-it-py = ">=1.0"
+mdit-py-plugins = "*"
+nbformat = "*"
+packaging = "*"
+pyyaml = "*"
+
+[package.extras]
+dev = ["autopep8", "black", "flake8", "gitpython", "ipykernel", "isort", "jupyter-fs[fs] (>=1.0)", "jupyter-server (!=2.11)", "nbconvert", "pre-commit", "pytest", "pytest-asyncio", "pytest-cov (>=2.6.1)", "pytest-randomly", "pytest-xdist", "sphinx", "sphinx-gallery (>=0.8)"]
+docs = ["myst-parser", "sphinx", "sphinx-copybutton", "sphinx-rtd-theme"]
+test = ["pytest", "pytest-asyncio", "pytest-randomly", "pytest-xdist"]
+test-cov = ["black", "ipykernel", "jupyter-server (!=2.11)", "nbconvert", "pytest", "pytest-asyncio", "pytest-cov (>=2.6.1)", "pytest-randomly", "pytest-xdist"]
+test-external = ["autopep8", "black", "flake8", "gitpython", "ipykernel", "isort", "jupyter-fs[fs] (>=1.0)", "jupyter-server (!=2.11)", "nbconvert", "pre-commit", "pytest", "pytest-asyncio", "pytest-randomly", "pytest-xdist", "sphinx", "sphinx-gallery (>=0.8)"]
+test-functional = ["black", "pytest", "pytest-asyncio", "pytest-randomly", "pytest-xdist"]
+test-integration = ["black", "ipykernel", "jupyter-server (!=2.11)", "nbconvert", "pytest", "pytest-asyncio", "pytest-randomly", "pytest-xdist"]
+test-ui = ["bash-kernel"]
+
[[package]]
name = "loguru"
version = "0.7.3"
@@ -979,6 +1080,26 @@ files = [
[package.dependencies]
traitlets = "*"
+[[package]]
+name = "mdit-py-plugins"
+version = "0.5.0"
+description = "Collection of plugins for markdown-it-py"
+optional = false
+python-versions = ">=3.10"
+groups = ["dev"]
+files = [
+ {file = "mdit_py_plugins-0.5.0-py3-none-any.whl", hash = "sha256:07a08422fc1936a5d26d146759e9155ea466e842f5ab2f7d2266dd084c8dab1f"},
+ {file = "mdit_py_plugins-0.5.0.tar.gz", hash = "sha256:f4918cb50119f50446560513a8e311d574ff6aaed72606ddae6d35716fe809c6"},
+]
+
+[package.dependencies]
+markdown-it-py = ">=2.0.0,<5.0.0"
+
+[package.extras]
+code-style = ["pre-commit"]
+rtd = ["myst-parser", "sphinx-book-theme"]
+testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
+
[[package]]
name = "mdurl"
version = "0.1.2"
@@ -1063,6 +1184,28 @@ files = [
{file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"},
]
+[[package]]
+name = "nbformat"
+version = "5.10.4"
+description = "The Jupyter Notebook format"
+optional = false
+python-versions = ">=3.8"
+groups = ["dev"]
+files = [
+ {file = "nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b"},
+ {file = "nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a"},
+]
+
+[package.dependencies]
+fastjsonschema = ">=2.15"
+jsonschema = ">=2.6"
+jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0"
+traitlets = ">=5.1"
+
+[package.extras]
+docs = ["myst-parser", "pydata-sphinx-theme", "sphinx", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"]
+test = ["pep440", "pre-commit", "pytest", "testpath"]
+
[[package]]
name = "nbqa"
version = "1.9.1"
@@ -1597,6 +1740,22 @@ files = [
[package.dependencies]
cffi = {version = "*", markers = "implementation_name == \"pypy\""}
+[[package]]
+name = "referencing"
+version = "0.36.2"
+description = "JSON Referencing + Python"
+optional = false
+python-versions = ">=3.9"
+groups = ["dev"]
+files = [
+ {file = "referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0"},
+ {file = "referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa"},
+]
+
+[package.dependencies]
+attrs = ">=22.2.0"
+rpds-py = ">=0.7.0"
+
[[package]]
name = "requests"
version = "2.32.5"
@@ -1638,6 +1797,171 @@ pygments = ">=2.13.0,<3.0.0"
[package.extras]
jupyter = ["ipywidgets (>=7.5.1,<9)"]
+[[package]]
+name = "rpds-py"
+version = "0.27.1"
+description = "Python bindings to Rust's persistent data structures (rpds)"
+optional = false
+python-versions = ">=3.9"
+groups = ["dev"]
+files = [
+ {file = "rpds_py-0.27.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:68afeec26d42ab3b47e541b272166a0b4400313946871cba3ed3a4fc0cab1cef"},
+ {file = "rpds_py-0.27.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74e5b2f7bb6fa38b1b10546d27acbacf2a022a8b5543efb06cfebc72a59c85be"},
+ {file = "rpds_py-0.27.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9024de74731df54546fab0bfbcdb49fae19159ecaecfc8f37c18d2c7e2c0bd61"},
+ {file = "rpds_py-0.27.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:31d3ebadefcd73b73928ed0b2fd696f7fefda8629229f81929ac9c1854d0cffb"},
+ {file = "rpds_py-0.27.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2e7f8f169d775dd9092a1743768d771f1d1300453ddfe6325ae3ab5332b4657"},
+ {file = "rpds_py-0.27.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d905d16f77eb6ab2e324e09bfa277b4c8e5e6b8a78a3e7ff8f3cdf773b4c013"},
+ {file = "rpds_py-0.27.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50c946f048209e6362e22576baea09193809f87687a95a8db24e5fbdb307b93a"},
+ {file = "rpds_py-0.27.1-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:3deab27804d65cd8289eb814c2c0e807c4b9d9916c9225e363cb0cf875eb67c1"},
+ {file = "rpds_py-0.27.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8b61097f7488de4be8244c89915da8ed212832ccf1e7c7753a25a394bf9b1f10"},
+ {file = "rpds_py-0.27.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8a3f29aba6e2d7d90528d3c792555a93497fe6538aa65eb675b44505be747808"},
+ {file = "rpds_py-0.27.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dd6cd0485b7d347304067153a6dc1d73f7d4fd995a396ef32a24d24b8ac63ac8"},
+ {file = "rpds_py-0.27.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6f4461bf931108c9fa226ffb0e257c1b18dc2d44cd72b125bec50ee0ab1248a9"},
+ {file = "rpds_py-0.27.1-cp310-cp310-win32.whl", hash = "sha256:ee5422d7fb21f6a00c1901bf6559c49fee13a5159d0288320737bbf6585bd3e4"},
+ {file = "rpds_py-0.27.1-cp310-cp310-win_amd64.whl", hash = "sha256:3e039aabf6d5f83c745d5f9a0a381d031e9ed871967c0a5c38d201aca41f3ba1"},
+ {file = "rpds_py-0.27.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:be898f271f851f68b318872ce6ebebbc62f303b654e43bf72683dbdc25b7c881"},
+ {file = "rpds_py-0.27.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:62ac3d4e3e07b58ee0ddecd71d6ce3b1637de2d373501412df395a0ec5f9beb5"},
+ {file = "rpds_py-0.27.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4708c5c0ceb2d034f9991623631d3d23cb16e65c83736ea020cdbe28d57c0a0e"},
+ {file = "rpds_py-0.27.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:abfa1171a9952d2e0002aba2ad3780820b00cc3d9c98c6630f2e93271501f66c"},
+ {file = "rpds_py-0.27.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4b507d19f817ebaca79574b16eb2ae412e5c0835542c93fe9983f1e432aca195"},
+ {file = "rpds_py-0.27.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:168b025f8fd8d8d10957405f3fdcef3dc20f5982d398f90851f4abc58c566c52"},
+ {file = "rpds_py-0.27.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb56c6210ef77caa58e16e8c17d35c63fe3f5b60fd9ba9d424470c3400bcf9ed"},
+ {file = "rpds_py-0.27.1-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:d252f2d8ca0195faa707f8eb9368955760880b2b42a8ee16d382bf5dd807f89a"},
+ {file = "rpds_py-0.27.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6e5e54da1e74b91dbc7996b56640f79b195d5925c2b78efaa8c5d53e1d88edde"},
+ {file = "rpds_py-0.27.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ffce0481cc6e95e5b3f0a47ee17ffbd234399e6d532f394c8dce320c3b089c21"},
+ {file = "rpds_py-0.27.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a205fdfe55c90c2cd8e540ca9ceba65cbe6629b443bc05db1f590a3db8189ff9"},
+ {file = "rpds_py-0.27.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:689fb5200a749db0415b092972e8eba85847c23885c8543a8b0f5c009b1a5948"},
+ {file = "rpds_py-0.27.1-cp311-cp311-win32.whl", hash = "sha256:3182af66048c00a075010bc7f4860f33913528a4b6fc09094a6e7598e462fe39"},
+ {file = "rpds_py-0.27.1-cp311-cp311-win_amd64.whl", hash = "sha256:b4938466c6b257b2f5c4ff98acd8128ec36b5059e5c8f8372d79316b1c36bb15"},
+ {file = "rpds_py-0.27.1-cp311-cp311-win_arm64.whl", hash = "sha256:2f57af9b4d0793e53266ee4325535a31ba48e2f875da81a9177c9926dfa60746"},
+ {file = "rpds_py-0.27.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ae2775c1973e3c30316892737b91f9283f9908e3cc7625b9331271eaaed7dc90"},
+ {file = "rpds_py-0.27.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2643400120f55c8a96f7c9d858f7be0c88d383cd4653ae2cf0d0c88f668073e5"},
+ {file = "rpds_py-0.27.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16323f674c089b0360674a4abd28d5042947d54ba620f72514d69be4ff64845e"},
+ {file = "rpds_py-0.27.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a1f4814b65eacac94a00fc9a526e3fdafd78e439469644032032d0d63de4881"},
+ {file = "rpds_py-0.27.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ba32c16b064267b22f1850a34051121d423b6f7338a12b9459550eb2096e7ec"},
+ {file = "rpds_py-0.27.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5c20f33fd10485b80f65e800bbe5f6785af510b9f4056c5a3c612ebc83ba6cb"},
+ {file = "rpds_py-0.27.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:466bfe65bd932da36ff279ddd92de56b042f2266d752719beb97b08526268ec5"},
+ {file = "rpds_py-0.27.1-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:41e532bbdcb57c92ba3be62c42e9f096431b4cf478da9bc3bc6ce5c38ab7ba7a"},
+ {file = "rpds_py-0.27.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f149826d742b406579466283769a8ea448eed82a789af0ed17b0cd5770433444"},
+ {file = "rpds_py-0.27.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:80c60cfb5310677bd67cb1e85a1e8eb52e12529545441b43e6f14d90b878775a"},
+ {file = "rpds_py-0.27.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7ee6521b9baf06085f62ba9c7a3e5becffbc32480d2f1b351559c001c38ce4c1"},
+ {file = "rpds_py-0.27.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a512c8263249a9d68cac08b05dd59d2b3f2061d99b322813cbcc14c3c7421998"},
+ {file = "rpds_py-0.27.1-cp312-cp312-win32.whl", hash = "sha256:819064fa048ba01b6dadc5116f3ac48610435ac9a0058bbde98e569f9e785c39"},
+ {file = "rpds_py-0.27.1-cp312-cp312-win_amd64.whl", hash = "sha256:d9199717881f13c32c4046a15f024971a3b78ad4ea029e8da6b86e5aa9cf4594"},
+ {file = "rpds_py-0.27.1-cp312-cp312-win_arm64.whl", hash = "sha256:33aa65b97826a0e885ef6e278fbd934e98cdcfed80b63946025f01e2f5b29502"},
+ {file = "rpds_py-0.27.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:e4b9fcfbc021633863a37e92571d6f91851fa656f0180246e84cbd8b3f6b329b"},
+ {file = "rpds_py-0.27.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1441811a96eadca93c517d08df75de45e5ffe68aa3089924f963c782c4b898cf"},
+ {file = "rpds_py-0.27.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55266dafa22e672f5a4f65019015f90336ed31c6383bd53f5e7826d21a0e0b83"},
+ {file = "rpds_py-0.27.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d78827d7ac08627ea2c8e02c9e5b41180ea5ea1f747e9db0915e3adf36b62dcf"},
+ {file = "rpds_py-0.27.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae92443798a40a92dc5f0b01d8a7c93adde0c4dc965310a29ae7c64d72b9fad2"},
+ {file = "rpds_py-0.27.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c46c9dd2403b66a2a3b9720ec4b74d4ab49d4fabf9f03dfdce2d42af913fe8d0"},
+ {file = "rpds_py-0.27.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2efe4eb1d01b7f5f1939f4ef30ecea6c6b3521eec451fb93191bf84b2a522418"},
+ {file = "rpds_py-0.27.1-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:15d3b4d83582d10c601f481eca29c3f138d44c92187d197aff663a269197c02d"},
+ {file = "rpds_py-0.27.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4ed2e16abbc982a169d30d1a420274a709949e2cbdef119fe2ec9d870b42f274"},
+ {file = "rpds_py-0.27.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a75f305c9b013289121ec0f1181931975df78738cdf650093e6b86d74aa7d8dd"},
+ {file = "rpds_py-0.27.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:67ce7620704745881a3d4b0ada80ab4d99df390838839921f99e63c474f82cf2"},
+ {file = "rpds_py-0.27.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9d992ac10eb86d9b6f369647b6a3f412fc0075cfd5d799530e84d335e440a002"},
+ {file = "rpds_py-0.27.1-cp313-cp313-win32.whl", hash = "sha256:4f75e4bd8ab8db624e02c8e2fc4063021b58becdbe6df793a8111d9343aec1e3"},
+ {file = "rpds_py-0.27.1-cp313-cp313-win_amd64.whl", hash = "sha256:f9025faafc62ed0b75a53e541895ca272815bec18abe2249ff6501c8f2e12b83"},
+ {file = "rpds_py-0.27.1-cp313-cp313-win_arm64.whl", hash = "sha256:ed10dc32829e7d222b7d3b93136d25a406ba9788f6a7ebf6809092da1f4d279d"},
+ {file = "rpds_py-0.27.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:92022bbbad0d4426e616815b16bc4127f83c9a74940e1ccf3cfe0b387aba0228"},
+ {file = "rpds_py-0.27.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:47162fdab9407ec3f160805ac3e154df042e577dd53341745fc7fb3f625e6d92"},
+ {file = "rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb89bec23fddc489e5d78b550a7b773557c9ab58b7946154a10a6f7a214a48b2"},
+ {file = "rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e48af21883ded2b3e9eb48cb7880ad8598b31ab752ff3be6457001d78f416723"},
+ {file = "rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6f5b7bd8e219ed50299e58551a410b64daafb5017d54bbe822e003856f06a802"},
+ {file = "rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08f1e20bccf73b08d12d804d6e1c22ca5530e71659e6673bce31a6bb71c1e73f"},
+ {file = "rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dc5dceeaefcc96dc192e3a80bbe1d6c410c469e97bdd47494a7d930987f18b2"},
+ {file = "rpds_py-0.27.1-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:d76f9cc8665acdc0c9177043746775aa7babbf479b5520b78ae4002d889f5c21"},
+ {file = "rpds_py-0.27.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:134fae0e36022edad8290a6661edf40c023562964efea0cc0ec7f5d392d2aaef"},
+ {file = "rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:eb11a4f1b2b63337cfd3b4d110af778a59aae51c81d195768e353d8b52f88081"},
+ {file = "rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:13e608ac9f50a0ed4faec0e90ece76ae33b34c0e8656e3dceb9a7db994c692cd"},
+ {file = "rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dd2135527aa40f061350c3f8f89da2644de26cd73e4de458e79606384f4f68e7"},
+ {file = "rpds_py-0.27.1-cp313-cp313t-win32.whl", hash = "sha256:3020724ade63fe320a972e2ffd93b5623227e684315adce194941167fee02688"},
+ {file = "rpds_py-0.27.1-cp313-cp313t-win_amd64.whl", hash = "sha256:8ee50c3e41739886606388ba3ab3ee2aae9f35fb23f833091833255a31740797"},
+ {file = "rpds_py-0.27.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:acb9aafccaae278f449d9c713b64a9e68662e7799dbd5859e2c6b3c67b56d334"},
+ {file = "rpds_py-0.27.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b7fb801aa7f845ddf601c49630deeeccde7ce10065561d92729bfe81bd21fb33"},
+ {file = "rpds_py-0.27.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe0dd05afb46597b9a2e11c351e5e4283c741237e7f617ffb3252780cca9336a"},
+ {file = "rpds_py-0.27.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b6dfb0e058adb12d8b1d1b25f686e94ffa65d9995a5157afe99743bf7369d62b"},
+ {file = "rpds_py-0.27.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ed090ccd235f6fa8bb5861684567f0a83e04f52dfc2e5c05f2e4b1309fcf85e7"},
+ {file = "rpds_py-0.27.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf876e79763eecf3e7356f157540d6a093cef395b65514f17a356f62af6cc136"},
+ {file = "rpds_py-0.27.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12ed005216a51b1d6e2b02a7bd31885fe317e45897de81d86dcce7d74618ffff"},
+ {file = "rpds_py-0.27.1-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:ee4308f409a40e50593c7e3bb8cbe0b4d4c66d1674a316324f0c2f5383b486f9"},
+ {file = "rpds_py-0.27.1-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0b08d152555acf1f455154d498ca855618c1378ec810646fcd7c76416ac6dc60"},
+ {file = "rpds_py-0.27.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:dce51c828941973a5684d458214d3a36fcd28da3e1875d659388f4f9f12cc33e"},
+ {file = "rpds_py-0.27.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:c1476d6f29eb81aa4151c9a31219b03f1f798dc43d8af1250a870735516a1212"},
+ {file = "rpds_py-0.27.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3ce0cac322b0d69b63c9cdb895ee1b65805ec9ffad37639f291dd79467bee675"},
+ {file = "rpds_py-0.27.1-cp314-cp314-win32.whl", hash = "sha256:dfbfac137d2a3d0725758cd141f878bf4329ba25e34979797c89474a89a8a3a3"},
+ {file = "rpds_py-0.27.1-cp314-cp314-win_amd64.whl", hash = "sha256:a6e57b0abfe7cc513450fcf529eb486b6e4d3f8aee83e92eb5f1ef848218d456"},
+ {file = "rpds_py-0.27.1-cp314-cp314-win_arm64.whl", hash = "sha256:faf8d146f3d476abfee026c4ae3bdd9ca14236ae4e4c310cbd1cf75ba33d24a3"},
+ {file = "rpds_py-0.27.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:ba81d2b56b6d4911ce735aad0a1d4495e808b8ee4dc58715998741a26874e7c2"},
+ {file = "rpds_py-0.27.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:84f7d509870098de0e864cad0102711c1e24e9b1a50ee713b65928adb22269e4"},
+ {file = "rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9e960fc78fecd1100539f14132425e1d5fe44ecb9239f8f27f079962021523e"},
+ {file = "rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:62f85b665cedab1a503747617393573995dac4600ff51869d69ad2f39eb5e817"},
+ {file = "rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fed467af29776f6556250c9ed85ea5a4dd121ab56a5f8b206e3e7a4c551e48ec"},
+ {file = "rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2729615f9d430af0ae6b36cf042cb55c0936408d543fb691e1a9e36648fd35a"},
+ {file = "rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b207d881a9aef7ba753d69c123a35d96ca7cb808056998f6b9e8747321f03b8"},
+ {file = "rpds_py-0.27.1-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:639fd5efec029f99b79ae47e5d7e00ad8a773da899b6309f6786ecaf22948c48"},
+ {file = "rpds_py-0.27.1-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fecc80cb2a90e28af8a9b366edacf33d7a91cbfe4c2c4544ea1246e949cfebeb"},
+ {file = "rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42a89282d711711d0a62d6f57d81aa43a1368686c45bc1c46b7f079d55692734"},
+ {file = "rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:cf9931f14223de59551ab9d38ed18d92f14f055a5f78c1d8ad6493f735021bbb"},
+ {file = "rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f39f58a27cc6e59f432b568ed8429c7e1641324fbe38131de852cd77b2d534b0"},
+ {file = "rpds_py-0.27.1-cp314-cp314t-win32.whl", hash = "sha256:d5fa0ee122dc09e23607a28e6d7b150da16c662e66409bbe85230e4c85bb528a"},
+ {file = "rpds_py-0.27.1-cp314-cp314t-win_amd64.whl", hash = "sha256:6567d2bb951e21232c2f660c24cf3470bb96de56cdcb3f071a83feeaff8a2772"},
+ {file = "rpds_py-0.27.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c918c65ec2e42c2a78d19f18c553d77319119bf43aa9e2edf7fb78d624355527"},
+ {file = "rpds_py-0.27.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1fea2b1a922c47c51fd07d656324531adc787e415c8b116530a1d29c0516c62d"},
+ {file = "rpds_py-0.27.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbf94c58e8e0cd6b6f38d8de67acae41b3a515c26169366ab58bdca4a6883bb8"},
+ {file = "rpds_py-0.27.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c2a8fed130ce946d5c585eddc7c8eeef0051f58ac80a8ee43bd17835c144c2cc"},
+ {file = "rpds_py-0.27.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:037a2361db72ee98d829bc2c5b7cc55598ae0a5e0ec1823a56ea99374cfd73c1"},
+ {file = "rpds_py-0.27.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5281ed1cc1d49882f9997981c88df1a22e140ab41df19071222f7e5fc4e72125"},
+ {file = "rpds_py-0.27.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fd50659a069c15eef8aa3d64bbef0d69fd27bb4a50c9ab4f17f83a16cbf8905"},
+ {file = "rpds_py-0.27.1-cp39-cp39-manylinux_2_31_riscv64.whl", hash = "sha256:c4b676c4ae3921649a15d28ed10025548e9b561ded473aa413af749503c6737e"},
+ {file = "rpds_py-0.27.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:079bc583a26db831a985c5257797b2b5d3affb0386e7ff886256762f82113b5e"},
+ {file = "rpds_py-0.27.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4e44099bd522cba71a2c6b97f68e19f40e7d85399de899d66cdb67b32d7cb786"},
+ {file = "rpds_py-0.27.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e202e6d4188e53c6661af813b46c37ca2c45e497fc558bacc1a7630ec2695aec"},
+ {file = "rpds_py-0.27.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f41f814b8eaa48768d1bb551591f6ba45f87ac76899453e8ccd41dba1289b04b"},
+ {file = "rpds_py-0.27.1-cp39-cp39-win32.whl", hash = "sha256:9e71f5a087ead99563c11fdaceee83ee982fd39cf67601f4fd66cb386336ee52"},
+ {file = "rpds_py-0.27.1-cp39-cp39-win_amd64.whl", hash = "sha256:71108900c9c3c8590697244b9519017a400d9ba26a36c48381b3f64743a44aab"},
+ {file = "rpds_py-0.27.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7ba22cb9693df986033b91ae1d7a979bc399237d45fccf875b76f62bb9e52ddf"},
+ {file = "rpds_py-0.27.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5b640501be9288c77738b5492b3fd3abc4ba95c50c2e41273c8a1459f08298d3"},
+ {file = "rpds_py-0.27.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb08b65b93e0c6dd70aac7f7890a9c0938d5ec71d5cb32d45cf844fb8ae47636"},
+ {file = "rpds_py-0.27.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d7ff07d696a7a38152ebdb8212ca9e5baab56656749f3d6004b34ab726b550b8"},
+ {file = "rpds_py-0.27.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fb7c72262deae25366e3b6c0c0ba46007967aea15d1eea746e44ddba8ec58dcc"},
+ {file = "rpds_py-0.27.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7b002cab05d6339716b03a4a3a2ce26737f6231d7b523f339fa061d53368c9d8"},
+ {file = "rpds_py-0.27.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23f6b69d1c26c4704fec01311963a41d7de3ee0570a84ebde4d544e5a1859ffc"},
+ {file = "rpds_py-0.27.1-pp310-pypy310_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:530064db9146b247351f2a0250b8f00b289accea4596a033e94be2389977de71"},
+ {file = "rpds_py-0.27.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7b90b0496570bd6b0321724a330d8b545827c4df2034b6ddfc5f5275f55da2ad"},
+ {file = "rpds_py-0.27.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:879b0e14a2da6a1102a3fc8af580fc1ead37e6d6692a781bd8c83da37429b5ab"},
+ {file = "rpds_py-0.27.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:0d807710df3b5faa66c731afa162ea29717ab3be17bdc15f90f2d9f183da4059"},
+ {file = "rpds_py-0.27.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:3adc388fc3afb6540aec081fa59e6e0d3908722771aa1e37ffe22b220a436f0b"},
+ {file = "rpds_py-0.27.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c796c0c1cc68cb08b0284db4229f5af76168172670c74908fdbd4b7d7f515819"},
+ {file = "rpds_py-0.27.1-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cdfe4bb2f9fe7458b7453ad3c33e726d6d1c7c0a72960bcc23800d77384e42df"},
+ {file = "rpds_py-0.27.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:8fabb8fd848a5f75a2324e4a84501ee3a5e3c78d8603f83475441866e60b94a3"},
+ {file = "rpds_py-0.27.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eda8719d598f2f7f3e0f885cba8646644b55a187762bec091fa14a2b819746a9"},
+ {file = "rpds_py-0.27.1-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c64d07e95606ec402a0a1c511fe003873fa6af630bda59bac77fac8b4318ebc"},
+ {file = "rpds_py-0.27.1-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:93a2ed40de81bcff59aabebb626562d48332f3d028ca2036f1d23cbb52750be4"},
+ {file = "rpds_py-0.27.1-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:387ce8c44ae94e0ec50532d9cb0edce17311024c9794eb196b90e1058aadeb66"},
+ {file = "rpds_py-0.27.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aaf94f812c95b5e60ebaf8bfb1898a7d7cb9c1af5744d4a67fa47796e0465d4e"},
+ {file = "rpds_py-0.27.1-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:4848ca84d6ded9b58e474dfdbad4b8bfb450344c0551ddc8d958bf4b36aa837c"},
+ {file = "rpds_py-0.27.1-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2bde09cbcf2248b73c7c323be49b280180ff39fadcfe04e7b6f54a678d02a7cf"},
+ {file = "rpds_py-0.27.1-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:94c44ee01fd21c9058f124d2d4f0c9dc7634bec93cd4b38eefc385dabe71acbf"},
+ {file = "rpds_py-0.27.1-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:df8b74962e35c9249425d90144e721eed198e6555a0e22a563d29fe4486b51f6"},
+ {file = "rpds_py-0.27.1-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:dc23e6820e3b40847e2f4a7726462ba0cf53089512abe9ee16318c366494c17a"},
+ {file = "rpds_py-0.27.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:aa8933159edc50be265ed22b401125c9eebff3171f570258854dbce3ecd55475"},
+ {file = "rpds_py-0.27.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a50431bf02583e21bf273c71b89d710e7a710ad5e39c725b14e685610555926f"},
+ {file = "rpds_py-0.27.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78af06ddc7fe5cc0e967085a9115accee665fb912c22a3f54bad70cc65b05fe6"},
+ {file = "rpds_py-0.27.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:70d0738ef8fee13c003b100c2fbd667ec4f133468109b3472d249231108283a3"},
+ {file = "rpds_py-0.27.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2f6fd8a1cea5bbe599b6e78a6e5ee08db434fc8ffea51ff201c8765679698b3"},
+ {file = "rpds_py-0.27.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8177002868d1426305bb5de1e138161c2ec9eb2d939be38291d7c431c4712df8"},
+ {file = "rpds_py-0.27.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:008b839781d6c9bf3b6a8984d1d8e56f0ec46dc56df61fd669c49b58ae800400"},
+ {file = "rpds_py-0.27.1-pp39-pypy39_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:a55b9132bb1ade6c734ddd2759c8dc132aa63687d259e725221f106b83a0e485"},
+ {file = "rpds_py-0.27.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a46fdec0083a26415f11d5f236b79fa1291c32aaa4a17684d82f7017a1f818b1"},
+ {file = "rpds_py-0.27.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:8a63b640a7845f2bdd232eb0d0a4a2dd939bcdd6c57e6bb134526487f3160ec5"},
+ {file = "rpds_py-0.27.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:7e32721e5d4922deaaf963469d795d5bde6093207c52fec719bd22e5d1bedbc4"},
+ {file = "rpds_py-0.27.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:2c426b99a068601b5f4623573df7a7c3d72e87533a2dd2253353a03e7502566c"},
+ {file = "rpds_py-0.27.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:4fc9b7fe29478824361ead6e14e4f5aed570d477e06088826537e202d25fe859"},
+ {file = "rpds_py-0.27.1.tar.gz", hash = "sha256:26a1c73171d10b7acccbded82bf6a586ab8203601e565badc74bbbf8bc5a10f8"},
+]
+
[[package]]
name = "ruff"
version = "0.12.12"
@@ -1927,4 +2251,4 @@ dev = ["black (>=19.3b0) ; python_version >= \"3.6\"", "pytest (>=4.6.2)"]
[metadata]
lock-version = "2.1"
python-versions = "^3.13"
-content-hash = "01523761e407eb4721a6ac25255a75913ec9eb170901cd8ad47a4dc31857fef4"
+content-hash = "9049da9f95908d67870adae3eb3a34cf3f62f9d7008f82d36958cc7dabfc4ab2"
diff --git a/pyproject.toml b/pyproject.toml
index 4dfd014..7306c4a 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -20,6 +20,7 @@ cookiecutter = "^2.6.0"
graphviz = "^0.21"
ipykernel = "^6.30.1"
isort = "^6.0.1"
+jupytext = "^1.16.6"
mypy = "^1.17.1"
nbqa = "^1.9.1"
pre-commit = "^4.3.0"
diff --git a/scripts/shared b/scripts/shared
index d6e9580..0216476 160000
--- a/scripts/shared
+++ b/scripts/shared
@@ -1 +1 @@
-Subproject commit d6e9580673bd0b1b6908add1fc721ad6e3489f7f
+Subproject commit 021647623d9d0304e3e1004e34c766b987f79a25
diff --git a/sonar-project.properties b/sonar-project.properties
index cb6e2c2..bdfd507 100644
--- a/sonar-project.properties
+++ b/sonar-project.properties
@@ -8,7 +8,7 @@ sonar.projectVersion=1.0
sonar.sources=leetcode,leetcode_py
sonar.tests=leetcode
sonar.test.inclusions=**/tests.py
-sonar.exclusions=**/conftest.py,**/.templates/**,**/__pycache__/**,**/.venv/**
+sonar.exclusions=**/conftest.py,**/.templates/**,**/__pycache__/**,**/.venv/**,**/playground.py
# Python specific settings
sonar.python.version=3.13
From af405d8b258e141b9466a15792af481753045f67 Mon Sep 17 00:00:00 2001
From: Wisaroot <66859294+wisarootl@users.noreply.github.com>
Date: Sat, 13 Sep 2025 11:08:49 +0700
Subject: [PATCH 04/58] feat: add find_all_anagrams_in_a_string (#38)
---
.amazonq/rules/development-rules.md | 14 ++
.amazonq/rules/test-case-enhancement.md | 16 +-
.pre-commit-config.yaml | 2 +-
.templates/leetcode/json/accounts_merge.json | 71 +++++---
...e_from_preorder_and_inorder_traversal.json | 62 +++++++
.../leetcode/json/diagonal_traverse.json | 62 +++++++
.../json/find_all_anagrams_in_a_string.json | 64 +++++++
...letter_combinations_of_a_phone_number.json | 63 +++++++
.templates/leetcode/json/subsets.json | 62 +++++++
.templates/leetcode/json/unique_paths.json | 64 +++++++
.templates/leetcode/json/word_search.json | 67 +++++++
Makefile | 2 +-
leetcode/accounts_merge/README.md | 14 +-
leetcode/accounts_merge/test_solution.py | 71 ++++----
.../README.md | 39 ++++
.../__init__.py | 0
.../helpers.py | 12 ++
.../playground.py | 30 ++++
.../solution.py | 59 ++++++
.../test_solution.py | 41 +++++
leetcode/diagonal_traverse/README.md | 37 ++++
leetcode/diagonal_traverse/__init__.py | 0
leetcode/diagonal_traverse/helpers.py | 8 +
leetcode/diagonal_traverse/playground.py | 29 +++
leetcode/diagonal_traverse/solution.py | 70 ++++++++
leetcode/diagonal_traverse/test_solution.py | 34 ++++
.../find_all_anagrams_in_a_string/README.md | 43 +++++
.../find_all_anagrams_in_a_string/__init__.py | 0
.../find_all_anagrams_in_a_string/helpers.py | 8 +
.../playground.py | 30 ++++
.../find_all_anagrams_in_a_string/solution.py | 56 ++++++
.../test_solution.py | 33 ++++
.../README.md | 43 +++++
.../__init__.py | 0
.../helpers.py | 10 ++
.../playground.py | 29 +++
.../solution.py | 31 ++++
.../test_solution.py | 169 ++++++++++++++++++
leetcode/subsets/README.md | 35 ++++
leetcode/subsets/__init__.py | 0
leetcode/subsets/helpers.py | 11 ++
leetcode/subsets/playground.py | 29 +++
leetcode/subsets/solution.py | 16 ++
leetcode/subsets/test_solution.py | 53 ++++++
leetcode/unique_paths/README.md | 43 +++++
leetcode/unique_paths/__init__.py | 0
leetcode/unique_paths/helpers.py | 8 +
leetcode/unique_paths/playground.py | 30 ++++
leetcode/unique_paths/solution.py | 29 +++
leetcode/unique_paths/test_solution.py | 34 ++++
leetcode/word_search/README.md | 52 ++++++
leetcode/word_search/__init__.py | 0
leetcode/word_search/helpers.py | 8 +
leetcode/word_search/playground.py | 30 ++++
leetcode/word_search/solution.py | 42 +++++
leetcode/word_search/test_solution.py | 44 +++++
pyproject.toml | 3 +
57 files changed, 1840 insertions(+), 72 deletions(-)
create mode 100644 .templates/leetcode/json/construct_binary_tree_from_preorder_and_inorder_traversal.json
create mode 100644 .templates/leetcode/json/diagonal_traverse.json
create mode 100644 .templates/leetcode/json/find_all_anagrams_in_a_string.json
create mode 100644 .templates/leetcode/json/letter_combinations_of_a_phone_number.json
create mode 100644 .templates/leetcode/json/subsets.json
create mode 100644 .templates/leetcode/json/unique_paths.json
create mode 100644 .templates/leetcode/json/word_search.json
create mode 100644 leetcode/construct_binary_tree_from_preorder_and_inorder_traversal/README.md
create mode 100644 leetcode/construct_binary_tree_from_preorder_and_inorder_traversal/__init__.py
create mode 100644 leetcode/construct_binary_tree_from_preorder_and_inorder_traversal/helpers.py
create mode 100644 leetcode/construct_binary_tree_from_preorder_and_inorder_traversal/playground.py
create mode 100644 leetcode/construct_binary_tree_from_preorder_and_inorder_traversal/solution.py
create mode 100644 leetcode/construct_binary_tree_from_preorder_and_inorder_traversal/test_solution.py
create mode 100644 leetcode/diagonal_traverse/README.md
create mode 100644 leetcode/diagonal_traverse/__init__.py
create mode 100644 leetcode/diagonal_traverse/helpers.py
create mode 100644 leetcode/diagonal_traverse/playground.py
create mode 100644 leetcode/diagonal_traverse/solution.py
create mode 100644 leetcode/diagonal_traverse/test_solution.py
create mode 100644 leetcode/find_all_anagrams_in_a_string/README.md
create mode 100644 leetcode/find_all_anagrams_in_a_string/__init__.py
create mode 100644 leetcode/find_all_anagrams_in_a_string/helpers.py
create mode 100644 leetcode/find_all_anagrams_in_a_string/playground.py
create mode 100644 leetcode/find_all_anagrams_in_a_string/solution.py
create mode 100644 leetcode/find_all_anagrams_in_a_string/test_solution.py
create mode 100644 leetcode/letter_combinations_of_a_phone_number/README.md
create mode 100644 leetcode/letter_combinations_of_a_phone_number/__init__.py
create mode 100644 leetcode/letter_combinations_of_a_phone_number/helpers.py
create mode 100644 leetcode/letter_combinations_of_a_phone_number/playground.py
create mode 100644 leetcode/letter_combinations_of_a_phone_number/solution.py
create mode 100644 leetcode/letter_combinations_of_a_phone_number/test_solution.py
create mode 100644 leetcode/subsets/README.md
create mode 100644 leetcode/subsets/__init__.py
create mode 100644 leetcode/subsets/helpers.py
create mode 100644 leetcode/subsets/playground.py
create mode 100644 leetcode/subsets/solution.py
create mode 100644 leetcode/subsets/test_solution.py
create mode 100644 leetcode/unique_paths/README.md
create mode 100644 leetcode/unique_paths/__init__.py
create mode 100644 leetcode/unique_paths/helpers.py
create mode 100644 leetcode/unique_paths/playground.py
create mode 100644 leetcode/unique_paths/solution.py
create mode 100644 leetcode/unique_paths/test_solution.py
create mode 100644 leetcode/word_search/README.md
create mode 100644 leetcode/word_search/__init__.py
create mode 100644 leetcode/word_search/helpers.py
create mode 100644 leetcode/word_search/playground.py
create mode 100644 leetcode/word_search/solution.py
create mode 100644 leetcode/word_search/test_solution.py
diff --git a/.amazonq/rules/development-rules.md b/.amazonq/rules/development-rules.md
index aae1892..d7f1080 100644
--- a/.amazonq/rules/development-rules.md
+++ b/.amazonq/rules/development-rules.md
@@ -18,6 +18,20 @@
- Test all: `make test`
- Beautiful logging with loguru
+### Multiple Solution Classes Pattern
+
+When implementing multiple approaches (e.g., Solution, SolutionMath), use parametrized testing:
+
+```python
+@pytest.mark.parametrize("solution_class", [Solution, SolutionMath])
+@pytest.mark.parametrize("input_params, expected", test_cases)
+def test_method(self, solution_class, input_params, expected):
+ result = run_helper(solution_class, *input_params)
+ assert_helper(result, expected)
+```
+
+This pattern tests all solution approaches with the same test cases, ensuring consistency across implementations.
+
## File Structure
Each problem has:
diff --git a/.amazonq/rules/test-case-enhancement.md b/.amazonq/rules/test-case-enhancement.md
index 11b5019..8b341d7 100644
--- a/.amazonq/rules/test-case-enhancement.md
+++ b/.amazonq/rules/test-case-enhancement.md
@@ -2,7 +2,7 @@
## Simple Enhancement Workflow
-When user requests test case enhancement:
+When user requests test case enhancement or **test reproducibility verification**:
### 1. Problem Resolution
@@ -69,6 +69,19 @@ make p-gen PROBLEM={problem_name} FORCE=1
make p-lint PROBLEM={problem_name}
```
+## Test Reproducibility Verification
+
+Use this same workflow when CI tests fail due to reproducibility issues:
+
+**Process Name**: Test Reproducibility Verification
+
+**When to Use**:
+
+- CI test failures in reproducibility checks
+- Inconsistent test results between environments
+- Missing edge cases causing coverage gaps
+- Need to ensure 100% code coverage
+
## Success Criteria
- All tests pass with enhanced test cases
@@ -76,3 +89,4 @@ make p-lint PROBLEM={problem_name}
- Original solution code preserved
- **Enhanced test cases in final test_solution.py**
- JSON template updated for future regeneration
+- **100% code coverage including edge cases**
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 23a8453..f080465 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -23,7 +23,7 @@ repos:
- repo: local
hooks:
- id: sync-submodules
- name: Sync git submodules
+ name: sync git submodules
entry: bash -c 'output=$(git submodule update --init --recursive --remote 2>&1); [ -z "$output" ]'
language: system
always_run: true
diff --git a/.templates/leetcode/json/accounts_merge.json b/.templates/leetcode/json/accounts_merge.json
index bcbddb6..ec92c0d 100644
--- a/.templates/leetcode/json/accounts_merge.json
+++ b/.templates/leetcode/json/accounts_merge.json
@@ -5,47 +5,60 @@
"problem_title": "Accounts Merge",
"difficulty": "Medium",
"topics": "Array, Hash Table, String, Depth-First Search, Breadth-First Search, Union Find, Sorting",
- "tags": ["grind-75"],
- "readme_description": "Given a list of `accounts` where each element `accounts[i]` is a list of strings, where the first element `accounts[i][0]` is a name, and the rest of the elements are **emails** representing emails of the account.\n\nNow, we would like to merge these accounts. Two accounts definitely belong to the same person if there is some common email to both accounts. Note that even if two accounts have the same name, they may belong to different people as people could have the same name. A person can have any number of accounts initially, but all of their accounts definitely have the same name.\n\nAfter merging the accounts, return the accounts in the following format: the first element of each account is the name, and the rest of the elements are emails **in sorted order**. The accounts themselves can be returned in **any order**.",
- "readme_examples": [
- {
- "content": "```\nInput: accounts = [[\"John\",\"johnsmith@mail.com\",\"john_newyork@mail.com\"],[\"John\",\"johnsmith@mail.com\",\"john00@mail.com\"],[\"Mary\",\"mary@mail.com\"],[\"John\",\"johnnybravo@mail.com\"]]\nOutput: [[\"John\",\"john00@mail.com\",\"john_newyork@mail.com\",\"johnsmith@mail.com\"],[\"Mary\",\"mary@mail.com\"],[\"John\",\"johnnybravo@mail.com\"]]\n```\n**Explanation:** The first and second John's are the same person as they have the common email \"johnsmith@mail.com\". The third John and Mary are different people as none of their email addresses are used by other accounts."
- },
- {
- "content": "```\nInput: accounts = [[\"Gabe\",\"Gabe0@m.co\",\"Gabe3@m.co\",\"Gabe1@m.co\"],[\"Kevin\",\"Kevin3@m.co\",\"Kevin5@m.co\",\"Kevin0@m.co\"],[\"Ethan\",\"Ethan5@m.co\",\"Ethan4@m.co\",\"Ethan0@m.co\"],[\"Hanzo\",\"Hanzo3@m.co\",\"Hanzo1@m.co\",\"Hanzo0@m.co\"],[\"Fern\",\"Fern5@m.co\",\"Fern1@m.co\",\"Fern0@m.co\"]]\nOutput: [[\"Ethan\",\"Ethan0@m.co\",\"Ethan4@m.co\",\"Ethan5@m.co\"],[\"Gabe\",\"Gabe0@m.co\",\"Gabe1@m.co\",\"Gabe3@m.co\"],[\"Hanzo\",\"Hanzo0@m.co\",\"Hanzo1@m.co\",\"Hanzo3@m.co\"],[\"Kevin\",\"Kevin0@m.co\",\"Kevin3@m.co\",\"Kevin5@m.co\"],[\"Fern\",\"Fern0@m.co\",\"Fern1@m.co\",\"Fern5@m.co\"]]\n```"
- }
- ],
- "readme_constraints": "- `1 <= accounts.length <= 1000`\n- `2 <= accounts[i].length <= 10`\n- `1 <= accounts[i][j].length <= 30`\n- `accounts[i][0]` consists of English letters.\n- `accounts[i][j] (for j > 0)` is a valid email.",
+ "_tags": { "list": ["grind-75"] },
+ "readme_description": "Given a list of `accounts` where each element `accounts[i]` is a list of strings, where the first element `accounts[i][0]` is a name, and the rest of the elements are emails representing emails of the account.\n\nNow, we would like to merge these accounts. Two accounts definitely belong to the same person if there is some common email to both accounts. Note that even if two accounts have the same name, they may belong to different people as people could have the same name. A person can have any number of accounts initially, but all of their accounts definitely have the same name.\n\nAfter merging the accounts, return the accounts in the following format: the first element of each account is the name, and the rest of the elements are emails in sorted order. The accounts themselves can be returned in any order.",
+ "_readme_examples": {
+ "list": [
+ {
+ "content": "```\nInput: accounts = [[\"John\",\"johnsmith@mail.com\",\"john_newyork@mail.com\"],[\"John\",\"johnsmith@mail.com\",\"john00@mail.com\"],[\"Mary\",\"mary@mail.com\"],[\"John\",\"johnnybravo@mail.com\"]]\nOutput: [[\"John\",\"john00@mail.com\",\"john_newyork@mail.com\",\"johnsmith@mail.com\"],[\"Mary\",\"mary@mail.com\"],[\"John\",\"johnnybravo@mail.com\"]]\n```\n**Explanation:** The first and second John's are the same person as they have the common email \"johnsmith@mail.com\". The third John and Mary are different people as none of their email addresses are used by other accounts."
+ },
+ {
+ "content": "```\nInput: accounts = [[\"Gabe\",\"Gabe0@m.co\",\"Gabe3@m.co\",\"Gabe1@m.co\"],[\"Kevin\",\"Kevin3@m.co\",\"Kevin5@m.co\",\"Kevin0@m.co\"],[\"Ethan\",\"Ethan5@m.co\",\"Ethan4@m.co\",\"Ethan0@m.co\"],[\"Hanzo\",\"Hanzo3@m.co\",\"Hanzo1@m.co\",\"Hanzo0@m.co\"],[\"Fern\",\"Fern5@m.co\",\"Fern1@m.co\",\"Fern0@m.co\"]]\nOutput: [[\"Ethan\",\"Ethan0@m.co\",\"Ethan4@m.co\",\"Ethan5@m.co\"],[\"Gabe\",\"Gabe0@m.co\",\"Gabe1@m.co\",\"Gabe3@m.co\"],[\"Hanzo\",\"Hanzo0@m.co\",\"Hanzo1@m.co\",\"Hanzo3@m.co\"],[\"Kevin\",\"Kevin0@m.co\",\"Kevin3@m.co\",\"Kevin5@m.co\"],[\"Fern\",\"Fern0@m.co\",\"Fern1@m.co\",\"Fern5@m.co\"]]\n```"
+ }
+ ]
+ },
+ "readme_constraints": "- 1 <= accounts.length <= 1000\n- 2 <= accounts[i].length <= 10\n- 1 <= accounts[i][j].length <= 30\n- accounts[i][0] consists of English letters.\n- accounts[i][j] (for j > 0) is a valid email.",
+ "readme_additional": "",
"helpers_imports": "",
+ "helpers_content": "",
"helpers_run_name": "accounts_merge",
"helpers_run_signature": "(solution_class: type, accounts: list[list[str]])",
"helpers_run_body": " implementation = solution_class()\n return implementation.accounts_merge(accounts)",
"helpers_assert_name": "accounts_merge",
"helpers_assert_signature": "(result: list[list[str]], expected: list[list[str]]) -> bool",
"helpers_assert_body": " # Sort both result and expected for comparison since order doesn't matter\n result_sorted = [sorted(account) for account in sorted(result)]\n expected_sorted = [sorted(account) for account in sorted(expected)]\n assert result_sorted == expected_sorted\n return True",
- "solution_methods": [
- {
- "name": "accounts_merge",
- "signature": "(self, accounts: list[list[str]]) -> list[list[str]]",
- "body": " # TODO: Implement accounts_merge\n return []"
- }
- ],
+ "solution_imports": "",
+ "solution_contents": "",
+ "solution_class_content": "",
"test_imports": "import pytest\nfrom leetcode_py.test_utils import logged_test\nfrom .helpers import assert_accounts_merge, run_accounts_merge\nfrom .solution import Solution",
"test_content": "",
"test_class_name": "AccountsMerge",
"test_class_content": " def setup_method(self):\n self.solution = Solution()",
- "test_helper_methods": [],
- "test_methods": [
- {
- "name": "test_accounts_merge",
- "signature": "(self, accounts: list[list[str]], expected: list[list[str]])",
- "parametrize": "accounts, expected",
- "test_cases": "[([[\"John\", \"johnsmith@mail.com\", \"john_newyork@mail.com\"], [\"John\", \"johnsmith@mail.com\", \"john00@mail.com\"], [\"Mary\", \"mary@mail.com\"], [\"John\", \"johnnybravo@mail.com\"]], [[\"John\", \"john00@mail.com\", \"john_newyork@mail.com\", \"johnsmith@mail.com\"], [\"Mary\", \"mary@mail.com\"], [\"John\", \"johnnybravo@mail.com\"]]), ([[\"Gabe\", \"Gabe0@m.co\", \"Gabe3@m.co\", \"Gabe1@m.co\"], [\"Kevin\", \"Kevin3@m.co\", \"Kevin5@m.co\", \"Kevin0@m.co\"], [\"Ethan\", \"Ethan5@m.co\", \"Ethan4@m.co\", \"Ethan0@m.co\"], [\"Hanzo\", \"Hanzo3@m.co\", \"Hanzo1@m.co\", \"Hanzo0@m.co\"], [\"Fern\", \"Fern5@m.co\", \"Fern1@m.co\", \"Fern0@m.co\"]], [[\"Ethan\", \"Ethan0@m.co\", \"Ethan4@m.co\", \"Ethan5@m.co\"], [\"Gabe\", \"Gabe0@m.co\", \"Gabe1@m.co\", \"Gabe3@m.co\"], [\"Hanzo\", \"Hanzo0@m.co\", \"Hanzo1@m.co\", \"Hanzo3@m.co\"], [\"Kevin\", \"Kevin0@m.co\", \"Kevin3@m.co\", \"Kevin5@m.co\"], [\"Fern\", \"Fern0@m.co\", \"Fern1@m.co\", \"Fern5@m.co\"]]), ([[\"John\", \"john@mail.com\"]], [[\"John\", \"john@mail.com\"]]), ([[\"John\", \"john1@mail.com\"], [\"John\", \"john2@mail.com\"], [\"John\", \"john3@mail.com\"]], [[\"John\", \"john1@mail.com\"], [\"John\", \"john2@mail.com\"], [\"John\", \"john3@mail.com\"]]), ([[\"John\", \"a@mail.com\", \"b@mail.com\"], [\"John\", \"b@mail.com\", \"c@mail.com\"], [\"John\", \"d@mail.com\"]], [[\"John\", \"a@mail.com\", \"b@mail.com\", \"c@mail.com\"], [\"John\", \"d@mail.com\"]]), ([[\"Alice\", \"alice@mail.com\", \"alice1@mail.com\"], [\"Alice\", \"alice2@mail.com\", \"alice3@mail.com\"], [\"Alice\", \"alice1@mail.com\", \"alice2@mail.com\"]], [[\"Alice\", \"alice1@mail.com\", \"alice2@mail.com\", \"alice3@mail.com\", \"alice@mail.com\"]]), ([[\"Bob\", \"bob@mail.com\"], [\"Bob\", \"bob@mail.com\"]], [[\"Bob\", \"bob@mail.com\"]]), ([[\"David\", \"david1@mail.com\", \"david2@mail.com\"], [\"David\", \"david3@mail.com\"], [\"David\", \"david2@mail.com\", \"david4@mail.com\"]], [[\"David\", \"david1@mail.com\", \"david2@mail.com\", \"david4@mail.com\"], [\"David\", \"david3@mail.com\"]]), ([[\"Alex\", \"alex@mail.com\"], [\"Alex\", \"alex@mail.com\", \"alex2@mail.com\"], [\"Alex\", \"alex3@mail.com\"]], [[\"Alex\", \"alex2@mail.com\", \"alex@mail.com\"], [\"Alex\", \"alex3@mail.com\"]]), ([[\"Tom\", \"tom1@mail.com\"], [\"Tom\", \"tom2@mail.com\"], [\"Tom\", \"tom3@mail.com\"], [\"Tom\", \"tom4@mail.com\"]], [[\"Tom\", \"tom1@mail.com\"], [\"Tom\", \"tom2@mail.com\"], [\"Tom\", \"tom3@mail.com\"], [\"Tom\", \"tom4@mail.com\"]]), ([[\"Sam\", \"sam@mail.com\", \"sam1@mail.com\", \"sam2@mail.com\"]], [[\"Sam\", \"sam@mail.com\", \"sam1@mail.com\", \"sam2@mail.com\"]])]",
- "body": " result = run_accounts_merge(Solution, accounts)\n assert_accounts_merge(result, expected)"
- }
- ],
+ "_solution_methods": {
+ "list": [
+ {
+ "name": "accounts_merge",
+ "signature": "(self, accounts: list[list[str]]) -> list[list[str]]",
+ "body": " # TODO: Implement accounts_merge\n return []"
+ }
+ ]
+ },
+ "_test_helper_methods": {
+ "list": [{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }]
+ },
+ "_test_methods": {
+ "list": [
+ {
+ "name": "test_accounts_merge",
+ "signature": "(self, accounts: list[list[str]], expected: list[list[str]])",
+ "parametrize": "accounts, expected",
+ "test_cases": "[([['John', 'johnsmith@mail.com', 'john_newyork@mail.com'], ['John', 'johnsmith@mail.com', 'john00@mail.com'], ['Mary', 'mary@mail.com'], ['John', 'johnnybravo@mail.com']], [['John', 'john00@mail.com', 'john_newyork@mail.com', 'johnsmith@mail.com'], ['Mary', 'mary@mail.com'], ['John', 'johnnybravo@mail.com']]), ([['Gabe', 'Gabe0@m.co', 'Gabe3@m.co', 'Gabe1@m.co'], ['Kevin', 'Kevin3@m.co', 'Kevin5@m.co', 'Kevin0@m.co'], ['Ethan', 'Ethan5@m.co', 'Ethan4@m.co', 'Ethan0@m.co'], ['Hanzo', 'Hanzo3@m.co', 'Hanzo1@m.co', 'Hanzo0@m.co'], ['Fern', 'Fern5@m.co', 'Fern1@m.co', 'Fern0@m.co']], [['Ethan', 'Ethan0@m.co', 'Ethan4@m.co', 'Ethan5@m.co'], ['Gabe', 'Gabe0@m.co', 'Gabe1@m.co', 'Gabe3@m.co'], ['Hanzo', 'Hanzo0@m.co', 'Hanzo1@m.co', 'Hanzo3@m.co'], ['Kevin', 'Kevin0@m.co', 'Kevin3@m.co', 'Kevin5@m.co'], ['Fern', 'Fern0@m.co', 'Fern1@m.co', 'Fern5@m.co']]), ([['Alice', 'alice@mail.com']], [['Alice', 'alice@mail.com']]), ([['Bob', 'bob1@mail.com'], ['Bob', 'bob2@mail.com']], [['Bob', 'bob1@mail.com'], ['Bob', 'bob2@mail.com']]), ([['Alice', 'alice@mail.com', 'alice2@mail.com'], ['Alice', 'alice2@mail.com', 'alice3@mail.com']], [['Alice', 'alice2@mail.com', 'alice3@mail.com', 'alice@mail.com']]), ([['A', 'a@mail.com', 'b@mail.com'], ['B', 'b@mail.com', 'c@mail.com'], ['C', 'c@mail.com', 'd@mail.com']], [['A', 'a@mail.com', 'b@mail.com', 'c@mail.com', 'd@mail.com']]), ([['David', 'david@mail.com'], ['David', 'david@mail.com']], [['David', 'david@mail.com']]), ([['Alex', 'alex1@mail.com'], ['Bob', 'bob1@mail.com'], ['Charlie', 'charlie1@mail.com']], [['Alex', 'alex1@mail.com'], ['Bob', 'bob1@mail.com'], ['Charlie', 'charlie1@mail.com']]), ([['John', 'john1@mail.com', 'john2@mail.com'], ['John', 'john3@mail.com'], ['Jane', 'jane1@mail.com']], [['John', 'john1@mail.com', 'john2@mail.com'], ['John', 'john3@mail.com'], ['Jane', 'jane1@mail.com']]), ([['User', 'user@mail.com', 'user1@mail.com'], ['User', 'user2@mail.com', 'user@mail.com'], ['User', 'user3@mail.com', 'user1@mail.com']], [['User', 'user1@mail.com', 'user2@mail.com', 'user3@mail.com', 'user@mail.com']]), ([['Test', 'test1@mail.com'], ['Test', 'test2@mail.com'], ['Test', 'test1@mail.com', 'test3@mail.com']], [['Test', 'test2@mail.com'], ['Test', 'test1@mail.com', 'test3@mail.com']]), ([['Name', 'a@mail.com', 'b@mail.com', 'c@mail.com'], ['Name', 'd@mail.com', 'e@mail.com'], ['Name', 'c@mail.com', 'f@mail.com']], [['Name', 'd@mail.com', 'e@mail.com'], ['Name', 'a@mail.com', 'b@mail.com', 'c@mail.com', 'f@mail.com']])]",
+ "body": " result = run_accounts_merge(Solution, accounts)\n assert_accounts_merge(result, expected)"
+ }
+ ]
+ },
"playground_imports": "from helpers import run_accounts_merge, assert_accounts_merge\nfrom solution import Solution",
- "playground_setup": "# Example test case\naccounts = [[\"John\", \"johnsmith@mail.com\", \"john_newyork@mail.com\"], [\"John\", \"johnsmith@mail.com\", \"john00@mail.com\"], [\"Mary\", \"mary@mail.com\"], [\"John\", \"johnnybravo@mail.com\"]]\nexpected = [[\"John\", \"john00@mail.com\", \"john_newyork@mail.com\", \"johnsmith@mail.com\"], [\"Mary\", \"mary@mail.com\"], [\"John\", \"johnnybravo@mail.com\"]]",
+ "playground_setup": "# Example test case\naccounts = [['John', 'johnsmith@mail.com', 'john_newyork@mail.com'], ['John', 'johnsmith@mail.com', 'john00@mail.com'], ['Mary', 'mary@mail.com'], ['John', 'johnnybravo@mail.com']]\nexpected = [['John', 'john00@mail.com', 'john_newyork@mail.com', 'johnsmith@mail.com'], ['Mary', 'mary@mail.com'], ['John', 'johnnybravo@mail.com']]",
"playground_run": "result = run_accounts_merge(Solution, accounts)\nresult",
"playground_assert": "assert_accounts_merge(result, expected)"
}
diff --git a/.templates/leetcode/json/construct_binary_tree_from_preorder_and_inorder_traversal.json b/.templates/leetcode/json/construct_binary_tree_from_preorder_and_inorder_traversal.json
new file mode 100644
index 0000000..e7e7716
--- /dev/null
+++ b/.templates/leetcode/json/construct_binary_tree_from_preorder_and_inorder_traversal.json
@@ -0,0 +1,62 @@
+{
+ "problem_name": "construct_binary_tree_from_preorder_and_inorder_traversal",
+ "solution_class_name": "Solution",
+ "problem_number": "105",
+ "problem_title": "Construct Binary Tree from Preorder and Inorder Traversal",
+ "difficulty": "Medium",
+ "topics": "Array, Hash Table, Divide and Conquer, Tree, Binary Tree",
+ "_tags": { "list": ["grind-75"] },
+ "readme_description": "Given two integer arrays `preorder` and `inorder` where `preorder` is the preorder traversal of a binary tree and `inorder` is the inorder traversal of the same tree, construct and return the binary tree.",
+ "_readme_examples": {
+ "list": [
+ {
+ "content": "\n\n```\nInput: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]\nOutput: [3,9,20,null,null,15,7]\n```"
+ },
+ { "content": "```\nInput: preorder = [-1], inorder = [-1]\nOutput: [-1]\n```" }
+ ]
+ },
+ "readme_constraints": "- 1 <= preorder.length <= 3000\n- inorder.length == preorder.length\n- -3000 <= preorder[i], inorder[i] <= 3000\n- preorder and inorder consist of unique values.\n- Each value of inorder also appears in preorder.\n- preorder is guaranteed to be the preorder traversal of the tree.\n- inorder is guaranteed to be the inorder traversal of the tree.",
+ "readme_additional": "",
+ "helpers_imports": "from leetcode_py import TreeNode",
+ "helpers_content": "",
+ "helpers_run_name": "build_tree",
+ "helpers_run_signature": "(solution_class: type, preorder: list[int], inorder: list[int])",
+ "helpers_run_body": " implementation = solution_class()\n return implementation.build_tree(preorder, inorder)",
+ "helpers_assert_name": "build_tree",
+ "helpers_assert_signature": "(result: TreeNode | None, expected_list: list[int | None]) -> bool",
+ "helpers_assert_body": " expected = TreeNode.from_list(expected_list) if expected_list else None\n assert result == expected\n return True",
+ "solution_imports": "from leetcode_py import TreeNode",
+ "solution_contents": "",
+ "solution_class_content": "",
+ "test_imports": "import pytest\nfrom leetcode_py.test_utils import logged_test\nfrom .helpers import assert_build_tree, run_build_tree\nfrom .solution import Solution",
+ "test_content": "",
+ "test_class_name": "ConstructBinaryTreeFromPreorderAndInorderTraversal",
+ "test_class_content": " def setup_method(self):\n self.solution = Solution()",
+ "_solution_methods": {
+ "list": [
+ {
+ "name": "build_tree",
+ "signature": "(self, preorder: list[int], inorder: list[int]) -> TreeNode | None",
+ "body": " # TODO: Implement build_tree\n return None"
+ }
+ ]
+ },
+ "_test_helper_methods": {
+ "list": [{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }]
+ },
+ "_test_methods": {
+ "list": [
+ {
+ "name": "test_build_tree",
+ "signature": "(self, preorder: list[int], inorder: list[int], expected_list: list[int | None])",
+ "parametrize": "preorder, inorder, expected_list",
+ "test_cases": "[([], [], []), ([1], [1], [1]), ([3, 9, 20, 15, 7], [9, 3, 15, 20, 7], [3, 9, 20, None, None, 15, 7]), ([-1], [-1], [-1]), ([1, 2], [2, 1], [1, 2]), ([1, 2], [1, 2], [1, None, 2]), ([1, 2, 3], [2, 1, 3], [1, 2, 3]), ([1, 2, 4, 5, 3, 6], [4, 2, 5, 1, 6, 3], [1, 2, 3, 4, 5, 6]), ([1, 2, 3, 4], [1, 2, 3, 4], [1, None, 2, None, 3, None, 4]), ([4, 3, 2, 1], [1, 2, 3, 4], [4, 3, None, 2, None, 1]), ([10, 5, 1, 7, 40, 50], [1, 5, 7, 10, 40, 50], [10, 5, 40, 1, 7, None, 50]), ([1, 3, 2], [1, 2, 3], [1, None, 3, 2]), ([2, 1, 3], [1, 2, 3], [2, 1, 3]), ([5, 3, 2, 1, 4, 6, 7], [1, 2, 3, 4, 5, 6, 7], [5, 3, 6, 2, 4, None, 7, 1]), ([7, 3, 2, 1, 5, 4, 6, 10, 9, 11], [1, 2, 3, 4, 5, 6, 7, 9, 10, 11], [7, 3, 10, 2, 5, 9, 11, 1, None, 4, 6]), ([-3000, -2999, -2998], [-2998, -2999, -3000], [-3000, -2999, None, -2998])]",
+ "body": " result = run_build_tree(Solution, preorder, inorder)\n assert_build_tree(result, expected_list)"
+ }
+ ]
+ },
+ "playground_imports": "from helpers import run_build_tree, assert_build_tree\nfrom solution import Solution\nfrom leetcode_py import TreeNode",
+ "playground_setup": "# Example test case\npreorder = [3, 9, 20, 15, 7]\ninorder = [9, 3, 15, 20, 7]\nexpected_list = [3, 9, 20, None, None, 15, 7]",
+ "playground_run": "result = run_build_tree(Solution, preorder, inorder)\nresult",
+ "playground_assert": "assert_build_tree(result, expected_list)"
+}
diff --git a/.templates/leetcode/json/diagonal_traverse.json b/.templates/leetcode/json/diagonal_traverse.json
new file mode 100644
index 0000000..df17575
--- /dev/null
+++ b/.templates/leetcode/json/diagonal_traverse.json
@@ -0,0 +1,62 @@
+{
+ "problem_name": "diagonal_traverse",
+ "solution_class_name": "Solution",
+ "problem_number": "498",
+ "problem_title": "Diagonal Traverse",
+ "difficulty": "Medium",
+ "topics": "Array, Matrix, Simulation",
+ "_tags": { "list": [] },
+ "readme_description": "Given an `m x n` matrix `mat`, return *an array of all the elements of the array in a diagonal order*.",
+ "_readme_examples": {
+ "list": [
+ {
+ "content": "\n\n```\nInput: mat = [[1,2,3],[4,5,6],[7,8,9]]\nOutput: [1,2,4,7,5,3,6,8,9]\n```"
+ },
+ { "content": "```\nInput: mat = [[1,2],[3,4]]\nOutput: [1,2,3,4]\n```" }
+ ]
+ },
+ "readme_constraints": "- `m == mat.length`\n- `n == mat[i].length`\n- `1 <= m, n <= 10^4`\n- `1 <= m * n <= 10^4`\n- `-10^5 <= mat[i][j] <= 10^5`",
+ "readme_additional": "",
+ "helpers_imports": "",
+ "helpers_content": "",
+ "helpers_run_name": "find_diagonal_order",
+ "helpers_run_signature": "(solution_class: type, mat: list[list[int]])",
+ "helpers_run_body": " implementation = solution_class()\n return implementation.find_diagonal_order(mat)",
+ "helpers_assert_name": "find_diagonal_order",
+ "helpers_assert_signature": "(result: list[int], expected: list[int]) -> bool",
+ "helpers_assert_body": " assert result == expected\n return True",
+ "solution_imports": "",
+ "solution_contents": "",
+ "solution_class_content": "",
+ "test_imports": "import pytest\nfrom leetcode_py.test_utils import logged_test\nfrom .helpers import assert_find_diagonal_order, run_find_diagonal_order\nfrom .solution import Solution",
+ "test_content": "",
+ "test_class_name": "DiagonalTraverse",
+ "test_class_content": " def setup_method(self):\n self.solution = Solution()",
+ "_solution_methods": {
+ "list": [
+ {
+ "name": "find_diagonal_order",
+ "signature": "(self, mat: list[list[int]]) -> list[int]",
+ "body": " # TODO: Implement find_diagonal_order\n return []"
+ }
+ ]
+ },
+ "_test_helper_methods": {
+ "list": [{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }]
+ },
+ "_test_methods": {
+ "list": [
+ {
+ "name": "test_find_diagonal_order",
+ "signature": "(self, mat: list[list[int]], expected: list[int])",
+ "parametrize": "mat, expected",
+ "test_cases": "[([[1, 2, 3], [4, 5, 6], [7, 8, 9]], [1, 2, 4, 7, 5, 3, 6, 8, 9]), ([[1, 2], [3, 4]], [1, 2, 3, 4]), ([[1]], [1]), ([[1, 2, 3]], [1, 2, 3]), ([[1], [2], [3]], [1, 2, 3]), ([[1, 2, 3, 4], [5, 6, 7, 8]], [1, 2, 5, 6, 3, 4, 7, 8]), ([[1, 2], [3, 4], [5, 6]], [1, 2, 3, 5, 4, 6]), ([[1, 2, 3, 4, 5]], [1, 2, 3, 4, 5]), ([[1], [2], [3], [4], [5]], [1, 2, 3, 4, 5]), ([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]], [1, 2, 5, 9, 6, 3, 4, 7, 10, 11, 8, 12]), ([[-1, 0, 1], [2, -3, 4]], [-1, 0, 2, -3, 1, 4]), ([[100]], [100])]",
+ "body": " result = run_find_diagonal_order(Solution, mat)\n assert_find_diagonal_order(result, expected)"
+ }
+ ]
+ },
+ "playground_imports": "from helpers import run_find_diagonal_order, assert_find_diagonal_order\nfrom solution import Solution",
+ "playground_setup": "# Example test case\nmat = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]\nexpected = [1, 2, 4, 7, 5, 3, 6, 8, 9]",
+ "playground_run": "result = run_find_diagonal_order(Solution, mat)\nresult",
+ "playground_assert": "assert_find_diagonal_order(result, expected)"
+}
diff --git a/.templates/leetcode/json/find_all_anagrams_in_a_string.json b/.templates/leetcode/json/find_all_anagrams_in_a_string.json
new file mode 100644
index 0000000..fa9cd1a
--- /dev/null
+++ b/.templates/leetcode/json/find_all_anagrams_in_a_string.json
@@ -0,0 +1,64 @@
+{
+ "problem_name": "find_all_anagrams_in_a_string",
+ "solution_class_name": "Solution",
+ "problem_number": "438",
+ "problem_title": "Find All Anagrams in a String",
+ "difficulty": "Medium",
+ "topics": "Hash Table, String, Sliding Window",
+ "_tags": { "list": ["grind-75"] },
+ "readme_description": "Given two strings `s` and `p`, return an array of all the start indices of `p`'s anagrams in `s`. You may return the answer in any order.\n\nAn **anagram** is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.",
+ "_readme_examples": {
+ "list": [
+ {
+ "content": "```\nInput: s = \"cbaebabacd\", p = \"abc\"\nOutput: [0,6]\n```\n**Explanation:**\nThe substring with start index = 0 is \"cba\", which is an anagram of \"abc\".\nThe substring with start index = 6 is \"bac\", which is an anagram of \"abc\"."
+ },
+ {
+ "content": "```\nInput: s = \"abab\", p = \"ab\"\nOutput: [0,1,2]\n```\n**Explanation:**\nThe substring with start index = 0 is \"ab\", which is an anagram of \"ab\".\nThe substring with start index = 1 is \"ba\", which is an anagram of \"ab\".\nThe substring with start index = 2 is \"ab\", which is an anagram of \"ab\"."
+ }
+ ]
+ },
+ "readme_constraints": "- 1 <= s.length, p.length <= 3 * 10^4\n- s and p consist of lowercase English letters.",
+ "readme_additional": "",
+ "helpers_imports": "",
+ "helpers_content": "",
+ "helpers_run_name": "find_anagrams",
+ "helpers_run_signature": "(solution_class: type, s: str, p: str)",
+ "helpers_run_body": " implementation = solution_class()\n return implementation.find_anagrams(s, p)",
+ "helpers_assert_name": "find_anagrams",
+ "helpers_assert_signature": "(result: list[int], expected: list[int]) -> bool",
+ "helpers_assert_body": " assert sorted(result) == sorted(expected)\n return True",
+ "solution_imports": "",
+ "solution_contents": "",
+ "solution_class_content": "",
+ "test_imports": "import pytest\nfrom leetcode_py.test_utils import logged_test\nfrom .helpers import assert_find_anagrams, run_find_anagrams\nfrom .solution import Solution",
+ "test_content": "",
+ "test_class_name": "FindAllAnagramsInAString",
+ "test_class_content": " def setup_method(self):\n self.solution = Solution()",
+ "_solution_methods": {
+ "list": [
+ {
+ "name": "find_anagrams",
+ "signature": "(self, s: str, p: str) -> list[int]",
+ "body": " # TODO: Implement find_anagrams\n return []"
+ }
+ ]
+ },
+ "_test_helper_methods": {
+ "list": [{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }]
+ },
+ "_test_methods": {
+ "list": [
+ {
+ "name": "test_find_anagrams",
+ "signature": "(self, s: str, p: str, expected: list[int])",
+ "parametrize": "s, p, expected",
+ "test_cases": "[('cbaebabacd', 'abc', [0, 6]), ('abab', 'ab', [0, 1, 2]), ('a', 'aa', []), ('aa', 'aa', [0]), ('abcdefg', 'xyz', []), ('aab', 'ab', [1]), ('aaab', 'ab', [2]), ('baa', 'aa', [1]), ('abacabad', 'aaab', []), ('ababacb', 'abc', [3, 4]), ('abaacbabc', 'abc', [3, 4, 6]), ('abab', 'abab', [0])]",
+ "body": " result = run_find_anagrams(Solution, s, p)\n assert_find_anagrams(result, expected)"
+ }
+ ]
+ },
+ "playground_imports": "from helpers import run_find_anagrams, assert_find_anagrams\nfrom solution import Solution",
+ "playground_setup": "# Example test case\ns = 'cbaebabacd'\np = 'abc'\nexpected = [0, 6]",
+ "playground_run": "result = run_find_anagrams(Solution, s, p)\nresult",
+ "playground_assert": "assert_find_anagrams(result, expected)"
+}
diff --git a/.templates/leetcode/json/letter_combinations_of_a_phone_number.json b/.templates/leetcode/json/letter_combinations_of_a_phone_number.json
new file mode 100644
index 0000000..990afaf
--- /dev/null
+++ b/.templates/leetcode/json/letter_combinations_of_a_phone_number.json
@@ -0,0 +1,63 @@
+{
+ "problem_name": "letter_combinations_of_a_phone_number",
+ "solution_class_name": "Solution",
+ "problem_number": "17",
+ "problem_title": "Letter Combinations of a Phone Number",
+ "difficulty": "Medium",
+ "topics": "Hash Table, String, Backtracking",
+ "_tags": { "list": ["grind-75"] },
+ "readme_description": "Given a string containing digits from `2-9` inclusive, return all possible letter combinations that the number could represent. Return the answer in **any order**.\n\nA mapping of digits to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters.",
+ "_readme_examples": {
+ "list": [
+ {
+ "content": "\n\n```\nInput: digits = \"23\"\nOutput: [\"ad\",\"ae\",\"af\",\"bd\",\"be\",\"bf\",\"cd\",\"ce\",\"cf\"]\n```"
+ },
+ { "content": "```\nInput: digits = \"\"\nOutput: []\n```" },
+ { "content": "```\nInput: digits = \"2\"\nOutput: [\"a\",\"b\",\"c\"]\n```" }
+ ]
+ },
+ "readme_constraints": "- `0 <= digits.length <= 4`\n- `digits[i]` is a digit in the range `['2', '9']`.",
+ "readme_additional": "",
+ "helpers_imports": "",
+ "helpers_content": "",
+ "helpers_run_name": "letter_combinations",
+ "helpers_run_signature": "(solution_class: type, digits: str)",
+ "helpers_run_body": " implementation = solution_class()\n return implementation.letter_combinations(digits)",
+ "helpers_assert_name": "letter_combinations",
+ "helpers_assert_signature": "(result: list[str], expected: list[str]) -> bool",
+ "helpers_assert_body": " result.sort()\n expected.sort()\n assert result == expected\n return True",
+ "solution_imports": "",
+ "solution_contents": "",
+ "solution_class_content": "",
+ "test_imports": "import pytest\nfrom leetcode_py.test_utils import logged_test\nfrom .helpers import assert_letter_combinations, run_letter_combinations\nfrom .solution import Solution",
+ "test_content": "",
+ "test_class_name": "LetterCombinationsOfAPhoneNumber",
+ "test_class_content": " def setup_method(self):\n self.solution = Solution()",
+ "_solution_methods": {
+ "list": [
+ {
+ "name": "letter_combinations",
+ "signature": "(self, digits: str) -> list[str]",
+ "body": " # TODO: Implement letter_combinations\n return []"
+ }
+ ]
+ },
+ "_test_helper_methods": {
+ "list": [{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }]
+ },
+ "_test_methods": {
+ "list": [
+ {
+ "name": "test_letter_combinations",
+ "signature": "(self, digits: str, expected: list[str])",
+ "parametrize": "digits, expected",
+ "test_cases": "[('23', ['ad', 'ae', 'af', 'bd', 'be', 'bf', 'cd', 'ce', 'cf']), ('', []), ('2', ['a', 'b', 'c']), ('234', ['adg', 'adh', 'adi', 'aeg', 'aeh', 'aei', 'afg', 'afh', 'afi', 'bdg', 'bdh', 'bdi', 'beg', 'beh', 'bei', 'bfg', 'bfh', 'bfi', 'cdg', 'cdh', 'cdi', 'ceg', 'ceh', 'cei', 'cfg', 'cfh', 'cfi']), ('7', ['p', 'q', 'r', 's']), ('9', ['w', 'x', 'y', 'z']), ('79', ['pw', 'px', 'py', 'pz', 'qw', 'qx', 'qy', 'qz', 'rw', 'rx', 'ry', 'rz', 'sw', 'sx', 'sy', 'sz']), ('22', ['aa', 'ab', 'ac', 'ba', 'bb', 'bc', 'ca', 'cb', 'cc']), ('3456', ['dgjm', 'dgjn', 'dgjo', 'dgkm', 'dgkn', 'dgko', 'dglm', 'dgln', 'dglo', 'dhjm', 'dhjn', 'dhjo', 'dhkm', 'dhkn', 'dhko', 'dhlm', 'dhln', 'dhlo', 'dijm', 'dijn', 'dijo', 'dikm', 'dikn', 'diko', 'dilm', 'diln', 'dilo', 'egjm', 'egjn', 'egjo', 'egkm', 'egkn', 'egko', 'eglm', 'egln', 'eglo', 'ehjm', 'ehjn', 'ehjo', 'ehkm', 'ehkn', 'ehko', 'ehlm', 'ehln', 'ehlo', 'eijm', 'eijn', 'eijo', 'eikm', 'eikn', 'eiko', 'eilm', 'eiln', 'eilo', 'fgjm', 'fgjn', 'fgjo', 'fgkm', 'fgkn', 'fgko', 'fglm', 'fgln', 'fglo', 'fhjm', 'fhjn', 'fhjo', 'fhkm', 'fhkn', 'fhko', 'fhlm', 'fhln', 'fhlo', 'fijm', 'fijn', 'fijo', 'fikm', 'fikn', 'fiko', 'film', 'filn', 'filo']), ('25', ['aj', 'ak', 'al', 'bj', 'bk', 'bl', 'cj', 'ck', 'cl']), ('78', ['pt', 'pu', 'pv', 'qt', 'qu', 'qv', 'rt', 'ru', 'rv', 'st', 'su', 'sv']), ('89', ['tw', 'tx', 'ty', 'tz', 'uw', 'ux', 'uy', 'uz', 'vw', 'vx', 'vy', 'vz'])]",
+ "body": " result = run_letter_combinations(Solution, digits)\n assert_letter_combinations(result, expected)"
+ }
+ ]
+ },
+ "playground_imports": "from helpers import run_letter_combinations, assert_letter_combinations\nfrom solution import Solution",
+ "playground_setup": "# Example test case\ndigits = '23'\nexpected = ['ad', 'ae', 'af', 'bd', 'be', 'bf', 'cd', 'ce', 'cf']",
+ "playground_run": "result = run_letter_combinations(Solution, digits)\nresult",
+ "playground_assert": "assert_letter_combinations(result, expected)"
+}
diff --git a/.templates/leetcode/json/subsets.json b/.templates/leetcode/json/subsets.json
new file mode 100644
index 0000000..a30f10a
--- /dev/null
+++ b/.templates/leetcode/json/subsets.json
@@ -0,0 +1,62 @@
+{
+ "problem_name": "subsets",
+ "solution_class_name": "Solution",
+ "problem_number": "78",
+ "problem_title": "Subsets",
+ "difficulty": "Medium",
+ "topics": "Array, Backtracking, Bit Manipulation",
+ "_tags": { "list": ["grind-75"] },
+ "readme_description": "Given an integer array `nums` of **unique** elements, return *all possible* subsets (the power set).\n\nThe solution set **must not** contain duplicate subsets. Return the solution in **any order**.",
+ "_readme_examples": {
+ "list": [
+ {
+ "content": "```\nInput: nums = [1,2,3]\nOutput: [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]\n```"
+ },
+ { "content": "```\nInput: nums = [0]\nOutput: [[],[0]]\n```" }
+ ]
+ },
+ "readme_constraints": "- 1 <= nums.length <= 10\n- -10 <= nums[i] <= 10\n- All the numbers of nums are unique.",
+ "readme_additional": "",
+ "helpers_imports": "",
+ "helpers_content": "",
+ "helpers_run_name": "subsets",
+ "helpers_run_signature": "(solution_class: type, nums: list[int])",
+ "helpers_run_body": " implementation = solution_class()\n return implementation.subsets(nums)",
+ "helpers_assert_name": "subsets",
+ "helpers_assert_signature": "(result: list[list[int]], expected: list[list[int]]) -> bool",
+ "helpers_assert_body": " # Sort both result and expected for comparison since order doesn't matter\n result_sorted = [sorted(subset) for subset in sorted(result)]\n expected_sorted = [sorted(subset) for subset in sorted(expected)]\n assert result_sorted == expected_sorted\n return True",
+ "solution_imports": "",
+ "solution_contents": "",
+ "solution_class_content": "",
+ "test_imports": "import pytest\nfrom leetcode_py.test_utils import logged_test\nfrom .helpers import assert_subsets, run_subsets\nfrom .solution import Solution",
+ "test_content": "",
+ "test_class_name": "Subsets",
+ "test_class_content": " def setup_method(self):\n self.solution = Solution()",
+ "_solution_methods": {
+ "list": [
+ {
+ "name": "subsets",
+ "signature": "(self, nums: list[int]) -> list[list[int]]",
+ "body": " # TODO: Implement subsets\n return []"
+ }
+ ]
+ },
+ "_test_helper_methods": {
+ "list": [{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }]
+ },
+ "_test_methods": {
+ "list": [
+ {
+ "name": "test_subsets",
+ "signature": "(self, nums: list[int], expected: list[list[int]])",
+ "parametrize": "nums, expected",
+ "test_cases": "[([1, 2, 3], [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]), ([0], [[], [0]]), ([1], [[], [1]]), ([1, 2], [[], [1], [2], [1, 2]]), ([4, 1, 0], [[], [4], [4, 1], [4, 1, 0], [4, 0], [1], [1, 0], [0]]), ([-1, 0, 1], [[], [-1], [-1, 0], [-1, 0, 1], [-1, 1], [0], [0, 1], [1]]), ([5], [[], [5]]), ([2, 1, 3], [[], [2], [2, 1], [2, 1, 3], [2, 3], [1], [1, 3], [3]]), ([10], [[], [10]]), ([-10, 10], [[], [-10], [-10, 10], [10]]), ([1, 2, 3, 4], [[], [1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 4], [1, 3], [1, 3, 4], [1, 4], [2], [2, 3], [2, 3, 4], [2, 4], [3], [3, 4], [4]]), ([5, 2], [[], [5], [5, 2], [2]])]",
+ "body": " result = run_subsets(Solution, nums)\n assert_subsets(result, expected)"
+ }
+ ]
+ },
+ "playground_imports": "from helpers import run_subsets, assert_subsets\nfrom solution import Solution",
+ "playground_setup": "# Example test case\nnums = [1, 2, 3]\nexpected = [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]",
+ "playground_run": "result = run_subsets(Solution, nums)\nresult",
+ "playground_assert": "assert_subsets(result, expected)"
+}
diff --git a/.templates/leetcode/json/unique_paths.json b/.templates/leetcode/json/unique_paths.json
new file mode 100644
index 0000000..001900d
--- /dev/null
+++ b/.templates/leetcode/json/unique_paths.json
@@ -0,0 +1,64 @@
+{
+ "problem_name": "unique_paths",
+ "solution_class_name": "Solution",
+ "problem_number": "62",
+ "problem_title": "Unique Paths",
+ "difficulty": "Medium",
+ "topics": "Math, Dynamic Programming, Combinatorics",
+ "_tags": { "list": ["grind-75"] },
+ "readme_description": "There is a robot on an `m x n` grid. The robot is initially located at the **top-left corner** (i.e., `grid[0][0]`). The robot tries to move to the **bottom-right corner** (i.e., `grid[m - 1][n - 1]`). The robot can only move either down or right at any point in time.\n\nGiven the two integers `m` and `n`, return *the number of possible unique paths that the robot can take to reach the bottom-right corner*.\n\nThe test cases are generated so that the answer will be less than or equal to `2 * 10^9`.",
+ "_readme_examples": {
+ "list": [
+ {
+ "content": "\n\n```\nInput: m = 3, n = 7\nOutput: 28\n```"
+ },
+ {
+ "content": "```\nInput: m = 3, n = 2\nOutput: 3\n```\n**Explanation:** From the top-left corner, there are a total of 3 ways to reach the bottom-right corner:\n1. Right -> Down -> Down\n2. Down -> Down -> Right\n3. Down -> Right -> Down"
+ }
+ ]
+ },
+ "readme_constraints": "- 1 <= m, n <= 100",
+ "readme_additional": "",
+ "helpers_imports": "",
+ "helpers_content": "",
+ "helpers_run_name": "unique_paths",
+ "helpers_run_signature": "(solution_class: type, m: int, n: int)",
+ "helpers_run_body": " implementation = solution_class()\n return implementation.unique_paths(m, n)",
+ "helpers_assert_name": "unique_paths",
+ "helpers_assert_signature": "(result: int, expected: int) -> bool",
+ "helpers_assert_body": " assert result == expected\n return True",
+ "solution_imports": "",
+ "solution_contents": "",
+ "solution_class_content": "",
+ "test_imports": "import pytest\nfrom leetcode_py.test_utils import logged_test\nfrom .helpers import assert_unique_paths, run_unique_paths\nfrom .solution import Solution",
+ "test_content": "",
+ "test_class_name": "UniquePaths",
+ "test_class_content": " def setup_method(self):\n self.solution = Solution()",
+ "_solution_methods": {
+ "list": [
+ {
+ "name": "unique_paths",
+ "signature": "(self, m: int, n: int) -> int",
+ "body": " # TODO: Implement unique_paths\n return 0"
+ }
+ ]
+ },
+ "_test_helper_methods": {
+ "list": [{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }]
+ },
+ "_test_methods": {
+ "list": [
+ {
+ "name": "test_unique_paths",
+ "signature": "(self, m: int, n: int, expected: int)",
+ "parametrize": "m, n, expected",
+ "test_cases": "[(3, 7, 28), (3, 2, 3), (1, 1, 1), (1, 10, 1), (10, 1, 1), (2, 2, 2), (3, 3, 6), (4, 4, 20), (5, 5, 70), (2, 3, 3), (3, 4, 10), (4, 5, 35), (6, 3, 21), (7, 3, 28), (10, 10, 48620)]",
+ "body": " result = run_unique_paths(Solution, m, n)\n assert_unique_paths(result, expected)"
+ }
+ ]
+ },
+ "playground_imports": "from helpers import run_unique_paths, assert_unique_paths\nfrom solution import Solution",
+ "playground_setup": "# Example test case\nm = 3\nn = 7\nexpected = 28",
+ "playground_run": "result = run_unique_paths(Solution, m, n)\nresult",
+ "playground_assert": "assert_unique_paths(result, expected)"
+}
diff --git a/.templates/leetcode/json/word_search.json b/.templates/leetcode/json/word_search.json
new file mode 100644
index 0000000..776a490
--- /dev/null
+++ b/.templates/leetcode/json/word_search.json
@@ -0,0 +1,67 @@
+{
+ "problem_name": "word_search",
+ "solution_class_name": "Solution",
+ "problem_number": "79",
+ "problem_title": "Word Search",
+ "difficulty": "Medium",
+ "topics": "Array, String, Backtracking, Depth-First Search, Matrix",
+ "_tags": { "list": ["grind-75"] },
+ "readme_description": "Given an `m x n` grid of characters `board` and a string `word`, return `true` *if* `word` *exists in the grid*.\n\nThe word can be constructed from letters of sequentially adjacent cells, where adjacent cells are horizontally or vertically neighboring. The same letter cell may not be used more than once.",
+ "_readme_examples": {
+ "list": [
+ {
+ "content": "\n\n```\nInput: board = [[\"A\",\"B\",\"C\",\"E\"],[\"S\",\"F\",\"C\",\"S\"],[\"A\",\"D\",\"E\",\"E\"]], word = \"ABCCED\"\nOutput: true\n```"
+ },
+ {
+ "content": "\n\n```\nInput: board = [[\"A\",\"B\",\"C\",\"E\"],[\"S\",\"F\",\"C\",\"S\"],[\"A\",\"D\",\"E\",\"E\"]], word = \"SEE\"\nOutput: true\n```"
+ },
+ {
+ "content": "\n\n```\nInput: board = [[\"A\",\"B\",\"C\",\"E\"],[\"S\",\"F\",\"C\",\"S\"],[\"A\",\"D\",\"E\",\"E\"]], word = \"ABCB\"\nOutput: false\n```"
+ }
+ ]
+ },
+ "readme_constraints": "- `m == board.length`\n- `n = board[i].length`\n- `1 <= m, n <= 6`\n- `1 <= word.length <= 15`\n- `board` and `word` consists of only lowercase and uppercase English letters.",
+ "readme_additional": "**Follow up:** Could you use search pruning to make your solution faster with a larger `board`?",
+ "helpers_imports": "",
+ "helpers_content": "",
+ "helpers_run_name": "exist",
+ "helpers_run_signature": "(solution_class: type, board: list[list[str]], word: str)",
+ "helpers_run_body": " implementation = solution_class()\n return implementation.exist(board, word)",
+ "helpers_assert_name": "exist",
+ "helpers_assert_signature": "(result: bool, expected: bool) -> bool",
+ "helpers_assert_body": " assert result == expected\n return True",
+ "solution_imports": "",
+ "solution_contents": "",
+ "solution_class_content": "",
+ "test_imports": "import pytest\nfrom leetcode_py.test_utils import logged_test\nfrom .helpers import assert_exist, run_exist\nfrom .solution import Solution",
+ "test_content": "",
+ "test_class_name": "WordSearch",
+ "test_class_content": " def setup_method(self):\n self.solution = Solution()",
+ "_solution_methods": {
+ "list": [
+ {
+ "name": "exist",
+ "signature": "(self, board: list[list[str]], word: str) -> bool",
+ "body": " # TODO: Implement exist\n return False"
+ }
+ ]
+ },
+ "_test_helper_methods": {
+ "list": [{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }]
+ },
+ "_test_methods": {
+ "list": [
+ {
+ "name": "test_exist",
+ "signature": "(self, board: list[list[str]], word: str, expected: bool)",
+ "parametrize": "board, word, expected",
+ "test_cases": "[([['A', 'B', 'C', 'E'], ['S', 'F', 'C', 'S'], ['A', 'D', 'E', 'E']], 'ABCCED', True), ([['A', 'B', 'C', 'E'], ['S', 'F', 'C', 'S'], ['A', 'D', 'E', 'E']], 'SEE', True), ([['A', 'B', 'C', 'E'], ['S', 'F', 'C', 'S'], ['A', 'D', 'E', 'E']], 'ABCB', False), ([['A']], 'A', True), ([['A']], 'B', False), ([['A', 'B'], ['C', 'D']], 'ACDB', True), ([['A', 'B'], ['C', 'D']], 'ABDC', True), ([['A', 'B'], ['C', 'D']], 'ABCD', False), ([['C', 'A', 'A'], ['A', 'A', 'A'], ['B', 'C', 'D']], 'AAB', True), ([['A', 'B', 'C', 'E'], ['S', 'F', 'C', 'S'], ['A', 'D', 'E', 'E']], 'ABCESEEEFS', False), ([['A', 'A', 'A', 'A', 'A', 'A'], ['A', 'A', 'A', 'A', 'A', 'A'], ['A', 'A', 'A', 'A', 'A', 'A'], ['A', 'A', 'A', 'A', 'A', 'A'], ['A', 'A', 'A', 'A', 'A', 'A'], ['A', 'A', 'A', 'A', 'A', 'A']], 'AAAAAAAAAAAAAAB', False), ([['A', 'B', 'C', 'E'], ['S', 'F', 'C', 'S'], ['A', 'D', 'E', 'E']], 'SFCS', True)]",
+ "body": " result = run_exist(Solution, board, word)\n assert_exist(result, expected)"
+ }
+ ]
+ },
+ "playground_imports": "from helpers import run_exist, assert_exist\nfrom solution import Solution",
+ "playground_setup": "# Example test case\nboard = [['A', 'B', 'C', 'E'], ['S', 'F', 'C', 'S'], ['A', 'D', 'E', 'E']]\nword = 'ABCCED'\nexpected = True",
+ "playground_run": "result = run_exist(Solution, board, word)\nresult",
+ "playground_assert": "assert_exist(result, expected)"
+}
diff --git a/Makefile b/Makefile
index 377ff6d..c6eeb6a 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
PYTHON_VERSION = 3.13
-PROBLEM ?= two_sum
+PROBLEM ?= find_all_anagrams_in_a_string
FORCE ?= 0
COMMA := ,
diff --git a/leetcode/accounts_merge/README.md b/leetcode/accounts_merge/README.md
index 53a64a3..dd3f61e 100644
--- a/leetcode/accounts_merge/README.md
+++ b/leetcode/accounts_merge/README.md
@@ -8,11 +8,11 @@
## Problem Description
-Given a list of `accounts` where each element `accounts[i]` is a list of strings, where the first element `accounts[i][0]` is a name, and the rest of the elements are **emails** representing emails of the account.
+Given a list of `accounts` where each element `accounts[i]` is a list of strings, where the first element `accounts[i][0]` is a name, and the rest of the elements are emails representing emails of the account.
Now, we would like to merge these accounts. Two accounts definitely belong to the same person if there is some common email to both accounts. Note that even if two accounts have the same name, they may belong to different people as people could have the same name. A person can have any number of accounts initially, but all of their accounts definitely have the same name.
-After merging the accounts, return the accounts in the following format: the first element of each account is the name, and the rest of the elements are emails **in sorted order**. The accounts themselves can be returned in **any order**.
+After merging the accounts, return the accounts in the following format: the first element of each account is the name, and the rest of the elements are emails in sorted order. The accounts themselves can be returned in any order.
## Examples
@@ -34,8 +34,8 @@ Output: [["Ethan","Ethan0@m.co","Ethan4@m.co","Ethan5@m.co"],["Gabe","Gabe0@m.co
## Constraints
-- `1 <= accounts.length <= 1000`
-- `2 <= accounts[i].length <= 10`
-- `1 <= accounts[i][j].length <= 30`
-- `accounts[i][0]` consists of English letters.
-- `accounts[i][j] (for j > 0)` is a valid email.
+- 1 <= accounts.length <= 1000
+- 2 <= accounts[i].length <= 10
+- 1 <= accounts[i][j].length <= 30
+- accounts[i][0] consists of English letters.
+- accounts[i][j] (for j > 0) is a valid email.
diff --git a/leetcode/accounts_merge/test_solution.py b/leetcode/accounts_merge/test_solution.py
index fc73296..8f18c66 100644
--- a/leetcode/accounts_merge/test_solution.py
+++ b/leetcode/accounts_merge/test_solution.py
@@ -43,64 +43,69 @@ def setup_method(self):
["Fern", "Fern0@m.co", "Fern1@m.co", "Fern5@m.co"],
],
),
- ([["John", "john@mail.com"]], [["John", "john@mail.com"]]),
+ ([["Alice", "alice@mail.com"]], [["Alice", "alice@mail.com"]]),
(
- [["John", "john1@mail.com"], ["John", "john2@mail.com"], ["John", "john3@mail.com"]],
- [["John", "john1@mail.com"], ["John", "john2@mail.com"], ["John", "john3@mail.com"]],
+ [["Bob", "bob1@mail.com"], ["Bob", "bob2@mail.com"]],
+ [["Bob", "bob1@mail.com"], ["Bob", "bob2@mail.com"]],
),
(
[
- ["John", "a@mail.com", "b@mail.com"],
- ["John", "b@mail.com", "c@mail.com"],
- ["John", "d@mail.com"],
+ ["Alice", "alice@mail.com", "alice2@mail.com"],
+ ["Alice", "alice2@mail.com", "alice3@mail.com"],
],
- [["John", "a@mail.com", "b@mail.com", "c@mail.com"], ["John", "d@mail.com"]],
+ [["Alice", "alice2@mail.com", "alice3@mail.com", "alice@mail.com"]],
),
(
[
- ["Alice", "alice@mail.com", "alice1@mail.com"],
- ["Alice", "alice2@mail.com", "alice3@mail.com"],
- ["Alice", "alice1@mail.com", "alice2@mail.com"],
+ ["A", "a@mail.com", "b@mail.com"],
+ ["B", "b@mail.com", "c@mail.com"],
+ ["C", "c@mail.com", "d@mail.com"],
],
- [["Alice", "alice1@mail.com", "alice2@mail.com", "alice3@mail.com", "alice@mail.com"]],
+ [["A", "a@mail.com", "b@mail.com", "c@mail.com", "d@mail.com"]],
+ ),
+ ([["David", "david@mail.com"], ["David", "david@mail.com"]], [["David", "david@mail.com"]]),
+ (
+ [["Alex", "alex1@mail.com"], ["Bob", "bob1@mail.com"], ["Charlie", "charlie1@mail.com"]],
+ [["Alex", "alex1@mail.com"], ["Bob", "bob1@mail.com"], ["Charlie", "charlie1@mail.com"]],
),
- ([["Bob", "bob@mail.com"], ["Bob", "bob@mail.com"]], [["Bob", "bob@mail.com"]]),
(
[
- ["David", "david1@mail.com", "david2@mail.com"],
- ["David", "david3@mail.com"],
- ["David", "david2@mail.com", "david4@mail.com"],
+ ["John", "john1@mail.com", "john2@mail.com"],
+ ["John", "john3@mail.com"],
+ ["Jane", "jane1@mail.com"],
],
[
- ["David", "david1@mail.com", "david2@mail.com", "david4@mail.com"],
- ["David", "david3@mail.com"],
+ ["John", "john1@mail.com", "john2@mail.com"],
+ ["John", "john3@mail.com"],
+ ["Jane", "jane1@mail.com"],
],
),
(
[
- ["Alex", "alex@mail.com"],
- ["Alex", "alex@mail.com", "alex2@mail.com"],
- ["Alex", "alex3@mail.com"],
+ ["User", "user@mail.com", "user1@mail.com"],
+ ["User", "user2@mail.com", "user@mail.com"],
+ ["User", "user3@mail.com", "user1@mail.com"],
],
- [["Alex", "alex2@mail.com", "alex@mail.com"], ["Alex", "alex3@mail.com"]],
+ [["User", "user1@mail.com", "user2@mail.com", "user3@mail.com", "user@mail.com"]],
),
(
[
- ["Tom", "tom1@mail.com"],
- ["Tom", "tom2@mail.com"],
- ["Tom", "tom3@mail.com"],
- ["Tom", "tom4@mail.com"],
- ],
- [
- ["Tom", "tom1@mail.com"],
- ["Tom", "tom2@mail.com"],
- ["Tom", "tom3@mail.com"],
- ["Tom", "tom4@mail.com"],
+ ["Test", "test1@mail.com"],
+ ["Test", "test2@mail.com"],
+ ["Test", "test1@mail.com", "test3@mail.com"],
],
+ [["Test", "test2@mail.com"], ["Test", "test1@mail.com", "test3@mail.com"]],
),
(
- [["Sam", "sam@mail.com", "sam1@mail.com", "sam2@mail.com"]],
- [["Sam", "sam@mail.com", "sam1@mail.com", "sam2@mail.com"]],
+ [
+ ["Name", "a@mail.com", "b@mail.com", "c@mail.com"],
+ ["Name", "d@mail.com", "e@mail.com"],
+ ["Name", "c@mail.com", "f@mail.com"],
+ ],
+ [
+ ["Name", "d@mail.com", "e@mail.com"],
+ ["Name", "a@mail.com", "b@mail.com", "c@mail.com", "f@mail.com"],
+ ],
),
],
)
diff --git a/leetcode/construct_binary_tree_from_preorder_and_inorder_traversal/README.md b/leetcode/construct_binary_tree_from_preorder_and_inorder_traversal/README.md
new file mode 100644
index 0000000..1fff676
--- /dev/null
+++ b/leetcode/construct_binary_tree_from_preorder_and_inorder_traversal/README.md
@@ -0,0 +1,39 @@
+# Construct Binary Tree from Preorder and Inorder Traversal
+
+**Difficulty:** Medium
+**Topics:** Array, Hash Table, Divide and Conquer, Tree, Binary Tree
+**Tags:** grind-75
+
+**LeetCode:** [Problem 105](https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/description/)
+
+## Problem Description
+
+Given two integer arrays `preorder` and `inorder` where `preorder` is the preorder traversal of a binary tree and `inorder` is the inorder traversal of the same tree, construct and return the binary tree.
+
+## Examples
+
+### Example 1:
+
+
+
+```
+Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
+Output: [3,9,20,null,null,15,7]
+```
+
+### Example 2:
+
+```
+Input: preorder = [-1], inorder = [-1]
+Output: [-1]
+```
+
+## Constraints
+
+- 1 <= preorder.length <= 3000
+- inorder.length == preorder.length
+- -3000 <= preorder[i], inorder[i] <= 3000
+- preorder and inorder consist of unique values.
+- Each value of inorder also appears in preorder.
+- preorder is guaranteed to be the preorder traversal of the tree.
+- inorder is guaranteed to be the inorder traversal of the tree.
diff --git a/leetcode/construct_binary_tree_from_preorder_and_inorder_traversal/__init__.py b/leetcode/construct_binary_tree_from_preorder_and_inorder_traversal/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/leetcode/construct_binary_tree_from_preorder_and_inorder_traversal/helpers.py b/leetcode/construct_binary_tree_from_preorder_and_inorder_traversal/helpers.py
new file mode 100644
index 0000000..10c4f04
--- /dev/null
+++ b/leetcode/construct_binary_tree_from_preorder_and_inorder_traversal/helpers.py
@@ -0,0 +1,12 @@
+from leetcode_py import TreeNode
+
+
+def run_build_tree(solution_class: type, preorder: list[int], inorder: list[int]):
+ implementation = solution_class()
+ return implementation.build_tree(preorder, inorder)
+
+
+def assert_build_tree(result: TreeNode | None, expected_list: list[int | None]) -> bool:
+ expected = TreeNode.from_list(expected_list) if expected_list else None
+ assert result == expected
+ return True
diff --git a/leetcode/construct_binary_tree_from_preorder_and_inorder_traversal/playground.py b/leetcode/construct_binary_tree_from_preorder_and_inorder_traversal/playground.py
new file mode 100644
index 0000000..fa4baf4
--- /dev/null
+++ b/leetcode/construct_binary_tree_from_preorder_and_inorder_traversal/playground.py
@@ -0,0 +1,30 @@
+# ---
+# 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_build_tree, run_build_tree
+from solution import Solution
+
+# %%
+# Example test case
+preorder = [3, 9, 20, 15, 7]
+inorder = [9, 3, 15, 20, 7]
+expected_list = [3, 9, 20, None, None, 15, 7]
+
+# %%
+result = run_build_tree(Solution, preorder, inorder)
+result
+
+# %%
+assert_build_tree(result, expected_list)
diff --git a/leetcode/construct_binary_tree_from_preorder_and_inorder_traversal/solution.py b/leetcode/construct_binary_tree_from_preorder_and_inorder_traversal/solution.py
new file mode 100644
index 0000000..8dce67c
--- /dev/null
+++ b/leetcode/construct_binary_tree_from_preorder_and_inorder_traversal/solution.py
@@ -0,0 +1,59 @@
+from leetcode_py import TreeNode
+
+
+class Solution:
+ """
+ Construct Binary Tree from Preorder and Inorder Traversal
+
+ Algorithm Explanation:
+ - Preorder: Root -> Left -> Right (first element is always root)
+ - Inorder: Left -> Root -> Right (root splits left/right subtrees)
+
+ Example: preorder=[3,9,20,15,7], inorder=[9,3,15,20,7]
+
+ Step 1: Root = 3 (first in preorder)
+ Find 3 in inorder at index 1
+ Left subtree: inorder[0:1] = [9]
+ Right subtree: inorder[2:] = [15,20,7]
+
+ Step 2: Build left subtree with preorder=[9], inorder=[9]
+ Root = 9, no children
+
+ Step 3: Build right subtree with preorder=[20,15,7], inorder=[15,20,7]
+ Root = 20, left=[15], right=[7]
+
+ Final tree:
+ 3
+ / \
+ 9 20
+ / \
+ 15 7
+ """
+
+ # Time: O(n) - hashmap lookup O(1) for each of n nodes
+ # Space: O(n) - hashmap + recursion stack
+ def build_tree(self, preorder: list[int], inorder: list[int]) -> TreeNode | None:
+ if not preorder or not inorder:
+ return None
+
+ inorder_map = {val: i for i, val in enumerate(inorder)}
+ self.preorder_index = 0
+
+ def build(left: int, right: int) -> TreeNode | None:
+ # left, right: boundaries in inorder array for current subtree
+ if left > right:
+ return None
+
+ root_val = preorder[self.preorder_index]
+ self.preorder_index += 1
+ root = TreeNode(root_val)
+
+ mid = inorder_map[root_val] # root position in inorder
+ # Left subtree: inorder[left:mid-1]
+ root.left = build(left, mid - 1)
+ # Right subtree: inorder[mid+1:right]
+ root.right = build(mid + 1, right)
+
+ return root
+
+ return build(0, len(inorder) - 1)
diff --git a/leetcode/construct_binary_tree_from_preorder_and_inorder_traversal/test_solution.py b/leetcode/construct_binary_tree_from_preorder_and_inorder_traversal/test_solution.py
new file mode 100644
index 0000000..5f08fe6
--- /dev/null
+++ b/leetcode/construct_binary_tree_from_preorder_and_inorder_traversal/test_solution.py
@@ -0,0 +1,41 @@
+import pytest
+
+from leetcode_py.test_utils import logged_test
+
+from .helpers import assert_build_tree, run_build_tree
+from .solution import Solution
+
+
+class TestConstructBinaryTreeFromPreorderAndInorderTraversal:
+ def setup_method(self):
+ self.solution = Solution()
+
+ @logged_test
+ @pytest.mark.parametrize(
+ "preorder, inorder, expected_list",
+ [
+ ([], [], []),
+ ([1], [1], [1]),
+ ([3, 9, 20, 15, 7], [9, 3, 15, 20, 7], [3, 9, 20, None, None, 15, 7]),
+ ([-1], [-1], [-1]),
+ ([1, 2], [2, 1], [1, 2]),
+ ([1, 2], [1, 2], [1, None, 2]),
+ ([1, 2, 3], [2, 1, 3], [1, 2, 3]),
+ ([1, 2, 4, 5, 3, 6], [4, 2, 5, 1, 6, 3], [1, 2, 3, 4, 5, 6]),
+ ([1, 2, 3, 4], [1, 2, 3, 4], [1, None, 2, None, 3, None, 4]),
+ ([4, 3, 2, 1], [1, 2, 3, 4], [4, 3, None, 2, None, 1]),
+ ([10, 5, 1, 7, 40, 50], [1, 5, 7, 10, 40, 50], [10, 5, 40, 1, 7, None, 50]),
+ ([1, 3, 2], [1, 2, 3], [1, None, 3, 2]),
+ ([2, 1, 3], [1, 2, 3], [2, 1, 3]),
+ ([5, 3, 2, 1, 4, 6, 7], [1, 2, 3, 4, 5, 6, 7], [5, 3, 6, 2, 4, None, 7, 1]),
+ (
+ [7, 3, 2, 1, 5, 4, 6, 10, 9, 11],
+ [1, 2, 3, 4, 5, 6, 7, 9, 10, 11],
+ [7, 3, 10, 2, 5, 9, 11, 1, None, 4, 6],
+ ),
+ ([-3000, -2999, -2998], [-2998, -2999, -3000], [-3000, -2999, None, -2998]),
+ ],
+ )
+ def test_build_tree(self, preorder: list[int], inorder: list[int], expected_list: list[int | None]):
+ result = run_build_tree(Solution, preorder, inorder)
+ assert_build_tree(result, expected_list)
diff --git a/leetcode/diagonal_traverse/README.md b/leetcode/diagonal_traverse/README.md
new file mode 100644
index 0000000..e988eef
--- /dev/null
+++ b/leetcode/diagonal_traverse/README.md
@@ -0,0 +1,37 @@
+# Diagonal Traverse
+
+**Difficulty:** Medium
+**Topics:** Array, Matrix, Simulation
+**Tags:**
+
+**LeetCode:** [Problem 498](https://leetcode.com/problems/diagonal-traverse/description/)
+
+## Problem Description
+
+Given an `m x n` matrix `mat`, return _an array of all the elements of the array in a diagonal order_.
+
+## Examples
+
+### Example 1:
+
+
+
+```
+Input: mat = [[1,2,3],[4,5,6],[7,8,9]]
+Output: [1,2,4,7,5,3,6,8,9]
+```
+
+### Example 2:
+
+```
+Input: mat = [[1,2],[3,4]]
+Output: [1,2,3,4]
+```
+
+## Constraints
+
+- `m == mat.length`
+- `n == mat[i].length`
+- `1 <= m, n <= 10^4`
+- `1 <= m * n <= 10^4`
+- `-10^5 <= mat[i][j] <= 10^5`
diff --git a/leetcode/diagonal_traverse/__init__.py b/leetcode/diagonal_traverse/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/leetcode/diagonal_traverse/helpers.py b/leetcode/diagonal_traverse/helpers.py
new file mode 100644
index 0000000..e828640
--- /dev/null
+++ b/leetcode/diagonal_traverse/helpers.py
@@ -0,0 +1,8 @@
+def run_find_diagonal_order(solution_class: type, mat: list[list[int]]):
+ implementation = solution_class()
+ return implementation.find_diagonal_order(mat)
+
+
+def assert_find_diagonal_order(result: list[int], expected: list[int]) -> bool:
+ assert result == expected
+ return True
diff --git a/leetcode/diagonal_traverse/playground.py b/leetcode/diagonal_traverse/playground.py
new file mode 100644
index 0000000..ffdfc99
--- /dev/null
+++ b/leetcode/diagonal_traverse/playground.py
@@ -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_find_diagonal_order, run_find_diagonal_order
+from solution import Solution
+
+# %%
+# Example test case
+mat = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
+expected = [1, 2, 4, 7, 5, 3, 6, 8, 9]
+
+# %%
+result = run_find_diagonal_order(Solution, mat)
+result
+
+# %%
+assert_find_diagonal_order(result, expected)
diff --git a/leetcode/diagonal_traverse/solution.py b/leetcode/diagonal_traverse/solution.py
new file mode 100644
index 0000000..e3f8ecb
--- /dev/null
+++ b/leetcode/diagonal_traverse/solution.py
@@ -0,0 +1,70 @@
+class Solution:
+ """
+ Diagonal Traverse Pattern:
+
+ Matrix with coordinates: d = i+j (diagonal index):
+ 1(0,0) 2(0,1) 3(0,2) d=0: 1(0,0) ↗
+ 4(1,0) 5(1,1) 6(1,2) d=1: 2(0,1), 4(1,0) ↙
+ 7(2,0) 8(2,1) 9(2,2) d=2: 3(0,2), 5(1,1), 7(2,0) ↗
+ d=3: 6(1,2), 8(2,1) ↙
+ d=4: 9(2,2) ↗
+
+ 'd' = diagonal number = sum of row+col indices (i+j)
+ Each diagonal contains elements where i+j equals the same value
+
+ Result: [1,2,4,7,5,3,6,8,9]
+ """
+
+ # Time: O(m*n)
+ # Space: O(1)
+ def find_diagonal_order(self, mat: list[list[int]]) -> list[int]:
+ m, n = len(mat), len(mat[0])
+ result = []
+
+ for d in range(m + n - 1):
+ if d % 2 == 0: # up-right diagonal
+ for i in range(min(d, m - 1), max(-1, d - n), -1):
+ result.append(mat[i][d - i])
+ else: # down-left diagonal
+ for i in range(max(0, d - n + 1), min(d + 1, m)):
+ result.append(mat[i][d - i])
+
+ return result
+
+
+class SolutionRowShift:
+ """
+ Row-shift approach: shift each row to align diagonals into columns
+
+ Original matrix: After shifting rows (col-row=actual_col):
+ 1 2 3 col=0 col=1 col=2 col=3 col=4
+ 4 5 6 1 2 3
+ 7 8 9 4 5 6
+ 7 8 9
+ ↑ ↓ ↑ ↓ ↑
+
+ Each row is shifted right by its row index, creating vertical columns
+ from the original diagonals. Then alternate traversal direction.
+
+ Traverse: 1 → 2,4 → 7,5,3 → 6,8 → 9
+ """
+
+ # Time: O(m*n)
+ # Space: O(1)
+ def find_diagonal_order(self, mat: list[list[int]]) -> list[int]:
+ m, n = len(mat), len(mat[0])
+ result = []
+
+ for col in range(m + n - 1):
+ if col % 2 == 1: # upward
+ for row in range(m):
+ i = col - row
+ if 0 <= i < n:
+ result.append(mat[row][i])
+ else: # downward
+ for row in range(m - 1, -1, -1):
+ i = col - row
+ if 0 <= i < n:
+ result.append(mat[row][i])
+
+ return result
diff --git a/leetcode/diagonal_traverse/test_solution.py b/leetcode/diagonal_traverse/test_solution.py
new file mode 100644
index 0000000..a57c110
--- /dev/null
+++ b/leetcode/diagonal_traverse/test_solution.py
@@ -0,0 +1,34 @@
+import pytest
+
+from leetcode_py.test_utils import logged_test
+
+from .helpers import assert_find_diagonal_order, run_find_diagonal_order
+from .solution import Solution, SolutionRowShift
+
+
+class TestDiagonalTraverse:
+ def setup_method(self):
+ self.solution = Solution()
+
+ @logged_test
+ @pytest.mark.parametrize("solution_class", [Solution, SolutionRowShift])
+ @pytest.mark.parametrize(
+ "mat, expected",
+ [
+ ([[1, 2, 3], [4, 5, 6], [7, 8, 9]], [1, 2, 4, 7, 5, 3, 6, 8, 9]),
+ ([[1, 2], [3, 4]], [1, 2, 3, 4]),
+ ([[1]], [1]),
+ ([[1, 2, 3]], [1, 2, 3]),
+ ([[1], [2], [3]], [1, 2, 3]),
+ ([[1, 2, 3, 4], [5, 6, 7, 8]], [1, 2, 5, 6, 3, 4, 7, 8]),
+ ([[1, 2], [3, 4], [5, 6]], [1, 2, 3, 5, 4, 6]),
+ ([[1, 2, 3, 4, 5]], [1, 2, 3, 4, 5]),
+ ([[1], [2], [3], [4], [5]], [1, 2, 3, 4, 5]),
+ ([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]], [1, 2, 5, 9, 6, 3, 4, 7, 10, 11, 8, 12]),
+ ([[-1, 0, 1], [2, -3, 4]], [-1, 0, 2, -3, 1, 4]),
+ ([[100]], [100]),
+ ],
+ )
+ def test_find_diagonal_order(self, solution_class, mat: list[list[int]], expected: list[int]):
+ result = run_find_diagonal_order(solution_class, mat)
+ assert_find_diagonal_order(result, expected)
diff --git a/leetcode/find_all_anagrams_in_a_string/README.md b/leetcode/find_all_anagrams_in_a_string/README.md
new file mode 100644
index 0000000..d84fab3
--- /dev/null
+++ b/leetcode/find_all_anagrams_in_a_string/README.md
@@ -0,0 +1,43 @@
+# Find All Anagrams in a String
+
+**Difficulty:** Medium
+**Topics:** Hash Table, String, Sliding Window
+**Tags:** grind-75
+
+**LeetCode:** [Problem 438](https://leetcode.com/problems/find-all-anagrams-in-a-string/description/)
+
+## Problem Description
+
+Given two strings `s` and `p`, return an array of all the start indices of `p`'s anagrams in `s`. You may return the answer in any order.
+
+An **anagram** is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.
+
+## Examples
+
+### Example 1:
+
+```
+Input: s = "cbaebabacd", p = "abc"
+Output: [0,6]
+```
+
+**Explanation:**
+The substring with start index = 0 is "cba", which is an anagram of "abc".
+The substring with start index = 6 is "bac", which is an anagram of "abc".
+
+### Example 2:
+
+```
+Input: s = "abab", p = "ab"
+Output: [0,1,2]
+```
+
+**Explanation:**
+The substring with start index = 0 is "ab", which is an anagram of "ab".
+The substring with start index = 1 is "ba", which is an anagram of "ab".
+The substring with start index = 2 is "ab", which is an anagram of "ab".
+
+## Constraints
+
+- 1 <= s.length, p.length <= 3 \* 10^4
+- s and p consist of lowercase English letters.
diff --git a/leetcode/find_all_anagrams_in_a_string/__init__.py b/leetcode/find_all_anagrams_in_a_string/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/leetcode/find_all_anagrams_in_a_string/helpers.py b/leetcode/find_all_anagrams_in_a_string/helpers.py
new file mode 100644
index 0000000..5836a99
--- /dev/null
+++ b/leetcode/find_all_anagrams_in_a_string/helpers.py
@@ -0,0 +1,8 @@
+def run_find_anagrams(solution_class: type, s: str, p: str):
+ implementation = solution_class()
+ return implementation.find_anagrams(s, p)
+
+
+def assert_find_anagrams(result: list[int], expected: list[int]) -> bool:
+ assert sorted(result) == sorted(expected)
+ return True
diff --git a/leetcode/find_all_anagrams_in_a_string/playground.py b/leetcode/find_all_anagrams_in_a_string/playground.py
new file mode 100644
index 0000000..42f330b
--- /dev/null
+++ b/leetcode/find_all_anagrams_in_a_string/playground.py
@@ -0,0 +1,30 @@
+# ---
+# 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_find_anagrams, run_find_anagrams
+from solution import Solution
+
+# %%
+# Example test case
+s = "cbaebabacd"
+p = "abc"
+expected = [0, 6]
+
+# %%
+result = run_find_anagrams(Solution, s, p)
+result
+
+# %%
+assert_find_anagrams(result, expected)
diff --git a/leetcode/find_all_anagrams_in_a_string/solution.py b/leetcode/find_all_anagrams_in_a_string/solution.py
new file mode 100644
index 0000000..f26a54f
--- /dev/null
+++ b/leetcode/find_all_anagrams_in_a_string/solution.py
@@ -0,0 +1,56 @@
+from collections import Counter
+
+
+class Solution:
+ """
+ Sliding Window with Character Frequency Counting
+
+ Algorithm:
+ 1. Count character frequencies in pattern p
+ 2. Use sliding window of size len(p) on string s
+ 3. Maintain frequency count of current window
+ 4. When frequencies match, record start index
+
+ ASCII Visualization:
+ s = "cbaebabacd", p = "abc" (need: a=1, b=1, c=1)
+
+ Window positions:
+ [cba]ebabacd -> {c:1, b:1, a:1} ✓ matches -> index 0
+ c[bae]babacd -> {b:1, a:1, e:1} ✗
+ cb[aeb]abacd -> {a:1, e:1, b:1} ✗
+ cba[eba]bacd -> {e:1, b:1, a:1} ✗
+ cbae[bab]acd -> {b:2, a:1} ✗
+ cbaeb[aba]cd -> {a:2, b:1} ✗
+ cbaeba[bac]d -> {b:1, a:1, c:1} ✓ matches -> index 6
+ """
+
+ # Time: O(n) where n is length of s
+ # Space: O(1) - at most 26 lowercase letters
+ def find_anagrams(self, s: str, p: str) -> list[int]:
+ if len(p) > len(s):
+ return []
+
+ result = []
+ p_count = Counter(p)
+ window_count = Counter(s[: len(p)])
+
+ # Check first window
+ if window_count == p_count:
+ result.append(0)
+
+ # Slide window
+ for i in range(len(p), len(s)):
+ # Add new character
+ window_count[s[i]] += 1
+
+ # Remove old character
+ left_char = s[i - len(p)]
+ window_count[left_char] -= 1
+ if window_count[left_char] == 0:
+ del window_count[left_char]
+
+ # Check if current window is anagram
+ if window_count == p_count:
+ result.append(i - len(p) + 1)
+
+ return result
diff --git a/leetcode/find_all_anagrams_in_a_string/test_solution.py b/leetcode/find_all_anagrams_in_a_string/test_solution.py
new file mode 100644
index 0000000..3782888
--- /dev/null
+++ b/leetcode/find_all_anagrams_in_a_string/test_solution.py
@@ -0,0 +1,33 @@
+import pytest
+
+from leetcode_py.test_utils import logged_test
+
+from .helpers import assert_find_anagrams, run_find_anagrams
+from .solution import Solution
+
+
+class TestFindAllAnagramsInAString:
+ def setup_method(self):
+ self.solution = Solution()
+
+ @logged_test
+ @pytest.mark.parametrize(
+ "s, p, expected",
+ [
+ ("cbaebabacd", "abc", [0, 6]),
+ ("abab", "ab", [0, 1, 2]),
+ ("a", "aa", []),
+ ("aa", "aa", [0]),
+ ("abcdefg", "xyz", []),
+ ("aab", "ab", [1]),
+ ("aaab", "ab", [2]),
+ ("baa", "aa", [1]),
+ ("abacabad", "aaab", []),
+ ("ababacb", "abc", [3, 4]),
+ ("abaacbabc", "abc", [3, 4, 6]),
+ ("abab", "abab", [0]),
+ ],
+ )
+ def test_find_anagrams(self, s: str, p: str, expected: list[int]):
+ result = run_find_anagrams(Solution, s, p)
+ assert_find_anagrams(result, expected)
diff --git a/leetcode/letter_combinations_of_a_phone_number/README.md b/leetcode/letter_combinations_of_a_phone_number/README.md
new file mode 100644
index 0000000..43f0064
--- /dev/null
+++ b/leetcode/letter_combinations_of_a_phone_number/README.md
@@ -0,0 +1,43 @@
+# Letter Combinations of a Phone Number
+
+**Difficulty:** Medium
+**Topics:** Hash Table, String, Backtracking
+**Tags:** grind-75
+
+**LeetCode:** [Problem 17](https://leetcode.com/problems/letter-combinations-of-a-phone-number/description/)
+
+## Problem Description
+
+Given a string containing digits from `2-9` inclusive, return all possible letter combinations that the number could represent. Return the answer in **any order**.
+
+A mapping of digits to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters.
+
+## Examples
+
+### Example 1:
+
+
+
+```
+Input: digits = "23"
+Output: ["ad","ae","af","bd","be","bf","cd","ce","cf"]
+```
+
+### Example 2:
+
+```
+Input: digits = ""
+Output: []
+```
+
+### Example 3:
+
+```
+Input: digits = "2"
+Output: ["a","b","c"]
+```
+
+## Constraints
+
+- `0 <= digits.length <= 4`
+- `digits[i]` is a digit in the range `['2', '9']`.
diff --git a/leetcode/letter_combinations_of_a_phone_number/__init__.py b/leetcode/letter_combinations_of_a_phone_number/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/leetcode/letter_combinations_of_a_phone_number/helpers.py b/leetcode/letter_combinations_of_a_phone_number/helpers.py
new file mode 100644
index 0000000..b35cae8
--- /dev/null
+++ b/leetcode/letter_combinations_of_a_phone_number/helpers.py
@@ -0,0 +1,10 @@
+def run_letter_combinations(solution_class: type, digits: str):
+ implementation = solution_class()
+ return implementation.letter_combinations(digits)
+
+
+def assert_letter_combinations(result: list[str], expected: list[str]) -> bool:
+ result.sort()
+ expected.sort()
+ assert result == expected
+ return True
diff --git a/leetcode/letter_combinations_of_a_phone_number/playground.py b/leetcode/letter_combinations_of_a_phone_number/playground.py
new file mode 100644
index 0000000..3dcbf29
--- /dev/null
+++ b/leetcode/letter_combinations_of_a_phone_number/playground.py
@@ -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_letter_combinations, run_letter_combinations
+from solution import Solution
+
+# %%
+# Example test case
+digits = "23"
+expected = ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]
+
+# %%
+result = run_letter_combinations(Solution, digits)
+result
+
+# %%
+assert_letter_combinations(result, expected)
diff --git a/leetcode/letter_combinations_of_a_phone_number/solution.py b/leetcode/letter_combinations_of_a_phone_number/solution.py
new file mode 100644
index 0000000..b198a2e
--- /dev/null
+++ b/leetcode/letter_combinations_of_a_phone_number/solution.py
@@ -0,0 +1,31 @@
+class Solution:
+
+ # Time: O(4^n)
+ # Space: O(4^n)
+ def letter_combinations(self, digits: str) -> list[str]:
+ if not digits:
+ return []
+
+ phone = {
+ "2": "abc",
+ "3": "def",
+ "4": "ghi",
+ "5": "jkl",
+ "6": "mno",
+ "7": "pqrs",
+ "8": "tuv",
+ "9": "wxyz",
+ }
+
+ result = []
+
+ def backtrack(i: int, path: str) -> None:
+ if i == len(digits):
+ result.append(path)
+ return
+
+ for letter in phone[digits[i]]:
+ backtrack(i + 1, path + letter)
+
+ backtrack(0, "")
+ return result
diff --git a/leetcode/letter_combinations_of_a_phone_number/test_solution.py b/leetcode/letter_combinations_of_a_phone_number/test_solution.py
new file mode 100644
index 0000000..c28498c
--- /dev/null
+++ b/leetcode/letter_combinations_of_a_phone_number/test_solution.py
@@ -0,0 +1,169 @@
+import pytest
+
+from leetcode_py.test_utils import logged_test
+
+from .helpers import assert_letter_combinations, run_letter_combinations
+from .solution import Solution
+
+
+class TestLetterCombinationsOfAPhoneNumber:
+ def setup_method(self):
+ self.solution = Solution()
+
+ @logged_test
+ @pytest.mark.parametrize(
+ "digits, expected",
+ [
+ ("23", ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]),
+ ("", []),
+ ("2", ["a", "b", "c"]),
+ (
+ "234",
+ [
+ "adg",
+ "adh",
+ "adi",
+ "aeg",
+ "aeh",
+ "aei",
+ "afg",
+ "afh",
+ "afi",
+ "bdg",
+ "bdh",
+ "bdi",
+ "beg",
+ "beh",
+ "bei",
+ "bfg",
+ "bfh",
+ "bfi",
+ "cdg",
+ "cdh",
+ "cdi",
+ "ceg",
+ "ceh",
+ "cei",
+ "cfg",
+ "cfh",
+ "cfi",
+ ],
+ ),
+ ("7", ["p", "q", "r", "s"]),
+ ("9", ["w", "x", "y", "z"]),
+ (
+ "79",
+ [
+ "pw",
+ "px",
+ "py",
+ "pz",
+ "qw",
+ "qx",
+ "qy",
+ "qz",
+ "rw",
+ "rx",
+ "ry",
+ "rz",
+ "sw",
+ "sx",
+ "sy",
+ "sz",
+ ],
+ ),
+ ("22", ["aa", "ab", "ac", "ba", "bb", "bc", "ca", "cb", "cc"]),
+ (
+ "3456",
+ [
+ "dgjm",
+ "dgjn",
+ "dgjo",
+ "dgkm",
+ "dgkn",
+ "dgko",
+ "dglm",
+ "dgln",
+ "dglo",
+ "dhjm",
+ "dhjn",
+ "dhjo",
+ "dhkm",
+ "dhkn",
+ "dhko",
+ "dhlm",
+ "dhln",
+ "dhlo",
+ "dijm",
+ "dijn",
+ "dijo",
+ "dikm",
+ "dikn",
+ "diko",
+ "dilm",
+ "diln",
+ "dilo",
+ "egjm",
+ "egjn",
+ "egjo",
+ "egkm",
+ "egkn",
+ "egko",
+ "eglm",
+ "egln",
+ "eglo",
+ "ehjm",
+ "ehjn",
+ "ehjo",
+ "ehkm",
+ "ehkn",
+ "ehko",
+ "ehlm",
+ "ehln",
+ "ehlo",
+ "eijm",
+ "eijn",
+ "eijo",
+ "eikm",
+ "eikn",
+ "eiko",
+ "eilm",
+ "eiln",
+ "eilo",
+ "fgjm",
+ "fgjn",
+ "fgjo",
+ "fgkm",
+ "fgkn",
+ "fgko",
+ "fglm",
+ "fgln",
+ "fglo",
+ "fhjm",
+ "fhjn",
+ "fhjo",
+ "fhkm",
+ "fhkn",
+ "fhko",
+ "fhlm",
+ "fhln",
+ "fhlo",
+ "fijm",
+ "fijn",
+ "fijo",
+ "fikm",
+ "fikn",
+ "fiko",
+ "film",
+ "filn",
+ "filo",
+ ],
+ ),
+ ("25", ["aj", "ak", "al", "bj", "bk", "bl", "cj", "ck", "cl"]),
+ ("78", ["pt", "pu", "pv", "qt", "qu", "qv", "rt", "ru", "rv", "st", "su", "sv"]),
+ ("89", ["tw", "tx", "ty", "tz", "uw", "ux", "uy", "uz", "vw", "vx", "vy", "vz"]),
+ ],
+ )
+ def test_letter_combinations(self, digits: str, expected: list[str]):
+ result = run_letter_combinations(Solution, digits)
+ assert_letter_combinations(result, expected)
diff --git a/leetcode/subsets/README.md b/leetcode/subsets/README.md
new file mode 100644
index 0000000..a28b3e0
--- /dev/null
+++ b/leetcode/subsets/README.md
@@ -0,0 +1,35 @@
+# Subsets
+
+**Difficulty:** Medium
+**Topics:** Array, Backtracking, Bit Manipulation
+**Tags:** grind-75
+
+**LeetCode:** [Problem 78](https://leetcode.com/problems/subsets/description/)
+
+## Problem Description
+
+Given an integer array `nums` of **unique** elements, return _all possible_ subsets (the power set).
+
+The solution set **must not** contain duplicate subsets. Return the solution in **any order**.
+
+## Examples
+
+### Example 1:
+
+```
+Input: nums = [1,2,3]
+Output: [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
+```
+
+### Example 2:
+
+```
+Input: nums = [0]
+Output: [[],[0]]
+```
+
+## Constraints
+
+- 1 <= nums.length <= 10
+- -10 <= nums[i] <= 10
+- All the numbers of nums are unique.
diff --git a/leetcode/subsets/__init__.py b/leetcode/subsets/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/leetcode/subsets/helpers.py b/leetcode/subsets/helpers.py
new file mode 100644
index 0000000..a28c5a3
--- /dev/null
+++ b/leetcode/subsets/helpers.py
@@ -0,0 +1,11 @@
+def run_subsets(solution_class: type, nums: list[int]):
+ implementation = solution_class()
+ return implementation.subsets(nums)
+
+
+def assert_subsets(result: list[list[int]], expected: list[list[int]]) -> bool:
+ # Sort both result and expected for comparison since order doesn't matter
+ result_sorted = [sorted(subset) for subset in sorted(result)]
+ expected_sorted = [sorted(subset) for subset in sorted(expected)]
+ assert result_sorted == expected_sorted
+ return True
diff --git a/leetcode/subsets/playground.py b/leetcode/subsets/playground.py
new file mode 100644
index 0000000..c7f57bb
--- /dev/null
+++ b/leetcode/subsets/playground.py
@@ -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_subsets, run_subsets
+from solution import Solution
+
+# %%
+# Example test case
+nums = [1, 2, 3]
+expected = [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
+
+# %%
+result = run_subsets(Solution, nums)
+result
+
+# %%
+assert_subsets(result, expected)
diff --git a/leetcode/subsets/solution.py b/leetcode/subsets/solution.py
new file mode 100644
index 0000000..3b9d8a2
--- /dev/null
+++ b/leetcode/subsets/solution.py
@@ -0,0 +1,16 @@
+class Solution:
+
+ # Time: O(2^n)
+ # Space: O(2^n)
+ def subsets(self, nums: list[int]) -> list[list[int]]:
+ result = []
+
+ def backtrack(start: int, path: list[int]) -> None:
+ result.append(path[:])
+ for i in range(start, len(nums)):
+ path.append(nums[i])
+ backtrack(i + 1, path)
+ path.pop()
+
+ backtrack(0, [])
+ return result
diff --git a/leetcode/subsets/test_solution.py b/leetcode/subsets/test_solution.py
new file mode 100644
index 0000000..6efd136
--- /dev/null
+++ b/leetcode/subsets/test_solution.py
@@ -0,0 +1,53 @@
+import pytest
+
+from leetcode_py.test_utils import logged_test
+
+from .helpers import assert_subsets, run_subsets
+from .solution import Solution
+
+
+class TestSubsets:
+ def setup_method(self):
+ self.solution = Solution()
+
+ @logged_test
+ @pytest.mark.parametrize(
+ "nums, expected",
+ [
+ ([1, 2, 3], [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]),
+ ([0], [[], [0]]),
+ ([1], [[], [1]]),
+ ([1, 2], [[], [1], [2], [1, 2]]),
+ ([4, 1, 0], [[], [4], [4, 1], [4, 1, 0], [4, 0], [1], [1, 0], [0]]),
+ ([-1, 0, 1], [[], [-1], [-1, 0], [-1, 0, 1], [-1, 1], [0], [0, 1], [1]]),
+ ([5], [[], [5]]),
+ ([2, 1, 3], [[], [2], [2, 1], [2, 1, 3], [2, 3], [1], [1, 3], [3]]),
+ ([10], [[], [10]]),
+ ([-10, 10], [[], [-10], [-10, 10], [10]]),
+ (
+ [1, 2, 3, 4],
+ [
+ [],
+ [1],
+ [1, 2],
+ [1, 2, 3],
+ [1, 2, 3, 4],
+ [1, 2, 4],
+ [1, 3],
+ [1, 3, 4],
+ [1, 4],
+ [2],
+ [2, 3],
+ [2, 3, 4],
+ [2, 4],
+ [3],
+ [3, 4],
+ [4],
+ ],
+ ),
+ ([5, 2], [[], [5], [5, 2], [2]]),
+ ],
+ )
+ def test_subsets(self, nums: list[int], expected: list[list[int]]):
+ result = run_subsets(Solution, nums)
+ assert_subsets(result, expected)
diff --git a/leetcode/unique_paths/README.md b/leetcode/unique_paths/README.md
new file mode 100644
index 0000000..d40c811
--- /dev/null
+++ b/leetcode/unique_paths/README.md
@@ -0,0 +1,43 @@
+# Unique Paths
+
+**Difficulty:** Medium
+**Topics:** Math, Dynamic Programming, Combinatorics
+**Tags:** grind-75
+
+**LeetCode:** [Problem 62](https://leetcode.com/problems/unique-paths/description/)
+
+## Problem Description
+
+There is a robot on an `m x n` grid. The robot is initially located at the **top-left corner** (i.e., `grid[0][0]`). The robot tries to move to the **bottom-right corner** (i.e., `grid[m - 1][n - 1]`). The robot can only move either down or right at any point in time.
+
+Given the two integers `m` and `n`, return _the number of possible unique paths that the robot can take to reach the bottom-right corner_.
+
+The test cases are generated so that the answer will be less than or equal to `2 * 10^9`.
+
+## Examples
+
+### Example 1:
+
+
+
+```
+Input: m = 3, n = 7
+Output: 28
+```
+
+### Example 2:
+
+```
+Input: m = 3, n = 2
+Output: 3
+```
+
+**Explanation:** From the top-left corner, there are a total of 3 ways to reach the bottom-right corner:
+
+1. Right -> Down -> Down
+2. Down -> Down -> Right
+3. Down -> Right -> Down
+
+## Constraints
+
+- 1 <= m, n <= 100
diff --git a/leetcode/unique_paths/__init__.py b/leetcode/unique_paths/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/leetcode/unique_paths/helpers.py b/leetcode/unique_paths/helpers.py
new file mode 100644
index 0000000..c0ead78
--- /dev/null
+++ b/leetcode/unique_paths/helpers.py
@@ -0,0 +1,8 @@
+def run_unique_paths(solution_class: type, m: int, n: int):
+ implementation = solution_class()
+ return implementation.unique_paths(m, n)
+
+
+def assert_unique_paths(result: int, expected: int) -> bool:
+ assert result == expected
+ return True
diff --git a/leetcode/unique_paths/playground.py b/leetcode/unique_paths/playground.py
new file mode 100644
index 0000000..e70351b
--- /dev/null
+++ b/leetcode/unique_paths/playground.py
@@ -0,0 +1,30 @@
+# ---
+# 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_unique_paths, run_unique_paths
+from solution import Solution
+
+# %%
+# Example test case
+m = 3
+n = 7
+expected = 28
+
+# %%
+result = run_unique_paths(Solution, m, n)
+result
+
+# %%
+assert_unique_paths(result, expected)
diff --git a/leetcode/unique_paths/solution.py b/leetcode/unique_paths/solution.py
new file mode 100644
index 0000000..0a3ddb9
--- /dev/null
+++ b/leetcode/unique_paths/solution.py
@@ -0,0 +1,29 @@
+class Solution:
+ # Dynamic Programming
+ # Time: O(m * n)
+ # Space: O(min(m, n))
+ def unique_paths(self, m: int, n: int) -> int:
+ if m > n:
+ m, n = n, m
+ dp = [1] * m
+ for _ in range(1, n):
+ for j in range(1, m):
+ dp[j] += dp[j - 1]
+ return dp[m - 1]
+
+
+class SolutionMath:
+
+ # Math solution: C(m+n-2, m-1) = (m+n-2)! / ((m-1)! * (n-1)!)
+ # Time: O(min(m, n))
+ # Space: O(1)
+ def unique_paths(self, m: int, n: int) -> int:
+ # Total moves: (m-1) right + (n-1) down = m+n-2
+ # Choose (m-1) positions for right moves out of (m+n-2) total
+ if m > n:
+ m, n = n, m # Optimize for smaller factorial
+
+ result = 1
+ for i in range(m - 1):
+ result = result * (n + i) // (i + 1)
+ return result
diff --git a/leetcode/unique_paths/test_solution.py b/leetcode/unique_paths/test_solution.py
new file mode 100644
index 0000000..b66ad67
--- /dev/null
+++ b/leetcode/unique_paths/test_solution.py
@@ -0,0 +1,34 @@
+import pytest
+
+from leetcode_py.test_utils import logged_test
+
+from .helpers import assert_unique_paths, run_unique_paths
+from .solution import Solution, SolutionMath
+
+
+class TestUniquePaths:
+ @logged_test
+ @pytest.mark.parametrize("solution_class", [Solution, SolutionMath])
+ @pytest.mark.parametrize(
+ "m, n, expected",
+ [
+ (3, 7, 28),
+ (3, 2, 3),
+ (1, 1, 1),
+ (1, 10, 1),
+ (10, 1, 1),
+ (2, 2, 2),
+ (3, 3, 6),
+ (4, 4, 20),
+ (5, 5, 70),
+ (2, 3, 3),
+ (3, 4, 10),
+ (4, 5, 35),
+ (6, 3, 21),
+ (7, 3, 28),
+ (10, 10, 48620),
+ ],
+ )
+ def test_unique_paths(self, solution_class, m: int, n: int, expected: int):
+ result = run_unique_paths(solution_class, m, n)
+ assert_unique_paths(result, expected)
diff --git a/leetcode/word_search/README.md b/leetcode/word_search/README.md
new file mode 100644
index 0000000..8ceb82b
--- /dev/null
+++ b/leetcode/word_search/README.md
@@ -0,0 +1,52 @@
+# Word Search
+
+**Difficulty:** Medium
+**Topics:** Array, String, Backtracking, Depth-First Search, Matrix
+**Tags:** grind-75
+
+**LeetCode:** [Problem 79](https://leetcode.com/problems/word-search/description/)
+
+## Problem Description
+
+Given an `m x n` grid of characters `board` and a string `word`, return `true` _if_ `word` _exists in the grid_.
+
+The word can be constructed from letters of sequentially adjacent cells, where adjacent cells are horizontally or vertically neighboring. The same letter cell may not be used more than once.
+
+## Examples
+
+### Example 1:
+
+
+
+```
+Input: board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
+Output: true
+```
+
+### Example 2:
+
+
+
+```
+Input: board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "SEE"
+Output: true
+```
+
+### Example 3:
+
+
+
+```
+Input: board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCB"
+Output: false
+```
+
+## Constraints
+
+- `m == board.length`
+- `n = board[i].length`
+- `1 <= m, n <= 6`
+- `1 <= word.length <= 15`
+- `board` and `word` consists of only lowercase and uppercase English letters.
+
+**Follow up:** Could you use search pruning to make your solution faster with a larger `board`?
diff --git a/leetcode/word_search/__init__.py b/leetcode/word_search/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/leetcode/word_search/helpers.py b/leetcode/word_search/helpers.py
new file mode 100644
index 0000000..e1d096d
--- /dev/null
+++ b/leetcode/word_search/helpers.py
@@ -0,0 +1,8 @@
+def run_exist(solution_class: type, board: list[list[str]], word: str):
+ implementation = solution_class()
+ return implementation.exist(board, word)
+
+
+def assert_exist(result: bool, expected: bool) -> bool:
+ assert result == expected
+ return True
diff --git a/leetcode/word_search/playground.py b/leetcode/word_search/playground.py
new file mode 100644
index 0000000..5e69458
--- /dev/null
+++ b/leetcode/word_search/playground.py
@@ -0,0 +1,30 @@
+# ---
+# 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_exist, run_exist
+from solution import Solution
+
+# %%
+# Example test case
+board = [["A", "B", "C", "E"], ["S", "F", "C", "S"], ["A", "D", "E", "E"]]
+word = "ABCCED"
+expected = True
+
+# %%
+result = run_exist(Solution, board, word)
+result
+
+# %%
+assert_exist(result, expected)
diff --git a/leetcode/word_search/solution.py b/leetcode/word_search/solution.py
new file mode 100644
index 0000000..0b5a659
--- /dev/null
+++ b/leetcode/word_search/solution.py
@@ -0,0 +1,42 @@
+from collections import Counter
+
+
+class Solution:
+
+ # Time: O(m*n*4^L) where L is word length
+ # Space: O(L)
+ def exist(self, board: list[list[str]], word: str) -> bool:
+
+ m, n = len(board), len(board[0])
+
+ # Early pruning: check if board has enough characters
+ board_counter = Counter(ch for row in board for ch in row)
+ word_counter = Counter(word)
+ for ch in word_counter:
+ if board_counter[ch] < word_counter[ch]:
+ return False
+
+ # Optimization: start from less frequent end
+ if board_counter[word[0]] > board_counter[word[-1]]:
+ word = word[::-1]
+
+ def dfs(i: int, j: int, k: int) -> bool:
+ if k == len(word):
+ return True
+ if i < 0 or i >= m or j < 0 or j >= n or board[i][j] != word[k]:
+ return False
+
+ temp = board[i][j]
+ board[i][j] = "#"
+ for di, dj in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
+ if dfs(i + di, j + dj, k + 1):
+ board[i][j] = temp
+ return True
+ board[i][j] = temp
+ return False
+
+ for i in range(m):
+ for j in range(n):
+ if dfs(i, j, 0):
+ return True
+ return False
diff --git a/leetcode/word_search/test_solution.py b/leetcode/word_search/test_solution.py
new file mode 100644
index 0000000..5e1151d
--- /dev/null
+++ b/leetcode/word_search/test_solution.py
@@ -0,0 +1,44 @@
+import pytest
+
+from leetcode_py.test_utils import logged_test
+
+from .helpers import assert_exist, run_exist
+from .solution import Solution
+
+
+class TestWordSearch:
+ def setup_method(self):
+ self.solution = Solution()
+
+ @logged_test
+ @pytest.mark.parametrize(
+ "board, word, expected",
+ [
+ ([["A", "B", "C", "E"], ["S", "F", "C", "S"], ["A", "D", "E", "E"]], "ABCCED", True),
+ ([["A", "B", "C", "E"], ["S", "F", "C", "S"], ["A", "D", "E", "E"]], "SEE", True),
+ ([["A", "B", "C", "E"], ["S", "F", "C", "S"], ["A", "D", "E", "E"]], "ABCB", False),
+ ([["A"]], "A", True),
+ ([["A"]], "B", False),
+ ([["A", "B"], ["C", "D"]], "ACDB", True),
+ ([["A", "B"], ["C", "D"]], "ABDC", True),
+ ([["A", "B"], ["C", "D"]], "ABCD", False),
+ ([["C", "A", "A"], ["A", "A", "A"], ["B", "C", "D"]], "AAB", True),
+ ([["A", "B", "C", "E"], ["S", "F", "C", "S"], ["A", "D", "E", "E"]], "ABCESEEEFS", False),
+ (
+ [
+ ["A", "A", "A", "A", "A", "A"],
+ ["A", "A", "A", "A", "A", "A"],
+ ["A", "A", "A", "A", "A", "A"],
+ ["A", "A", "A", "A", "A", "A"],
+ ["A", "A", "A", "A", "A", "A"],
+ ["A", "A", "A", "A", "A", "A"],
+ ],
+ "AAAAAAAAAAAAAAB",
+ False,
+ ),
+ ([["A", "B", "C", "E"], ["S", "F", "C", "S"], ["A", "D", "E", "E"]], "SFCS", True),
+ ],
+ )
+ def test_exist(self, board: list[list[str]], word: str, expected: bool):
+ result = run_exist(Solution, board, word)
+ assert_exist(result, expected)
diff --git a/pyproject.toml b/pyproject.toml
index 7306c4a..7debb1c 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -76,3 +76,6 @@ python_files = ["tests.py", "test_*.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
addopts = "-v --tb=short"
+
+[tool.coverage.run]
+omit = ["**/playground.py"]
From 71ebd05d777f476ef23dd1048c6bb36debc056d5 Mon Sep 17 00:00:00 2001
From: Wisaroot <66859294+wisarootl@users.noreply.github.com>
Date: Sat, 13 Sep 2025 12:11:00 +0700
Subject: [PATCH 05/58] docs!: update README.md (#39)
- update README.md
- add issues/PR templates
---
.github/ISSUE_TEMPLATE/bug_report.md | 28 +++
.github/ISSUE_TEMPLATE/feature_request.md | 19 ++
.github/ISSUE_TEMPLATE/problem_request.md | 13 ++
.github/PULL_REQUEST_TEMPLATE.md | 7 +
CONTRIBUTING.md | 56 ++++++
README.md | 201 ++++++++++++++--------
docs/images/linkedlist-viz.png | Bin 30293 -> 39106 bytes
7 files changed, 248 insertions(+), 76 deletions(-)
create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md
create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md
create mode 100644 .github/ISSUE_TEMPLATE/problem_request.md
create mode 100644 .github/PULL_REQUEST_TEMPLATE.md
create mode 100644 CONTRIBUTING.md
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000..2071edd
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,28 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: "[BUG] "
+labels: bug
+assignees: ""
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+
+1. Run command '...'
+2. See error
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Environment:**
+
+- OS: [e.g. macOS, Ubuntu]
+- Python version: [e.g. 3.13]
+- Poetry version: [e.g. 1.8.0]
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000..205ef6c
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,19 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: "[FEATURE] "
+labels: enhancement
+assignees: ""
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/.github/ISSUE_TEMPLATE/problem_request.md b/.github/ISSUE_TEMPLATE/problem_request.md
new file mode 100644
index 0000000..6338c01
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/problem_request.md
@@ -0,0 +1,13 @@
+---
+name: Problem request
+about: Request a new LeetCode problem to be added
+title: "[PROBLEM] Add LeetCode #"
+labels: problem-request
+assignees: ""
+---
+
+**Problem(s)**
+Paste problem URL(s) or list name here (LeetCode, Blind 75, NeetCode 150, etc.):
+
+**Why this problem?**
+Brief explanation of why this problem should be added (e.g. part of a study plan, important pattern, etc.)
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..f41f9b3
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,7 @@
+## What changed?
+
+Describe your changes here.
+
+## Why?
+
+Brief explanation of the motivation behind this change.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..60ef591
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,56 @@
+# Contributing to LeetCode Practice Repository
+
+Thank you for your interest in contributing! This repository welcomes contributions from the community.
+
+## Ways to Contribute
+
+### 1. Add New Problems
+
+Use an LLM assistant (Cursor, GitHub Copilot Chat, Amazon Q) with the rule files:
+
+- Include `.amazonq/rules/problem-creation.md` in your LLM context
+- Ask: "Create LeetCode problem [number] ([name])"
+
+### 2. Enhance Test Cases
+
+- Include `.amazonq/rules/test-case-enhancement.md` in your LLM context
+- Ask: "Enhance test cases for [problem_name] problem"
+
+### 3. Improve Helper Classes
+
+- Add new data structure helpers in `leetcode_py/data_structures/`
+- Follow existing patterns with generic types and visualization support
+
+### 4. Bug Fixes & Improvements
+
+- Fix issues in existing problems
+- Improve documentation
+- Enhance CI/CD workflows
+
+## Development Setup
+
+```bash
+git clone https://github.com/wisarootl/leetcode-py.git
+cd leetcode-py
+poetry install
+make test
+```
+
+## Code Standards
+
+- Follow [PEP 8](https://peps.python.org/pep-0008/) Python style guide
+- Use modern type hints per [PEP 585](https://peps.python.org/pep-0585/)/[PEP 604](https://peps.python.org/pep-0604/): `list[str]`, `dict[str, int]`, `Type | None`
+- Automated linting enforced by CI (black, isort, ruff, mypy)
+- Minimum 12 test cases per problem
+
+## Pull Request Process
+
+1. Fork the repository
+2. Create a feature branch
+3. Make your changes
+4. Run `make lint` and `make test`
+5. Submit a pull request with clear description
+
+## Questions?
+
+Open an issue for questions or discussions about contributions.
diff --git a/README.md b/README.md
index ffd2a86..5ee0760 100644
--- a/README.md
+++ b/README.md
@@ -7,24 +7,38 @@
[](https://github.com/wisarootl/zerv/actions/workflows/ci-test.yml)
[](https://github.com/wisarootl/zerv/actions/workflows/cd.yml)
-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.
+A modern Python LeetCode practice environment that goes beyond basic problem solving. Features automated problem generation from LeetCode URLs, beautiful data structure visualizations (TreeNode, ListNode, GraphNode), and comprehensive testing with 12+ test cases per problem. Built with professional development practices including CI/CD, type hints, and quality gates.
+
+**What makes this different:**
+
+- 🤖 **LLM-Assisted Workflow**: Generate new problems instantly with AI assistance
+- 🎨 **Visual Debugging**: Interactive tree/graph rendering with Graphviz and anytree
+- 🧪 **Production Testing**: Comprehensive test suites with edge cases and reproducibility verification
+- 🚀 **Modern Python**: PEP 585/604 type hints, Poetry, and professional tooling
+- 📊 **Quality Assurance**: 95%+ test coverage, security scanning, automated linting
+
+Includes all **75 Grind problems** - the most essential coding interview questions curated for maximum impact.
+
+## 🎯 What's Included
+
+**Current**: All 75 problems from [Grind 75](https://www.techinterviewhandbook.org/grind75/) - the most essential coding interview problems curated by the creator of Blind 75.
+
+**Future**: Planned expansion to all 169 Grind problems for comprehensive interview preparation.
## 🚀 Quick Start
```bash
-# Clone the repository
+# Clone and setup
git clone https://github.com/wisarootl/leetcode-py.git
cd leetcode-py
-
-# Install dependencies
poetry install
-# Generate all problems to start practicing (fresh start - wipes all solutions)
-make gen-all-problems
+# Start with existing Grind 75 problems
+make gen-all-problems # Regenerates all problems with TODO placeholders
-# Run existing problems
-make p-test PROBLEM=insert_interval
-make p-test PROBLEM=invert_binary_tree
+# Practice a specific problem
+make p-test PROBLEM=two_sum
+# Edit leetcode/two_sum/solution.py, then rerun tests
# Run all tests
make test
@@ -33,113 +47,148 @@ make test
## 📋 Prerequisites
- Python 3.13+
-- make, git, Graphviz, poetry
+- Poetry, Make, Git, Graphviz
## 📁 Problem Structure
-Each problem follows a consistent template:
+Each problem follows a consistent, production-ready template:
```
leetcode/two_sum/
-├── README.md # Problem description and examples
-├── solution.py # Your implementation with TODO placeholder
-├── tests.py # Comprehensive test cases
-├── notebook.ipynb # Interactive playground
-└── __init__.py # Package marker
+├── README.md # Problem description with examples and constraints
+├── solution.py # Implementation with type hints and TODO placeholder
+├── test_solution.py # Comprehensive parametrized tests (12+ test cases)
+├── helpers.py # Test helper functions
+├── playground.py # Interactive debugging environment (converted from .ipynb)
+└── __init__.py # Package marker
```
-## 🎯 Supported Problem Categories (ongoing)
+## ✨ Key Features
-- **Arrays & Hashing** - Two Sum, Group Anagrams, Top K Elements
-- **Two Pointers** - Valid Palindrome, Container With Most Water
-- **Sliding Window** - Longest Substring, Minimum Window
-- **Stack** - Valid Parentheses, Daily Temperatures
-- **Binary Search** - Search Rotated Array, Find Minimum
-- **Linked Lists** - Reverse List, Merge Lists, Detect Cycle
-- **Trees** - Invert Tree, Maximum Depth, Serialize/Deserialize
-- **Tries** - Implement Trie, Word Search II
-- **Heap/Priority Queue** - Merge K Lists, Find Median
-- **Backtracking** - Combination Sum, Word Search, N-Queens
-- **Graphs** - Clone Graph, Course Schedule, Islands
-- **Advanced DP** - Climbing Stairs, Coin Change, LCS
-- **Greedy** - Jump Game, Gas Station
-- **Intervals** - Merge Intervals, Meeting Rooms
-- **Math & Geometry** - Rotate Image, Spiral Matrix
+### Production-Grade Development Environment
-Includes problems from **Blind 75**, **Grind 75**, **NeetCode 150**, and **Top Interview Questions**.
+- **Modern Python**: PEP 585/604 type hints, snake_case conventions
+- **Comprehensive Linting**: black, isort, ruff, mypy with nbqa for notebooks
+- **High Test Coverage**: 12+ test cases per problem including edge cases
+- **Beautiful Logging**: loguru integration for enhanced test debugging
+- **CI/CD Pipeline**: Automated testing, security scanning, and quality gates
-## 🎨 Visualizations
+### Enhanced Data Structure Visualization
-### Tree Visualization
+- **TreeNode**: Beautiful tree rendering with anytree and Graphviz
+- **ListNode**: Clean arrow-based visualization (`1 -> 2 -> 3`)
+- **Interactive Debugging**: Multi-cell playground environment

_Beautiful tree rendering with anytree and Graphviz_
-### Linked List Visualization
-

_Clean arrow-based list visualization_
-### Jupyter Notebook Integration
+### Flexible Notebook Support
+
+- **Template Generation**: Creates Jupyter notebooks (`.ipynb`) by default
+- **Repository State**: This repo uses Python files (`.py`) for better version control
+- **User Choice**: Use `make nb-to-py` to convert notebooks to Python files, or keep as `.ipynb` for interactive development

_Interactive multi-cell playground for each problem_
-## ✨ Features
-
-- **Template-driven development** - Consistent structure for every problem
-- **Beautiful visualizations** - TreeNode with anytree/Graphviz, ListNode with arrows
-- **Interactive notebooks** - Multi-cell playground for each problem
-- **One-command testing** - `make p-test PROBLEM=problem_name`
-- **Bulk regeneration** - `make gen-all-problems` from JSON templates
-- **Full linting** - black, isort, ruff, mypy with nbqa for notebooks
-- **Modern Python** - PEP 585/604 syntax with full type hints
+## 🔄 Usage Patterns
-## 🔄 Workflow Examples
+### For Current Grind 75 Problems
-**Practice existing problems**:
+Perfect if you want to focus on the most essential interview problems:
```bash
-# Work on a specific problem
-make p-test PROBLEM=lru_cache
-# Edit leetcode/lru_cache/solution.py
-# Run tests to verify
+# Regenerate all 75 problems with fresh TODO placeholders
+make gen-all-problems
-# Or use make p-test if default problem is set in Makefile
-make p-test
+# Work through problems systematically
+make p-test PROBLEM=two_sum
+make p-test PROBLEM=valid_palindrome
+make p-test PROBLEM=merge_two_sorted_lists
```
-**Add new problems**:
+### For Additional Problems (LLM-Assisted)
+
+If you need more problems beyond Grind 75, use an LLM assistant in your IDE (Cursor, GitHub Copilot Chat, Amazon Q, etc.):
```bash
-# Ask your LLM assistant:
-# "Create LeetCode problem 146 (LRU Cache)"
-# The assistant handles everything automatically!
+# Example commands to give your LLM assistant:
+"Create LeetCode problem 146 (LRU Cache)"
+"Add problem 'Word Ladder' by number 127"
+"Generate problem 'Serialize and Deserialize Binary Tree'"
+
+# For test enhancement (when you need more comprehensive test coverage):
+"Enhance test cases for two_sum problem"
+"Fix test reproducibility for binary_tree_inorder_traversal"
```
-_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`._
+**Required LLM Context**: Include these rule files in your LLM context for automated problem generation and test enhancement:
+
+- [`.amazonq/rules/problem-creation.md`](.amazonq/rules/problem-creation.md) - Complete problem generation workflow
+- [`.amazonq/rules/test-case-enhancement.md`](.amazonq/rules/test-case-enhancement.md) - Test enhancement and reproducibility verification
-**Bulk operations**:
+**Manual Check**: Find problems needing more test cases:
```bash
-# Test all problems
-make test
-# Regenerate all from templates
-make gen-all-problems
-# Check code quality
-make lint
+poetry run python .templates/check_test_cases.py --threshold=10
```
-## 🧰 Helper Classes (ongoing)
+## 🧰 Helper Classes
- **TreeNode**: `from leetcode_py import TreeNode`
- - Beautiful tree visualization with anytree rendering
- - Jupyter notebook support with Graphviz diagrams
- - Easy array ↔ tree conversion for testing
+ - Array ↔ tree conversion: `TreeNode.from_list([1,2,3])`, `tree.to_list()`
+ - Beautiful anytree text rendering and Graphviz SVG for Jupyter
+ - Node search: `tree.find_node(value)`
+ - Generic type support: `TreeNode[int]`, `TreeNode[str]`
+
- **ListNode**: `from leetcode_py import ListNode`
- - Clean arrow visualization (`1 -> 2 -> 3`)
- - Simple array ↔ list conversion
- - Perfect for debugging linked list problems
-- New helpers: Add to `leetcode_py/`
+ - Array ↔ list conversion: `ListNode.from_list([1,2,3])`, `node.to_list()`
+ - Cycle detection with Floyd's algorithm
+ - Graphviz visualization for Jupyter notebooks
+ - Generic type support: `ListNode[int]`, `ListNode[str]`
+
+- **GraphNode**: `from leetcode_py import GraphNode`
+ - Adjacency list conversion: `GraphNode.from_adjacency_list([[2,4],[1,3],[2,4],[1,3]])`
+ - Clone detection: `original.is_clone(cloned)`
+ - Graphviz visualization for undirected graphs
+ - DFS traversal utilities
+
+- **DictTree**: `from leetcode_py.data_structures import DictTree`
+ - Perfect for Trie implementations: `DictTree[str]()`
+ - Beautiful tree rendering with box-drawing characters
+ - Graphviz visualization for Jupyter notebooks
+ - Generic key type support
+
+## 🛠️ Development Commands
+
+```bash
+# Problem-specific operations
+make p-test PROBLEM=problem_name # Test specific problem
+make p-gen PROBLEM=problem_name # Generate problem from JSON template
+make p-lint PROBLEM=problem_name # Lint specific problem
+
+# Bulk operations
+make test # Run all tests
+make lint # Lint entire codebase
+make gen-all-problems # Regenerate all problems (destructive)
+```
+
+## 🏗️ Architecture
+
+- **Template-Driven**: JSON templates in `.templates/leetcode/json/` drive code generation
+- **Cookiecutter Integration**: Uses `.templates/leetcode/{{cookiecutter.problem_name}}/` template for consistent file structure
+- **Automated Scraping**: LLM-assisted problem data extraction from LeetCode
+- **Version Control Friendly**: Python files by default, optional notebook support
+
+## 📊 Quality Metrics
+
+- **Test Coverage**: 95%+ with comprehensive edge case testing (Codecov integration)
+- **Security**: SonarCloud quality gates, Trivy dependency scanning, Gitleaks secret detection
+- **Code Quality**: Automated linting with black, isort, ruff, mypy
+- **Test Reproducibility**: Automated verification that problems can be regenerated consistently
+- **CI/CD**: GitHub Actions for testing, security, pre-commit hooks, and release automation
-Perfect for interview preparation with professional-grade tooling and beautiful visualizations.
+Perfect for systematic coding interview preparation with professional development practices and enhanced debugging capabilities.
diff --git a/docs/images/linkedlist-viz.png b/docs/images/linkedlist-viz.png
index 46df3b5c81fdde319d5b931eca5706d32505d85f..49c8ed0c4ccd053e2fa8ac7b4f69a00c68bb2ebb 100644
GIT binary patch
literal 39106
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
literal 30293
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