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:

Input: "aabb"
Output: ["abba", "baab"]

Example 2:

Input: "abc"
Output: []

Hint:

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

这道题是之前那道 Palindrome Permutation 的拓展,那道题只是让判断存不存在回文全排列,而这题让返回所有的回文全排列,此题给了我们充分的提示:如果回文全排列存在,只需要生成前半段字符串即可,后面的直接根据前半段得到。那么再进一步思考,由于回文字符串有奇偶两种情况,偶数回文串例如 abba,可以平均分成前后半段,而奇数回文串例如 abcba,需要分成前中后三段,需要注意的是中间部分只能是一个字符,可以分析得出,如果一个字符串的回文字符串要存在,那么奇数个的字符只能有0个或1个,其余的必须是偶数个,所以可以用哈希表来记录所有字符的出现个数,然后找出出现奇数次数的字符加入 mid 中,如果有两个或两个以上的奇数个数的字符,则返回空集,对于每个字符,不管其奇偶,都将其个数除以2的个数的字符加入t中,这样做的原因是如果是偶数个,将其一般加入t中,如果是奇数,如果有1个,除以2是0,不会有字符加入t,如果是3个,除以2是1,取一个加入t。等获得了t之后,t是就是前半段字符,对其做全排列,每得到一个全排列,加上 mid 和该全排列的逆序列就是一种所求的回文字符串,这样就可以得到所有的回文全排列了。在全排序的子函数中有一点需要注意的是,如果直接用数组来保存结果时,并且t中如果有重复字符的话可能会出现重复项,比如 t = "baa" 的话,那么最终生成的结果会有重复项,不信可以自己尝试一下。这里简单的说明一下,当 start=0,i=1 时,交换后得到 aba,在之后当 start=1,i=2 时,交换后可以得到 aab。但是在之后回到第一层当baa后,当 start=0,i=2 时,交换后又得到了 aab,重复就产生了。那么其实最简单当去重复的方法就是将结果 res 定义成 HashSet,利用其去重复的特性,可以保证得到的是没有重复的,参见代码如下:

解法一:

class Solution {
public:
vector<string> generatePalindromes(string s) {
unordered_set<string> res;
unordered_map<char, int> m;
string t = "", mid = "";
for (auto a : s) ++m[a];
for (auto it : m) {
if (it.second % == ) mid += it.first;
t += string(it.second / , it.first);
if (mid.size() > ) return {};
}
permute(t, , mid, res);
return vector<string>(res.begin(), res.end());
}
void permute(string &t, int start, string mid, unordered_set<string> &res) {
if (start >= t.size()) {
res.insert(t + mid + string(t.rbegin(), t.rend()));
}
for (int i = start; i < t.size(); ++i) {
if (i != start && t[i] == t[start]) continue;
swap(t[i], t[start]);
permute(t, start + , mid, res);
swap(t[i], t[start]);
}
}
};

下面这种方法和上面的方法很相似,不同之处来于求全排列的方法略有不同,上面那种方法是通过交换字符的位置来生成不同的字符串,而下面这种方法是通过加不同的字符来生成全排列字符串,参见代码如下:

解法二:

class Solution {
public:
vector<string> generatePalindromes(string s) {
vector<string> res;
unordered_map<char, int> m;
string t = "", mid = "";
for (auto a : s) ++m[a];
for (auto &it : m) {
if (it.second % == ) mid += it.first;
it.second /= ;
t += string(it.second, it.first);
if (mid.size() > ) return {};
}
permute(t, m, mid, "", res);
return res;
}
void permute(string &t, unordered_map<char, int> &m, string mid, string out, vector<string> &res) {
if (out.size() >= t.size()) {
res.push_back(out + mid + string(out.rbegin(), out.rend()));
return;
}
for (auto &it : m) {
if (it.second > ) {
--it.second;
permute(t, m, mid, out + it.first, res);
++it.second;
}
}
}
};

在来看一种利用了 std 提供的 next_permutation 函数来实现的方法,这样就大大减轻了我们的工作量,但是这种方法个人感觉算是有些投机取巧了,不知道面试的时候面试官允不允许这样做,贴上来拓宽一下思路也是好的:

解法三:

