Every Way to Split a String Into Palindromic Pieces
Solve this Problems, 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:
Test Case 2:
Test Case 3:
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
BruteBetween 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.
O(2ⁿ · n)O(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
OptimalBuild 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.
O(2ⁿ · n)O(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}