原题目
面试题 01.04. 回文排列
给定一个字符串,编写一个函数判定其是否为某个回文串的排列之一。
回文串是指正反两个方向都一样的单词或短语。排列是指字母的重新排列。
回文串不一定是字典当中的单词。
示例1:
输入:"tactcoa"
输出:true(排列有"tacocat"、"atcocta",等等)
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/palindrome-permutation-lcci/
第一遍解法
哈希表,使用哈希表来保存每个字母出现的次数。当字母的次数出现一次以上(>=2)的奇数时,则认为不可回文排列。
class Solution {
public:
bool canPermutePalindrome(string s) {
unordered_map<char, int> count_map;
for (int i = 0; i < s.size(); i++) {
++count_map[s[i]];
}
int cnt = 0;
for (auto item : count_map) {
if (item.second % 2) {
cnt++;
}
}
return cnt > 1 ? false : true;
}
};
时间复杂度: O(n)
因为字母只有26个,为常数,所以空间复杂度: O(1)
网上好的解法
使用bitset来保存每个字符出现的次数。奇数次相应的位为1,偶数次相应的位为0。思路与哈希表一样,也是看奇数的次数是否大于等于两次。
class Solution {
public:
bool canPermutePalindrome(string s) {
bitset<128> bits; // 定义一个128位的数据结构,初始每一位为0
for (char c : s) {
bits.flip(c); // 位翻转,0->1, 1->0
}
return bits.none() || bits.count() == 1; // 若每个位都为0, 则bits.none()为true。 bits.count()为位为1的个数。
}
};
作者:942580475
链接:https://leetcode-cn.com/problems/palindrome-permutation-lcci/solution/wei-yun-suan-shi-yong-c-bitset-4xing-dai-ma-jie-ju/
来源:力扣(LeetCode)
时间复杂度: O(n)
空间复杂度: O(1)
最后的代码
bitset,优化了一下最后的返回条件。 认为只要奇数次数小于2,则认为原字符串可以回文排列。
class Solution {
public:
bool canPermutePalindrome(string s) {
bitset<128> bits;
for (char c : s) {
bits.flip(c);
}
return bits.count() < 2;
}
};
哈希表,在for循环中使用const type &的方式,避免了多余的拷贝。 同时精简了第一次解法中的return。
class Solution {
public:
bool canPermutePalindrome(string s) {
unordered_map<char, int> count_map;
for (const char &c : s) { // 使用const char&的for(:)循环,避免了拷贝。
++count_map[c];
}
int cnt = 0;
for (const auto &item : count_map) { // 原因同上for(:)
if (item.second % 2) {
cnt++;
}
}
return cnt < 2; // 精简了return
}
};
小结
-
解字符串类型的题目时,要首先想到哈希表。
-
map和set为有序的关联容器,底层为红黑树。
-
unordered_map和unordered_set为无序的关联容器,底层为哈希表,
-
for循环如果只是遍历,那么用const type&会提升效率。
-
bitset是一种表示位集合的数据结构,下面总结bitset常用方法。
// 初始化,n位的集合,初始值均为0 bitset<n> bits; // bits中是否存在置位的二进制 bits.any(); // bits中所有位都置位了吗? bits.all(); // bits中所有位都复位了吗? bits.none(); // 返回bits中置位的个数 bits.count(); // 置位 bits.set(pos); // 将pos下标的位置1 bits.set(); // 将所有位置1 // 复位 bits.reset(pos); // 将pos下标的位置0 bits.reset(); // 将所有位置0 // 翻转 bits.flip(pos); // 将pos下标的位翻转。 0->1 或 1->0。 bits.flip(); // 将所有位翻转