Given a string s, return all the palindromic permutations (without duplicates) of it. Return an empty list if no palindromic permutation could be form.
Example:
1 2 3 4 5
Input: "aabb" Output: ["abba", "baab"]
Input: "abc" Output: []
Hint: If a palindromic permutation exists, we just need to generate the first half of the string.
Analysis
Brute-Force
The brute-force solution is based on the same idea in 266. Palindrome Permutation I. Since we have to deal with duplicate cases, we apply the approach of using a hash set skip considered elements.
public List<String> generatePalindromes(String s) { List<String> result = newArrayList<>(); StringBuildersb=newStringBuilder(s); permute(0, s.length(), sb, result); return result; }
privatevoidpermute(int d, int n, StringBuilder sb, List<String> result) { if (d == n) { if (testPalindromicity(sb)) result.add(sb.toString()); return; } Set<Character> testSet = newHashSet<>(); for (inti= d; i < n; ++i) { charch= sb.charAt(i); if (testSet.contains(ch)) continue; testSet.add(ch); swap(sb, d, i); permute(d + 1, n, sb, result); swap(sb, d, i); } }
// swap characters in a StringBuilder privatevoidswap(StringBuilder sb, int i, int j) { chartemp= sb.charAt(i); sb.setCharAt(i, sb.charAt(j)); sb.setCharAt(j, temp); }
privatebooleantestPalindromicity(StringBuilder sb) { intn= sb.length(); for (inti=0; i < n / 2; ++i) { if (sb.charAt(i) != sb.charAt(n - i - 1)) returnfalse; } returntrue; }
Time: $O(N \times N!)$ Space: $O(N \times N!)$
Backtracking
To construct a palindrome we build the first half, append the middle character (odd case), and concatenate the reversed string of the first half.
Before the permutation, we need to know what characters we need to construct the first half, and also find out what the middle character is if it exists. It could be done in the function checkAndConstruct of counting occurrences (see the code for details).
The idea is not difficult, but the implementation is.
Note: If the count is odd and greater than $1$, this character could both lie in the first half and the middle position, e.g. "ababa".
privatevoidpermute(int d, int n, BuildInfo info, List<String> result) { if (d == n) { // only stops at left half StringBuilderreverseSb=newStringBuilder(info.sb.toString()); reverseSb.reverse(); result.add(info.sb.toString() + info.oddChar + reverseSb.toString()); return; } Set<Character> dupTestSet = newHashSet<>(); for (inti= d; i < n; ++i) { charch= info.sb.charAt(i); if (dupTestSet.contains(ch)) continue; dupTestSet.add(ch); swap(info.sb, d, i); permute(d + 1, n, info, result); swap(info.sb, d, i); } }
// swap characters in a StringBuilder privatevoidswap(StringBuilder sb, int i, int j) { chartemp= sb.charAt(i); sb.setCharAt(i, sb.charAt(j)); sb.setCharAt(j, temp); }