QUESTION
easy
题目描述
给定一个包含大写字母和小写字母的字符串,找到通过这些字母构造成的最长的回文串。
在构造过程中,请注意区分大小写。比如 “Aa” 不能当做一个回文字符串。
示例 1:
输入: "abccccdd"
输出: 7
解释:
我们可以构造的最长的回文串是"dccaccd", 它的长度是 7。
说明
假设字符串的长度不会超过 1010。
SOLUTION
- 如果一个字符出现偶数次,那么它必定对于构造回文串有帮助
- 如果一个字符出现奇数次,那么它的(奇数次 - 1)也可以用于构造回文串
- 每个回文串可以出现一个奇数次的字符
方法一
据前面的分析,关键点就在奇数次的字符,我们可以用一个映射来记录每个字符出现的次数,然后将偶数相加,奇数 - 1 再加,最后再 + 1。(注意这是在给出的字符串中出现了奇数次的字符的情况,如果没有奇数次字符最后不用再 + 1)
class Solution {
public:
int longestPalindrome(string s) {
int res = 0, flag = 0;
unordered_map<char, int> m;
for(char c : s) m[c]++;
for(auto cnt : m) {
if(!(cnt.second&1)) res += cnt.second;
else {
res += cnt.second - 1;
flag = 1;
}
}
return res + flag;
}
};
方法二
根据方法一积累的经验,我们可以用另外一种思路。由于无论每个字符的出现次数的奇偶,这道题中每个字符都可以帮助构造回文串,但奇数次的字符需要减 1,故我们只记录有多少个奇数次的字符,用字符串的总大小减去奇数次字符的个数,最后再 + 1 即可(因为每个回文串可以出现一个奇数次的字符),但要注意如果没有奇数次的字符,则不需要再 + 1;
class Solution {
public:
int longestPalindrome(string s) {
unordered_set<char> nset;
for (char c : s) {
if (!nset.count(c)) nset.insert(c);
else nset.erase(c);
}
if(nset.size() == 0) return s.size();
return s.size() - nset.size() + 1;
}
};