Question

Formatted question description: https://leetcode.ca/all/267.html

 267	Palindrome Permutation II

 Given a string s, return all the palindromic permutations (without duplicates) of it.
 Return an empty list if no palindromic permutation could be form.

 For example:

 Given s = "aabb", return ["abba", "baab"].

 Given s = "abc", return [].

 Hint:

 If a palindromic permutation exists, we just need to generate the first half of the string.
 To generate all distinct permutations of a (half of) string, use a similar approach from: Permutations II or Next Permutation.

Algorithm

One thing to note is that if you use an array to save the result directly, and if there are repeated characters in t, there may be duplicates, such as t = “baa”, then the final result will have duplicates

  • When start=0 and i=1, aba is obtained after the exchange,
  • Later when start=1 and i=2, aab can be obtained after the exchange.
  • But after returning to the first layer after baa, when start=0, i=2, aab is obtained after the exchange, and repetition occurs.

In fact, the easiest way to de-duplicate is to define the result res as a HashSet, and use its de-duplication feature to ensure that there is no duplicate.

Code

Java

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Palindrome_Permutation_II {
    public static void main(String[] args) {
        Palindrome_Permutation_II out = new Palindrome_Permutation_II();
        Solution s = out.new Solution();

        System.out.println(s.generatePalindromes("aabb"));
        System.out.println(s.generatePalindromes("aaaa"));
        System.out.println(s.generatePalindromes("aaaaa"));
    }

    public class Solution_lesscode {
        public List<String> generatePalindromes(String s) {
            int[] cha = new int [256];
            for (int i = 0; i < s.length(); i ++) {
                cha[s.charAt(i)] += 1;
            }
            List<String> result = new LinkedList<String>();
            boolean odd = false;
            int oddIndex = 0;
            for (int i = 0; i < 256; i ++) {
                if (cha[i] % 2 == 1) {
                    if (odd == true) {
                        return result;
                    }
                    oddIndex = i;
                    odd = true;
                }
            }

            String base = "";
            if (odd == true) {
                base = (char)oddIndex + "";
                cha[oddIndex] -= 1;
            }
            process(base, cha, s.length(), result);
            return result;
        }
        private void process(String base, int[] cha, int n, List<String> result) {
            if (base.length() == n) {
                result.add(base);
                return;
            }
            for (int i = 0; i < cha.length; i ++) {
                if (cha[i] > 0) {
                    cha[i] -= 2;
                    process((char)i + base + (char)i, cha, n, result);
                    cha[i] += 2;
                }
            }
        }
    }

    class Solution {
        public List<String> generatePalindromes(String s) {

            List<String> result = new ArrayList<>();

            int odd = 0;

            // char => its count
            Map<Character, Integer> map = new HashMap<>();

            // step 1. build character count map and count odds
            for (int i = 0; i < s.length(); i++) {
                char c = s.charAt(i);
                map.put(c, 1 + map.getOrDefault(c, 0));
                odd += map.get(c) % 2 != 0 ? 1 : -1;
            }

            // cannot form any palindromic string
            if (odd > 1) {
                return result;
            }

            // step 2. add half count of each character to list
            String mid = "";
            List<Character> charList = new ArrayList<>();
            for (Map.Entry<Character, Integer> entry : map.entrySet()) {
                char key = entry.getKey();
                int val = entry.getValue();

                if (val % 2 != 0) { // odd count char
                    mid += key;
                }

                for (int i = 0; i < val / 2; i++) {
                    charList.add(key);
                }
            }

            // step 3. generate all the permutations
            getPerm(charList, mid, new boolean[charList.size()], new StringBuilder(), result);

            return result;
        }

        // generate all unique permutation from list, sb: cur_res
        void getPerm(List<Character> list, String midChar, boolean[] used, StringBuilder sb, List<String> result) {
            if (sb.length() == list.size()) {
                // form the palindromic string
                result.add(sb.toString() + midChar + sb.reverse().toString());
                sb.reverse(); // restore
                return;
            }

            for (int i = 0; i < list.size(); i++) {
                // avoid duplication
                if (i > 0 && list.get(i) == list.get(i - 1) && !used[i - 1]) { // i-1 must already checked, so skip used[i - 1]==false
                    continue;
                }

                if (!used[i]) {
                    used[i] = true;
                    sb.append(list.get(i));
                    // recursion
                    getPerm(list, midChar, used, sb, result);
                    // backtracking
                    used[i] = false;
                    sb.deleteCharAt(sb.length() - 1);
                }
            }
        }
    }
}

All Problems

All Solutions