Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ repos:
- id: check-added-large-files
args: ["--maxkb=20000"]
- repo: https://github.com/gitleaks/gitleaks
rev: v8.29.1
rev: v8.30.0
hooks:
- name: gitleaks
id: gitleaks
Expand Down
32 changes: 32 additions & 0 deletions leetcode/palindrome_partitioning/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Palindrome Partitioning

**Difficulty:** Medium
**Topics:** String, Dynamic Programming, Backtracking
**Tags:** grind-75

**LeetCode:** [Problem 131](https://leetcode.com/problems/palindrome-partitioning/description/)

## Problem Description

Given a string `s`, partition `s` such that every substring of the partition is a **palindrome**. Return _all possible palindrome partitioning of `s`_.

## Examples

### Example 1:

```
Input: s = "aab"
Output: [["a","a","b"],["aa","b"]]
```

### Example 2:

```
Input: s = "a"
Output: [["a"]]
```

## Constraints

- `1 <= s.length <= 16`
- `s` contains only lowercase English letters.
Empty file.
15 changes: 15 additions & 0 deletions leetcode/palindrome_partitioning/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
def run_partition(solution_class: type, s: str):
implementation = solution_class()
return implementation.partition(s)


def assert_partition(result: list[list[str]], expected: list[list[str]]) -> bool:
# Sort inner lists and outer list for comparison
# Note: Inner lists are partitions (lists of strings), order of partitions doesn't matter
# Order of strings within a partition DOES matter (it must reconstruct s)
# But wait, the problem says "partition s", so the order of substrings must match the order in s.
# So we only need to sort the outer list of partitions.
result_sorted = sorted(result)
expected_sorted = sorted(expected)
assert result_sorted == expected_sorted
return True
29 changes: 29 additions & 0 deletions leetcode/palindrome_partitioning/playground.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# ---
# jupyter:
# jupytext:
# text_representation:
# extension: .py
# format_name: percent
# format_version: '1.3'
# jupytext_version: 1.18.1
# kernelspec:
# display_name: leetcode-py-py3.13
# language: python
# name: python3
# ---

# %%
from helpers import assert_partition, run_partition
from solution import Solution

# %%
# Example test case
s = "aab"
expected = [["a", "a", "b"], ["aa", "b"]]

# %%
result = run_partition(Solution, s)
result

# %%
assert_partition(result, expected)
22 changes: 22 additions & 0 deletions leetcode/palindrome_partitioning/solution.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
class Solution:
# Time: O(N * 2^N)
# Space: O(N)
def partition(self, s: str) -> list[list[str]]:
result: list[list[str]] = []
self._backtrack(s, 0, [], result)
return result

def _backtrack(self, s: str, start: int, path: list[str], result: list[list[str]]) -> None:
if start == len(s):
result.append(path[:])
return

for end in range(start + 1, len(s) + 1):
substring = s[start:end]
if self._is_palindrome(substring):
path.append(substring)
self._backtrack(s, end, path, result)
path.pop()

def _is_palindrome(self, s: str) -> bool:
return s == s[::-1]
33 changes: 33 additions & 0 deletions leetcode/palindrome_partitioning/test_solution.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import pytest

from leetcode_py import logged_test

from .helpers import assert_partition, run_partition
from .solution import Solution


class TestPalindromePartitioning:
def setup_method(self):
self.solution = Solution()

@logged_test
@pytest.mark.parametrize(
"s, expected",
[
("aab", [["a", "a", "b"], ["aa", "b"]]),
("a", [["a"]]),
("ab", [["a", "b"]]),
("aa", [["a", "a"], ["aa"]]),
("abc", [["a", "b", "c"]]),
("aba", [["a", "b", "a"], ["aba"]]),
("aaa", [["a", "a", "a"], ["a", "aa"], ["aa", "a"], ["aaa"]]),
("abba", [["a", "b", "b", "a"], ["a", "bb", "a"], ["abba"]]),
("zz", [["z", "z"], ["zz"]]),
("efe", [["e", "f", "e"], ["efe"]]),
("xyx", [["x", "y", "x"], ["xyx"]]),
("noon", [["n", "o", "o", "n"], ["n", "oo", "n"], ["noon"]]),
],
)
def test_partition(self, s: str, expected: list[list[str]]):
result = run_partition(Solution, s)
assert_partition(result, expected)
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
{
"problem_name": "palindrome_partitioning",
"solution_class_name": "Solution",
"problem_number": "131",
"problem_title": "Palindrome Partitioning",
"difficulty": "Medium",
"topics": "String, Dynamic Programming, Backtracking",
"readme_description": "Given a string `s`, partition `s` such that every substring of the partition is a **palindrome**. Return *all possible palindrome partitioning of `s`*.",
"_readme_examples": {
"list": [
{
"content": "```\nInput: s = \"aab\"\nOutput: [[\"a\",\"a\",\"b\"],[\"aa\",\"b\"]]\n```"
},
{
"content": "```\nInput: s = \"a\"\nOutput: [[\"a\"]]\n```"
}
]
},
"readme_constraints": "- `1 <= s.length <= 16`\n- `s` contains only lowercase English letters.",
"readme_additional": "",
"helpers_imports": "",
"helpers_content": "",
"helpers_run_name": "partition",
"helpers_run_signature": "(solution_class: type, s: str)",
"helpers_run_body": " implementation = solution_class()\n return implementation.partition(s)",
"helpers_assert_name": "partition",
"helpers_assert_signature": "(result: list[list[str]], expected: list[list[str]]) -> bool",
"helpers_assert_body": " # Sort inner lists and outer list for comparison\n # Note: Inner lists are partitions (lists of strings), order of partitions doesn't matter\n # Order of strings within a partition DOES matter (it must reconstruct s)\n # But wait, the problem says \"partition s\", so the order of substrings must match the order in s.\n # So we only need to sort the outer list of partitions.\n result_sorted = sorted(result)\n expected_sorted = 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 import logged_test\nfrom .helpers import assert_partition, run_partition\nfrom .solution import Solution",
"test_content": "",
"test_class_name": "PalindromePartitioning",
"test_class_content": " def setup_method(self):\n self.solution = Solution()",
"_solution_methods": {
"list": [
{
"name": "partition",
"signature": "(self, s: str) -> list[list[str]]",
"body": " # TODO: Implement partition\n return []"
}
]
},
"_test_helper_methods": {
"list": [
{
"name": "setup_method",
"parameters": "",
"body": "self.solution = Solution()"
}
]
},
"_test_methods": {
"list": [
{
"name": "test_partition",
"signature": "(self, s: str, expected: list[list[str]])",
"parametrize": "s, expected",
"test_cases": {
"list": [
"('aab', [['a', 'a', 'b'], ['aa', 'b']])",
"('a', [['a']])",
"('ab', [['a', 'b']])",
"('aa', [['a', 'a'], ['aa']])",
"('abc', [['a', 'b', 'c']])",
"('aba', [['a', 'b', 'a'], ['aba']])",
"('aaa', [['a', 'a', 'a'], ['a', 'aa'], ['aa', 'a'], ['aaa']])",
"('abba', [['a', 'b', 'b', 'a'], ['a', 'bb', 'a'], ['abba']])",
"('zz', [['z', 'z'], ['zz']])",
"('efe', [['e', 'f', 'e'], ['efe']])",
"('xyx', [['x', 'y', 'x'], ['xyx']])",
"('noon', [['n', 'o', 'o', 'n'], ['n', 'oo', 'n'], ['noon']])"
]
},
"body": " result = run_partition(Solution, s)\n assert_partition(result, expected)"
}
]
},
"playground_imports": "from helpers import run_partition, assert_partition\nfrom solution import Solution",
"playground_setup": "# Example test case\ns = 'aab'\nexpected = [['a', 'a', 'b'], ['aa', 'b']]",
"playground_run": "result = run_partition(Solution, s)\nresult",
"playground_assert": "assert_partition(result, expected)"
}