Partition a string s into all possible combinations of substrings such that every substring is a palindrome.
We solve this with backtracking + DP precomputation:
- Precompute palindromes:
dp[i][j] = trueifs[i..j]is a palindrome. - Backtracking: Build the partition step-by-step using a temporary path:
- At each step, try every possible end index
end≥start. - Only append
s[start..end]to the path if it’s a palindrome (dp[start][end]). - Recurse with
start = end + 1.
- At each step, try every possible end index
- Once
start == n, the current path is a valid partition → add to results.
- Initialize
dp[n][n]and fill it using:
dp[i][j] = (s[i] == s[j]) && (j - i < 2 || dp[i+1][j-1])j - i < 2handles length 1 or 2 substrings.- Otherwise, a substring is palindrome if its ends match and the middle substring is palindrome.
-
Initialize an empty
path(vector) and reserve capacityn. -
Initialize the result container
resand optionally reserve space:res.reserve(1 << (n - 1)); // pre-allocate space for ~2^(n-1) possible partitions
-
Start backtracking from
start = 0. -
For each
endfromstartton-1:
- If
dp[start][end]is true:- Append
s.substr(start, end-start+1)to path. - Recurse with
start = end + 1. - Backtrack by popping the last substring from path.
- Append
- When
start == n, copy path into results.
- DP precomputation allows O(1) palindrome checks during backtracking.
- path as vector is a shared temporary container; must copy path into results, cannot move it.
- Using
path.reserve(n)reduces vector reallocations during recursion. - Backtracking ensures all partitions are generated without extra pruning.
- Time:
- DP precomputation: O(n²)
- Backtracking: O(2^n * n) in the worst case (exponential number of partitions, each with O(n) substrings)
- Space:
- O(n²) for dp + O(n) for recursion stack + O(n) for path storage