Every Way to Split a String Into Palindromic Pieces

Solve this Problem
Medium20–25 min
Topics
Companies
Practice:LeetCode ↗GFG ↗
Given a string s, find every way to cut it into consecutive pieces so that each individual piece reads the same forwards and backwards. A single character always qualifies on its own, so at minimum the all-single-character split always works — the question is which other, coarser splits also happen to work. Trying every possible cut pattern and validating the resulting partition afterward finds every answer, but it builds and discards a lot of doomed partitions along the way — one non-palindromic piece anywhere invalidates the whole thing, yet that's only discovered once every piece has already been carved out. Checking each piece the moment it's proposed, before it's ever added to the path, means a doomed choice costs only the check itself — nothing gets built around it first.

Test Case 1:

Input:s = "abba"
Output:[["a", "b", "b", "a"], ["a", "bb", "a"], ["abba"]]
Explanation:Three ways to cut "abba" so every piece reads the same forwards and backwards.

Test Case 2:

Input:s = "xyz"
Output:[["x", "y", "z"]]
Explanation:No two adjacent (or further) characters match, so single letters are the only palindromic pieces available — there's exactly one valid split.

Test Case 3:

Input:s = "q"
Output:[["q"]]
Explanation:A single character is always its own palindrome.

Constraints

  • 1 ≤ s.length ≤ 8
  • s consists only of lowercase English letters
  • Results are returned sorted (each partition compared element-by-element, shorter first on a tie) for a stable, checkable answer
🚀

Try the Dry Run

Don't just read the solution — watch it execute, one step at a time.

Approach & Solutions

Brute Force — Try Every Cut Pattern, Validate the Whole Partition

Brute

Between n characters there are n-1 possible cut points, and each one is independently either "cut here" or "don't" — a bitmask over those n-1 gaps enumerates every possible way to slice the string, 2ⁿ⁻¹ of them. Build the resulting pieces for each mask, then check every piece for being a palindrome only once the whole partition already exists. This finds every valid answer, but a partition with even one non-palindromic piece is still fully built out of substrings before that piece gets checked and the whole thing thrown away.

TimeO(2ⁿ · n)
SpaceO(2ⁿ · n)
1class Solution { 2 public String[][] allPalindromicPartitions(String s) { 3 int n = s.length(); 4 int gaps = n - 1; 5 List<String[]> result = new ArrayList<>(); 6 for (int mask = 0; mask < (1 << gaps); mask++) { 7 List<String> pieces = new ArrayList<>(); 8 int start = 0; 9 for (int g = 0; g < gaps; g++) { 10 if ((mask & (1 << g)) != 0) { 11 pieces.add(s.substring(start, g + 1)); 12 start = g + 1; 13 } 14 } 15 pieces.add(s.substring(start)); 16 boolean allPalindromes = true; 17 for (String piece : pieces) { 18 if (!isPalindrome(piece)) { 19 allPalindromes = false; 20 break; 21 } 22 } 23 if (allPalindromes) { 24 result.add(pieces.toArray(new String[0])); 25 } 26 } 27 Collections.sort(result, (a, b) -> { 28 int len = Math.min(a.length, b.length); 29 for (int i = 0; i < len; i++) { 30 int cmp = a[i].compareTo(b[i]); 31 if (cmp != 0) return cmp; 32 } 33 return a.length - b.length; 34 }); 35 return result.toArray(new String[0][]); 36 } 37 38 private boolean isPalindrome(String s) { 39 int i = 0, j = s.length() - 1; 40 while (i < j) { 41 if (s.charAt(i) != s.charAt(j)) return false; 42 i++; 43 j--; 44 } 45 return true; 46 } 47}

Optimal — Try Each Next Piece, Validate Before Recursing

Optimal

Build a partition left to right: at the current position, try every possible length for the next piece, but check whether that specific piece is a palindrome immediately — only if it passes does the search extend into it. A prefix that instantly fails, like the "c" onward in "ca", is rejected right there and never gets appended to the path or explored any further, unlike the brute-force version which builds a complete partition around it first. Every branch this search ever enters is one built entirely out of confirmed palindromic pieces.

TimeO(2ⁿ · n)
SpaceO(n)
1class Solution { 2 public String[][] allPalindromicPartitions(String s) { 3 List<String[]> result = new ArrayList<>(); 4 List<String> path = new ArrayList<>(); 5 backtrack(s, 0, path, result); 6 return result.toArray(new String[0][]); 7 } 8 9 private void backtrack(String s, int start, List<String> path, List<String[]> result) { 10 if (start == s.length()) { 11 result.add(path.toArray(new String[0])); 12 return; 13 } 14 for (int end = start; end < s.length(); end++) { 15 String piece = s.substring(start, end + 1); 16 if (isPalindrome(piece)) { 17 path.add(piece); 18 backtrack(s, end + 1, path, result); 19 path.remove(path.size() - 1); 20 } 21 } 22 } 23 24 private boolean isPalindrome(String s) { 25 int i = 0, j = s.length() - 1; 26 while (i < j) { 27 if (s.charAt(i) != s.charAt(j)) return false; 28 i++; 29 j--; 30 } 31 return true; 32 } 33}

Related Problems