面试题 01.04. 回文排列

原题目

面试题 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();	 // 将所有位翻转
    
posted @ 2020-12-21 22:45  Cigar丶  阅读(94)  评论(0编辑  收藏  举报