The problem. Given a string s, split it into pieces so that every piece is a palindrome. Return all the possible splits.
s = "aab" -> [["a", "a", "b"], ["aa", "b"]]
s = "a" -> [["a"]]
s = "aba" -> [["a", "b", "a"], ["aba"]]Each call has a start position — everything before it is already split. The choices are where the next piece ends: any end from start to the last index. A choice is allowed only if s[start..end] is a palindrome; then recurse from end + 1. When start reaches the end of the string, the pieces so far are a complete answer. The palindrome check is the pruning — a non-palindrome piece cuts off its whole subtree.
Try each possible next piece; only palindromic pieces are explored further.
function partition(s) { const result = []; const path = []; const isPal = (i, j) => { while (i < j) if (s[i++] !== s[j--]) return false; return true; }; const cut = (start) => { if (start === s.length) { // the whole string is split result.push([...path]); return; } for (let end = start; end < s.length; end++) { if (!isPal(start, end)) continue; // prune: this piece isn't a palindrome path.push(s.slice(start, end + 1)); // choose the piece s[start..end] cut(end + 1); // split the rest path.pop(); } }; cut(0); return result;}Time O(n · 2ⁿ): a string of n equal letters has 2ⁿ⁻¹ splits, and each palindrome check is O(n). Space O(n) for the path and the call stack.
The same s[i..j] is checked again and again from different branches. Fill a table first: pal[i][j] is true when s[i] == s[j] and the inside, pal[i+1][j−1], is a palindrome (or there is no inside). Then every check during the search is O(1).
function partition(s) { const n = s.length; const pal = Array.from({ length: n }, () => new Array(n).fill(false)); for (let i = n - 1; i >= 0; i--) { for (let j = i; j < n; j++) { pal[i][j] = s[i] === s[j] && (j - i < 2 || pal[i + 1][j - 1]); // ends match, inside is a palindrome } } const result = []; const path = []; const cut = (start) => { if (start === n) { result.push([...path]); return; } for (let end = start; end < n; end++) { if (!pal[start][end]) continue; // O(1) check now path.push(s.slice(start, end + 1)); cut(end + 1); path.pop(); } }; cut(0); return result;}Time O(n · 2ⁿ) still (the output can be that big), but each check is O(1) after an O(n²) table. Space O(n²) for the table. Backtracking plus a DP table is a common pairing in hard problems.
[["a"]]."abc": only single letters.