LeetCode #131 Medium

Palindrome Partitioning

Split string s into pieces so every piece is a palindrome; return all such partitions.

backtrackingstringdp
Open on LeetCode ↗
02

Intuition

Choose the first piece, then the rest of the string is the same problem again. At each position try every palindromic prefix, recurse on the remainder, and backtrack. The palindrome check prunes whole subtrees the moment a prefix isn't one.

How to spot this pattern

Backtracking over cut points rather than elements: at each position, try every substring starting there, and recurse past whichever one you accepted. The palindrome test is the pruning — it stops whole branches before they're explored. Any "split the string into valid pieces" problem takes this shape.

03

Approach

1

Frame as choices at a cut point

From index start, every end where s[start:end+1] is a palindrome is a legal next piece.

2

Recurse and backtrack

Append the piece, recurse from end+1; when start reaches the end of the string the path is one complete answer. Pop and try the next cut.

3

Prune early

Non-palindromic prefixes are never extended — the check happens before recursion, keeping the tree small.

04

Solution & live demo

1class Solution:
2 def partition(self, s):
3 res, path = [], []
4 def is_pal(a, b):
5 while a < b:
6 if s[a] != s[b]: return False
7 a += 1; b -= 1
8 return True
9 def backtrack(start):
10 if start == len(s):
11 res.append(path[:]); return
12 for end in range(start, len(s)):
13 if is_pal(start, end):
14 path.append(s[start:end+1])
15 backtrack(end + 1)
16 path.pop()
17 backtrack(0)
18 return res
05

Common pitfalls

Recursing from start + 1 instead of end + 1

✗ Wrong
backtrack(start + 1)
✓ Right
backtrack(end + 1)

The piece just accepted spans start..end, so the next piece begins after end. Advancing by one re-consumes characters already placed and produces overlapping partitions.

Testing the whole string for palindromes up front

✗ Wrong
if s != s[::-1]: return []
✓ Right
if is_pal(start, end):
    path.append(s[start:end+1])

The pieces must be palindromes, not the input. "aab" isn't a palindrome yet partitions fine into ["a", "a", "b"].

Storing the path by reference

✗ Wrong
res.append(path)
✓ Right
res.append(path[:])

path is mutated as the search unwinds, so every stored reference ends up empty. The snapshot must be a copy taken at the moment the partition is complete.

06

Edge cases

Single character

Every 1-char string is a palindrome → [[c]].

All same letters, e.g. "aaa"

Every cut works — output size grows exponentially; that's inherent to the problem.

07

Complexity

Time
O(n · 2ⁿ)
Space
O(n)
Up to 2ⁿ⁻¹ partitions; recursion depth n.