LIKE CODING: LeetCode [267] Palindrome Permutation II
Given a string
For example:
Given
Given
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.
https://discuss.leetcode.com/topic/30850/java-6ms-solution-no-reversal-or-concat
https://discuss.leetcode.com/topic/22204/my-accepted-java-solution
The idea is to start recursion from the mid position, and copy char to left and right in the char array in-place until we reach the left and right ends.
elegant!. preaclloc a buffer and use String(char[]) constructor!
one suggestion to make less parameter is : left value is enough, since right can be calculated from left.
https://discuss.leetcode.com/topic/28020/short-backtracking-solution-in-java-3-ms
https://discuss.leetcode.com/topic/22204/my-accepted-java-solution
http://likesky3.iteye.com/blog/2238818
http://leetcode0.blogspot.com/2016/01/267-palindrome-permutation-ii.html
网上的解法,利用了一个char[] array, 来记录每次的变化。
http://blog.csdn.net/pointbreak1/article/details/48779125
Follow up
http://www.1point3acres.com/bbs/thread-209202-1-1.html
longest palindrome string from a give string, 比如“atatdc",可以返回”atdta" /"tadat"/"atcta"/"tacat",这个题目需要返回所有可能的结果。
Read full article from LIKE CODING: LeetCode [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.
https://discuss.leetcode.com/topic/30850/java-6ms-solution-no-reversal-or-concat
https://discuss.leetcode.com/topic/22204/my-accepted-java-solution
The idea is to start recursion from the mid position, and copy char to left and right in the char array in-place until we reach the left and right ends.
elegant!. preaclloc a buffer and use String(char[]) constructor!
one suggestion to make less parameter is : left value is enough, since right can be calculated from left.
public List<String> generatePalindromes(String s) {
int odd = 0;
String mid = "";
List<String> res = new ArrayList<>();
List<Character> list = new ArrayList<>();
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, map.containsKey(c) ? map.get(c) + 1 : 1);
odd += map.get(c) % 2 != 0 ? 1 : -1;
}
// cannot form any palindromic string
if (odd > 1) return res;
// step 2. add half count of each character to list
for (Map.Entry<Character, Integer> entry : map.entrySet()) {
char key = entry.getKey();
int val = entry.getValue();
if (val % 2 != 0) mid += key;
for (int i = 0; i < val / 2; i++) list.add(key);
}
// step 3. generate all the permutations
getPerm(list, mid, new boolean[list.size()], new StringBuilder(), res);
return res;
}
// generate all unique permutation from list
void getPerm(List<Character> list, String mid, boolean[] used, StringBuilder sb, List<String> res) {
if (sb.length() == list.size()) {
// form the palindromic string
res.add(sb.toString() + mid + sb.reverse().toString());
sb.reverse();//\\
return;
}
for (int i = 0; i < list.size(); i++) {
// avoid duplication
if (i > 0 && list.get(i) == list.get(i - 1) && !used[i - 1]) continue;
if (!used[i]) {
used[i] = true; sb.append(list.get(i));
// recursion
getPerm(list, mid, used, sb, res);
// backtracking
used[i] = false; sb.deleteCharAt(sb.length() - 1);
}
}
}
https://discuss.leetcode.com/topic/28020/short-backtracking-solution-in-java-3-ms
https://discuss.leetcode.com/topic/22204/my-accepted-java-solution
We only need to generate the first part of palindrome string, and the remaining part will be a middle character with the reverse of first part.
private List<String> list = new ArrayList<>();
public List<String> generatePalindromes(String s) {
int numOdds = 0; // How many characters that have odd number of count
int[] map = new int[256]; // Map from character to its frequency
for (char c: s.toCharArray()) {
map[c]++;
numOdds = (map[c] & 1) == 1 ? numOdds+1 : numOdds-1;
}
if (numOdds > 1) return list;
String mid = "";
int length = 0;
for (int i = 0; i < 256; i++) {
if (map[i] > 0) {
if ((map[i] & 1) == 1) { // Char with odd count will be in the middle
mid = "" + (char)i;
map[i]--;
}
map[i] /= 2; // Cut in half since we only generate half string
length += map[i]; // The length of half string
}
}
generatePalindromesHelper(map, length, "", mid);
return list;
}
private void generatePalindromesHelper(int[] map, int length, String s, String mid) {
if (s.length() == length) {
StringBuilder reverse = new StringBuilder(s).reverse(); // Second half
list.add(s + mid + reverse);
return;
}
for (int i = 0; i < 256; i++) { // backtracking just like permutation
if (map[i] > 0) {
map[i]--;
generatePalindromesHelper(map, length, s + (char)i, mid);
map[i]++;
}
}
}
http://likesky3.iteye.com/blog/2238818
先按照Palindrome Permutation 的方法判断输入字符串 s 能否排列成为一个回文串。通过检查开始构造过程,有两个思路:
思路1:按照leetcode的提示,我们仅需构造回文的前半部分。先利用前面判断过程中的map获得回文前半部分所有的字符,
相同字符排列在一起,然后按照Permutation II一题的思路获得前半部分所有的排列情况,最后组合回文的前后部分加入结果集。
思路2:从中间往两端递归构造回文串。
- // Method 1
- public List<String> generatePalindromes(String s) {
- List<String> ret = new ArrayList<String>();
- if (s == null || s.length() == 0) return ret;
- if (s.length() == 1) {ret.add(s); return ret;}
- int[] map = new int[256];
- for (int i = 0; i < s.length(); i++)
- map[s.charAt(i)]++;
- int oddCount = 0;
- int oddIdx = -1;
- StringBuilder half = new StringBuilder();
- for (int i = 0; i < 256; i++) {
- if ((map[i] & 1) == 1) {
- oddIdx = i;
- oddCount++;
- if (oddCount == 2) return ret;
- }
- int halfCount = map[i] / 2;
- for (int j = 0; j < halfCount; j++)
- half.append((char)i);
- }
- List<String> halfPermutation = new ArrayList<String>();
- getPermutation(half.toString().toCharArray(), new boolean[half.length()], new StringBuilder(), halfPermutation);
- for (String curr : halfPermutation) {
- StringBuilder curr2 = new StringBuilder(curr);
- if (oddIdx != -1)
- curr += (char)oddIdx;
- ret.add(curr + curr2.reverse().toString());
- }
- return ret;
- }
- public void getPermutation(char[] chars, boolean[] used, StringBuilder item, List<String> result) {
- if (item.length() == chars.length) {
- result.add(item.toString());
- } else {
- for (int i = 0; i < chars.length; i++) {
- if (used[i] || (i > 0 && chars[i] == chars[i - 1] && !used[i - 1]))
- continue;
- item.append(chars[i]);
- used[i] = true;
- getPermutation(chars, used, item, result);
- used[i] = false;
- item.deleteCharAt(item.length() - 1);
- }
- }
- }
- // Method 2
- public List<String> generatePalindromes2(String s) {
- List<String> ret = new ArrayList<String>();
- int[] map = new int[256];
- for (int i = 0; i < s.length(); i++)
- map[s.charAt(i)]++;
- int oddCount = 0;
- int oddIdx = -1;
- for (int i = 0; i < 256; i++) {
- if ((map[i] & 1) == 1) {
- oddIdx = i;
- oddCount++;
- if (oddCount == 2) return ret;
- }
- }
- String curr = "";
- if (oddIdx != -1) {
- curr += (char)oddIdx;
- map[oddIdx]--;
- }
- dfs(curr, map, s.length(), ret);
- return ret;
- }
- public void dfs(String curr, int[] map, int n, List<String> ret) {
- if (curr.length() < n) {
- for (int i = 0; i < map.length; i++) {
- if (map[i] > 0) {
- curr = (char)i + curr + (char)i;
- map[i] -= 2;
- dfs(curr, map, n, ret);
- curr = curr.substring(1, curr.length() - 1);
- map[i] += 2;
- }
- }
- } else {
- ret.add(curr);
- }
- }
- }
private List<String> list = new ArrayList<>();
public List<String> generatePalindromes(String s) {
int numOdds = 0; // How many characters that have odd number of count
int[] map = new int[256]; // Map from character to its frequency
for (char c: s.toCharArray()) {
map[c]++;
numOdds = (map[c] & 1) == 1 ? numOdds+1 : numOdds-1;
}
if (numOdds > 1) return list;
String mid = "";
int length = 0;
for (int i = 0; i < 256; i++) {
if (map[i] > 0) {
if ((map[i] & 1) == 1) { // Char with odd count will be in the middle
mid = "" + (char)i;
map[i]--;
}
map[i] /= 2; // Cut in half since we only generate half string
length += map[i]; // The length of half string
}
}
generatePalindromesHelper(map, length, "", mid);
return list;
}
private void generatePalindromesHelper(int[] map, int length, String s, String mid) {
if (s.length() == length) {
StringBuilder reverse = new StringBuilder(s).reverse(); // Second half
list.add(s + mid + reverse);
return;
}
for (int i = 0; i < 256; i++) { // backtracking just like permutation
if (map[i] > 0) {
map[i]--;
generatePalindromesHelper(map, length, s + (char)i, mid);
map[i]++;
}
}
}
public List<String> generatePalindromes(String s) {
List<String> result = new LinkedList<String>();
if (s == null)
return result;
char[] array = s.toCharArray();
Map<Character, Integer> map = new HashMap<Character, Integer>();
for (int i = 0; i < array.length; i++) {
char c = array[i];
map.put(c, map.getOrDefault(c, 0) + 1);
}
Character odd = null;
for (Map.Entry<Character, Integer> e : map.entrySet()) {
if (e.getValue() % 2 == 1) { // odd
if (odd != null) {
return result;
}
if (array.length % 2 == 0) {
return result;
}
odd = e.getKey();
}
}
if (odd == null) { // s is of even length
helper(array, result, map, array.length / 2 - 1, array.length / 2);
} else { // odd length
array[array.length / 2] = odd;
map.put(odd, map.get(odd) - 1);
helper(array, result, map, array.length / 2 - 1,
array.length / 2 + 1);
}
return result;
}
private void helper(char[] array, List<String> result,
Map<Character, Integer> map, int left, int right) {
if (left == -1) {
result.add(new String(array));
return;
}
for (Map.Entry<Character, Integer> e : map.entrySet()) {
if (e.getValue() >= 2) {
e.setValue(e.getValue() - 2);
array[left] = e.getKey();
array[right] = e.getKey();
helper(array, result, map, left - 1, right + 1);
e.setValue(e.getValue() + 2);
}
}
}
https://discuss.leetcode.com/topic/30850/java-6ms-solution-no-reversal-or-concat/2
https://leetcode.com/discuss/53626/ac-java-solution-with-explanation
public List<String> generatePalindromes(String s) {
public List<String> generatePalindromes(String s) {
List<String> result = new LinkedList<String>();
if (s == null)
return result;
char[] array = s.toCharArray();
Map<Character, Integer> map = new HashMap<Character, Integer>();
for (int i = 0; i < array.length; i++) {
char c = array[i];
map.put(c, map.getOrDefault(c, 0) + 1);
}
Character odd = null;
for (Map.Entry<Character, Integer> e : map.entrySet()) {
if (e.getValue() % 2 == 1) { // odd
if (odd != null) {
return result;
}
if (array.length % 2 == 0) {
return result;
}
odd = e.getKey();
}
}
if (odd == null) { // s is of even length
helper(array, result, map, array.length / 2 - 1, array.length / 2);
} else { // odd length
array[array.length / 2] = odd;
map.put(odd, map.get(odd) - 1);
helper(array, result, map, array.length / 2 - 1,
array.length / 2 + 1);
}
return result;
}
private void helper(char[] array, List<String> result,
Map<Character, Integer> map, int left, int right) {
if (left == -1) {
result.add(new String(array));
return;
}
for (Map.Entry<Character, Integer> e : map.entrySet()) {
if (e.getValue() >= 2) {
e.setValue(e.getValue() - 2);
array[left] = e.getKey();
array[right] = e.getKey();
helper(array, result, map, left - 1, right + 1);
e.setValue(e.getValue() + 2);
}
}
https://leetcode.com/discuss/53626/ac-java-solution-with-explanation
public List<String> generatePalindromes(String s) {
int odd = 0;
String mid = "";
List<String> res = new ArrayList<>();
List<Character> list = new ArrayList<>();
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, map.containsKey(c) ? map.get(c) + 1 : 1);
odd += map.get(c) % 2 != 0 ? 1 : -1;
}
// cannot form any palindromic string
if (odd > 1) return res;
// step 2. add half count of each character to list
for (Map.Entry<Character, Integer> entry : map.entrySet()) {
char key = entry.getKey();
int val = entry.getValue();
if (val % 2 != 0) mid += key;
for (int i = 0; i < val / 2; i++) list.add(key);
}
// step 3. generate all the permutations
getPerm(list, mid, new boolean[list.size()], new StringBuilder(), res);
return res;
}
// generate all unique permutation from list
void getPerm(List<Character> list, String mid, boolean[] used, StringBuilder sb, List<String> res) {
if (sb.length() == list.size()) {
// form the palindromic string
res.add(sb.toString() + mid + sb.reverse().toString());
sb.reverse();
return;
}
for (int i = 0; i < list.size(); i++) {
// avoid duplication
if (i > 0 && list.get(i) == list.get(i - 1) && !used[i - 1]) continue;
if (!used[i]) {
used[i] = true; sb.append(list.get(i));
// recursion
getPerm(list, mid, used, sb, res);
// backtracking
used[i] = false; sb.deleteCharAt(sb.length() - 1);
}
}
}
public
class
Solution {
public
List<String> generatePalindromes(String s) {
List<String> result =
new
ArrayList<>();
if
(s ==
null
|| s.length() ==
0
) {
return
result;
}
// Step 1: determine if the string s is palindrome permutated
Map<Character, Integer> map =
new
HashMap();
if
(!isPalindromePermutation(s, map)) {
return
result;
}
// Step 2: form the left half of the seed string
StringBuffer sb =
new
StringBuffer();
char
middle =
'\0'
;
Iterator it = map.entrySet().iterator();
while
(it.hasNext()) {
Map.Entry pair = (Map.Entry) it.next();
char
key = (
char
) pair.getKey();
int
val = (
int
) pair.getValue();
while
(val >
1
) {
sb.append(key);
val -=
2
;
}
if
(val ==
1
) {
middle = key;
}
}
// Step 3: gnerate the permutations of the string
permutation(sb.toString().toCharArray(),
0
, result);
List<String> result2 =
new
ArrayList<>();
// Step 4: append the right half of the string
for
(String str : result) {
StringBuffer tmp =
new
StringBuffer(str);
if
(middle !=
'\0'
) {
tmp.append(middle);
}
for
(
int
i = str.length() -
1
; i >=
0
; i--) {
tmp.append(str.charAt(i));
}
result2.add(tmp.toString());
}
return
result2;
}
private
boolean
isPalindromePermutation(String s, Map<Character, Integer> map) {
int
tolerance =
0
;
for
(
int
i =
0
; i < s.length(); i++) {
char
c = s.charAt(i);
if
(map.containsKey(c)) {
int
val = map.get(c);
map.put(c, val +
1
);
}
else
{
map.put(c,
1
);
}
}
Iterator it = map.entrySet().iterator();
while
(it.hasNext()) {
Map.Entry pair = (Map.Entry) it.next();
int
val = (
int
) pair.getValue();
if
(val %
2
==
1
) {
tolerance++;
}
}
if
(tolerance <=
1
) {
return
true
;
}
else
{
return
false
;
}
}
private
void
permutation(
char
[] s,
int
start, List<String> result) {
if
(start >= s.length) {
result.add(
new
String(s));
return
;
}
for
(
int
i = start; i < s.length; i++) {
if
(!containsDuplicate(s, start, i)) {
swap(s, i, start);
permutation(s, start +
1
, result);
swap(s, i, start);
}
}
}
private
void
swap(
char
[] s,
int
i,
int
j) {
char
temp = s[i];
s[i] = s[j];
s[j] = temp;
}
private
boolean
containsDuplicate(
char
[] s,
int
start,
int
end) {
for
(
int
i = start; i < end; i++) {
if
(s[i] == s[end]) {
return
true
;
}
}
return
false
;
}
}
//compute unique permutations of the first half palindrom
void bt(string halfs, int n, int pos, vector<string> &ret, int odd_cnt, char odd_char){
if
(pos==n){
string rev = halfs;
reverse(rev.begin(), rev.end());
if
(odd_cnt) halfs += odd_char;
ret.push_back(halfs+rev);
}
else
{
for
(int i=pos; i<n; ++i){
if
(i>pos && halfs[i]==halfs[pos])
continue
;
swap(halfs[i], halfs[pos]);
bt(halfs, n, pos+1, ret, odd_cnt, odd_char);
}
}
}
//compute first half of palindrome
string getHalfS(unordered_map<char, int> &hash, char &odd_char){
string halfs;
for
(auto h:hash){
if
(h.second%2==1){
odd_char = h.first;
h.second--;
}
for
(int i=0; i<h.second/2; ++i){
halfs += h.first;
}
}
return
halfs;
}
//compute the count of odd characters in string,
//if it is greater than 1, there's no palindrome permutaion
int getOddCnt(string s, unordered_map<char, int> &hash){
int odd_cnt = 0;
for
(auto c:s){
hash[c]++;
if
(hash[c]%2==1){
odd_cnt++;
}
else
{
odd_cnt--;
}
}
return
odd_cnt;
}
vector<string> generatePalindromes(string s) {
vector<string> ret;
unordered_map<char, int> hash;
int odd_cnt = getOddCnt(s, hash);
if
(odd_cnt>1)
return
ret;
char odd_char;
string halfs = getHalfS(hash, odd_char);
bt(halfs, halfs.size(), 0, ret, odd_cnt, odd_char);
return
ret;
}
public
List<String> generatePalindromes(String s) {
Map<Character,Integer> map =
new
HashMap<Character,Integer>();
for
(
int
i =
0
;i<s.length();i++){
char
ch = s.charAt(i);
map.put(ch, map.containsKey(ch) ? map.get(ch)+
1
:
1
);
}
return
helper(map);
}
private
List<String> helper(Map<Character,Integer> map){
List<String> list =
new
LinkedList<String>();
// declare new LinkedList to avoid ConcurrentModificationException
for
(Character ch :
new
LinkedList<Character>(map.keySet())){
int
count = map.get(ch);
if
(map.size()==
1
){
// only one char, we can use
char
[] tmp =
new
char
[count];
Arrays.fill(tmp,ch);
list.add(
new
String(tmp));
return
list;
}
if
(count ==
1
)
// if all odd #, will get an empy list
continue
;
map.put(ch,count-
2
);
if
(count ==
2
)
map.remove(ch);
List<String> lessList = helper(map);
for
(String str : lessList)
list.add(
""
+ch+str+ch);
map.put(ch,count);
}
return
list;
}
- 观察原因,应该是过多生成了新的Set()对象??????????????
- 每次都是旧的String + 新String,这样导致,要生成一个String with length n, we need O(n^2) space and time complexity to
网上的解法,利用了一个char[] array, 来记录每次的变化。
http://blog.csdn.net/pointbreak1/article/details/48779125
Follow up
http://www.1point3acres.com/bbs/thread-209202-1-1.html
longest palindrome string from a give string, 比如“atatdc",可以返回”atdta" /"tadat"/"atcta"/"tacat",这个题目需要返回所有可能的结果。
Read full article from LIKE CODING: LeetCode [267] Palindrome Permutation II