LeetCode Solutions

267. Palindrome Permutation II

Time: $O(n^n)$

Space: $O(|\texttt{ans}|)$

			

class Solution {
 public:
  vector<string> generatePalindromes(string s) {
    int odd = 0;
    unordered_map<char, int> count;

    // Get character occurrence
    for (const char c : s)
      ++count[c];

    // Count odd one
    for (const auto& [_, value] : count)
      if (value & 1)
        ++odd;

    // can't form any palindrome
    if (odd > 1)
      return {};

    vector<string> ans;
    vector<char> candidates;
    string mid;

    // Get mid and candidates characters
    for (const auto& [key, value] : count) {
      if (value & 1)
        mid += key;
      for (int i = 0; i < value / 2; ++i)
        candidates.push_back(key);
    }

    // Backtracking to generate our ans (strings)
    dfs(candidates, mid, vector<bool>(candidates.size()), "", ans);
    return ans;
  }

 private:
  // Generate all unique palindromes from candidates
  void dfs(const vector<char>& candidates, const string& mid,
           vector<bool>&& used, string&& path, vector<string>& ans) {
    if (path.length() == candidates.size()) {
      string secondHalf = path;
      reverse(begin(secondHalf), end(secondHalf));
      ans.push_back(path + mid + secondHalf);
      return;
    }

    for (int i = 0; i < candidates.size(); ++i) {
      if (used[i])
        continue;
      if (i > 0 && candidates[i] == candidates[i - 1] && !used[i - 1])
        continue;
      used[i] = true;
      path.push_back(candidates[i]);
      dfs(candidates, mid, move(used), move(path), ans);
      path.pop_back();
      used[i] = false;
    }
  }
};
			

class Solution {
  public List<String> generatePalindromes(String s) {
    int odd = 0;
    Map<Character, Integer> count = new HashMap<>();

    // Get character occurrence
    for (final char c : s.toCharArray())
      count.put(c, count.getOrDefault(c, 0) + 1);

    // Count odd one
    for (Map.Entry<Character, Integer> entry : count.entrySet())
      if (entry.getValue() % 2 == 1)
        ++odd;

    // can't form any palindrome
    if (odd > 1)
      return new ArrayList<>();

    List<String> ans = new ArrayList<>();
    List<Character> candidates = new ArrayList<>();
    StringBuilder mid = new StringBuilder();

    // Get mid and candidates characters
    for (Map.Entry<Character, Integer> entry : count.entrySet()) {
      final char key = entry.getKey();
      final int value = entry.getValue();
      if (value % 2 == 1)
        mid.append(key);
      for (int i = 0; i < value / 2; ++i)
        candidates.add(key);
    }

    // Backtracking to generate our ans (strings)
    dfs(candidates, mid, new boolean[candidates.size()], new StringBuilder(), ans);
    return ans;
  }

  // Generate all unique palindromes from candidates
  private void dfs(List<Character> candidates, StringBuilder mid, boolean[] used, StringBuilder sb,
                   List<String> ans) {
    if (sb.length() == candidates.size()) {
      ans.add(sb.toString() + mid + sb.reverse().toString());
      sb.reverse();
      return;
    }

    for (int i = 0; i < candidates.size(); ++i) {
      if (used[i])
        continue;
      if (i > 0 && candidates.get(i) == candidates.get(i - 1) && !used[i - 1])
        continue;
      used[i] = true;
      sb.append(candidates.get(i));
      dfs(candidates, mid, used, sb, ans);
      sb.deleteCharAt(sb.length() - 1);
      used[i] = false;
    }
  }
}
			

class Solution:
  def generatePalindromes(self, s: str) -> List[str]:
    # Get character occurrence
    count = Counter(s)

    # Count odd one
    odd = sum(value & 1 for value in count.values())

    # can't form any palindrome
    if odd > 1:
      return []

    ans = []
    candidates = []
    mid = ''

    # Get mid and candidates characters
    for key, value in count.items():
      if value & 1:
        mid += key
      for _ in range(value // 2):
        candidates.append(key)

    # Generate all unique palindromes from candidates
    def dfs(used: List[bool], path: List[chr]) -> None:
      if len(path) == len(candidates):
        ans.append(''.join(path) + mid + ''.join(path[::-1]))
        return

      for i, candidate in enumerate(candidates):
        if used[i]:
          continue
        if i > 0 and candidate == candidates[i - 1] and not used[i - 1]:
          continue
        used[i] = True
        path.append(candidate)
        dfs(used, path)
        path.pop()
        used[i] = False

    # Backtracking to generate our ans (strings)
    dfs([False] * len(candidates), [])
    return ans