class Solution {
public:
vector<string> generatePalindromes(string s) {
vector<string> res;
unordered_map<char, int> m;
string t = "", mid = "";
for (auto a : s) ++m[a];
for (auto it : m) {
if (it.second % == ) mid += it.first;
t += string(it.second / , it.first);
if (mid.size() > ) return {};
}
sort(t.begin(), t.end());
do {
res.push_back(t + mid + string(t.rbegin(), t.rend()));
} while (next_permutation(t.begin(), t.end()));
return res;
}
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/267

类似题目:

Next Permutation

Palindrome Permutation

Permutations II

Permutations

参考资料:

https://leetcode.com/problems/palindrome-permutation-ii/

https://leetcode.com/problems/palindrome-permutation-ii/discuss/69696/AC-Java-solution-with-explanation

https://leetcode.com/problems/palindrome-permutation-ii/discuss/69698/Short-backtracking-solution-in-Java-(3-ms)

https://leetcode.com/problems/palindrome-permutation-ii/discuss/69767/22-lines-0ms-C%2B%2B-easy-to-understand

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Palindrome Permutation II 回文全排列之二的更多相关文章

  1. [LeetCode] 267. Palindrome Permutation II 回文全排列 II

    Given a string s, return all the palindromic permutations (without duplicates) of it. Return an empt ...

  2. [Leetcode] palindrome partition ii 回文分区

    Given a string s, partition s such that every substring of the partition is a palindrome. Return the ...

  3. LeetCode 266. Palindrome Permutation (回文排列)$

    Given a string, determine if a permutation of the string could form a palindrome. For example," ...

  4. [LeetCode] Palindrome Linked List 回文链表

    Given a singly linked list, determine if it is a palindrome. Follow up: Could you do it in O(n) time ...

  5. [LeetCode] Palindrome Partitioning 拆分回文串

    Given a string s, partition s such that every substring of the partition is a palindrome. Return all ...

  6. [LeetCode] Palindrome Number 验证回文数字

    Determine whether an integer is a palindrome. Do this without extra space. click to show spoilers. S ...

  7. LeetCode Palindrome Permutation II

    原题链接在这里:https://leetcode.com/problems/palindrome-permutation-ii/ 题目: Given a string s, return all th ...

  8. [Leetcode] Palindrome number 判断回文数

    Determine whether an integer is a palindrome. Do this without extra space. click to show spoilers. S ...

  9. [LeetCode] Palindrome Permutation 回文全排列

    Given a string, determine if a permutation of the string could form a palindrome. For example," ...

随机推荐

  1. ASP.NET Core 中文文档 第三章 原理(12)托管

    原文:Hosting 作者:Steve Smith 翻译:娄宇(Lyrics) 校对:何镇汐.许登洋(Seay) 为了运行 ASP.NET Core 应用程序,你需要使用 WebHostBuilder ...

  2. .Net语言 APP开发平台——Smobiler学习日志:如何快速实现地图定位时的地点微调功能

    Smobiler是一个在VS环境中使用.Net语言来开发APP的开发平台,也许比Xamarin更方便 样式一 一.目标样式 我们要实现上图中的效果,需要如下的操作: 二.地点微调代码 VB: Dim ...

  3. Java中的多线程你只要看这一篇就够了

    学习Java的同学注意了!!! 学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:279558494 我们一起学Java! 引 如果对什么是线程.什么是进程仍存有疑惑, ...

  4. 用C++实现的贪吃蛇游戏

    我是一个C++初学者,控制台实现了一个贪吃蛇游戏. 代码如下: //"贪吃蛇游戏"V1.0 //李国良于2016年12月29日编写完成 #include <iostream& ...

  5. java socket编程(li)

    一.网络编程中两个主要的问题 一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行数据传输.在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的路由,由IP地址可以 ...

  6. A2W、W2A、A2T、T2A的使用方法

    1.A2W和W2A 在<Window核心编程>,多字节和宽字节之间转换比较麻烦的,MultiByteToWideChar函数和WideCharToMultiByte函数有足够多的参数的意义 ...

  7. LAMP布署笔记

    源代码软件的优点:     获得最新版,能及时修复bug:     能自行修改和定制: 源代码打包形式:     .tar.gz和.tar.bz2格式居多: 完整性校验:     md5sum校验工具 ...

  8. Css3新特性总结之边框与背景(二)

    一.条纹背景 利用background为linear-gradient函数实现,linear-gradient取值如下: <angle>:角度,渐变的方向 to left right to ...

  9. wpf版扫雷游戏

    近来觉得wpf做出来的界面很拉风,自己也很喜欢搞些小游戏,感觉这做出来的会很炫,很装逼,(满足自己的一点小小的虚荣心)于是就去自学,发现感觉很不错,可是属性N多,太多了,而且质料也少,很多不会用,只会 ...

  10. Swift3 - String 字符串、Array 数组、Dictionary 字典的使用

    Swift相关知识,本随笔为 字符串.数组.字典的简单使用,有理解.使用错误的地方望能指正. ///************************************************** ...