Given a string, determine if a permutation of the string could form a palindrome.
Example 1:
Input: "code"
Output: false
Example 2:
Input: "aab"
Output: true
Example 3:
Input: "carerac"
Output: true
Hint:
- Consider the palindromes of odd vs even length. What difference do you notice?
- Count the frequency of each character.
- If each character occurs even number of times, then it must be a palindrome. How about character which occurs odd number of times?
這道題讓我們判斷一個字符串的全排列有沒有是回文字符串的,那么根據題目中的提示,我們分字符串的個數是奇偶的情況來討論,如果是偶數的話,由於回文字符串的特性,每個字母出現的次數一定是偶數次,當字符串是奇數長度時,只有一個字母出現的次數是奇數,其余均為偶數,那么利用這個特性我們就可以解題,我們建立每個字母和其出現次數的映射,然后我們遍歷 HashMap,統計出現次數為奇數的字母的個數,那么只有兩種情況是回文數,第一種是沒有出現次數為奇數的字母,再一個就是字符串長度為奇數,且只有一個出現次數為奇數的字母,參見代碼如下:
解法一:
class Solution { public: bool canPermutePalindrome(string s) { unordered_map<char, int> m; int cnt = 0; for (auto a : s) ++m[a]; for (auto a : m) { if (a.second % 2 == 1) ++cnt; } return cnt == 0 || (s.size() % 2 == 1 && cnt == 1); } };
那么我們再來看一種解法,這種方法用到了一個 HashSet,我們遍歷字符串,如果某個字母不在 HashSet 中,我們加入這個字母,如果字母已經存在,我們刪除該字母,那么最終如果 HashSet 中沒有字母或是只有一個字母時,說明是回文串,參見代碼如下:
解法二:
class Solution { public: bool canPermutePalindrome(string s) { unordered_set<char> st; for (auto a : s) { if (!st.count(a)) st.insert(a); else st.erase(a); } return st.empty() || st.size() == 1; } };
再來看一種 bitset 的解法,這種方法也很巧妙,我們建立一個 256 大小的 bitset,每個字母根據其 ASCII 碼值的不同都有其對應的位置,然后我們遍歷整個字符串,遇到一個字符,就將其對應的位置的二進制數 flip 一下,就是0變1,1變0,那么遍歷完成后,所有出現次數為偶數的對應位置還應該為0,而出現次數為奇數的時候,對應位置就為1了,那么我們最后只要統計1的個數,就知道出現次數為奇數的字母的個數了,只要個數小於2就是回文數,參見代碼如下:
解法三:
class Solution { public: bool canPermutePalindrome(string s) { bitset<256> b; for (auto a : s) { b.flip(a); } return b.count() < 2; } };
類似題目:
參考資料:
https://leetcode.com/problems/palindrome-permutation/