题目(中等)
给你一个字符串数组 words 。words 中每个元素都是一个包含 两个 小写英文字母的单词。
请你从 words 中选择一些元素并按 任意顺序 连接它们,并得到一个 尽可能长的回文串 。每个元素 至多 只能使用一次。
请你返回你能得到的最长回文串的 长度 。如果没办法得到任何一个回文串,请你返回 0 。
回文串 指的是从前往后和从后往前读一样的字符串。
示例 1:
输入:words = [“lc”,“cl”,“gg”]
输出:6
解释:一个最长的回文串为 “lc” + “gg” + “cl” = “lcggcl” ,长度为 6 。
“clgglc” 是另一个可以得到的最长回文串。
示例 2:
输入:words = [“ab”,“ty”,“yt”,“lc”,“cl”,“ab”]
输出:8
解释:最长回文串是 “ty” + “lc” + “cl” + “yt” = “tylcclyt” ,长度为 8 。
“lcyttycl” 是另一个可以得到的最长回文串。
示例 3:
输入:words = [“cc”,“ll”,“xx”]
输出:2
解释:最长回文串是 “cc” ,长度为 2 。
“ll” 是另一个可以得到的最长回文串。“xx” 也是。
提示:
1 <= words.length <= 105
words[i].length == 2
words[i] 仅包含小写英文字母。
思路
看数据范围,1e5,用暴力两两配对尝试必然超时,所以用哈希表分情况计数;
对于叠词,如果成对出现,可以加入答案,如果有单独的,只能在中间多加一个;
对于普通词tmp,能配对的只有它和它回文符串couple,这两个字符串中出现次数最小的min(nomal[tmp], nomal[couple])次数才能配对成功,多余部分不能加入答案。
为避免重复计数,每次加入后清除该字符串的计数
代码
class Solution {
public:
int longestPalindrome(vector<string>& words) {
int ans = 0;
unordered_map<char, int> same; //存叠词及其出现次数
unordered_map<string, int> nomal; //存普通词及其次数
for(auto word : words) {
if(word[0] == word[1]) same[word[0]]++;
else nomal[word]++;
}
int flag_same = 0;
for(auto x : same) {
if(x.second % 2 == 0) ans += x.second * 2; //成对叠词可组队
else {
flag_same = 1;
ans += (x.second / 2) * 4; //偶数部分配对
}
}
ans += flag_same * 2; //最多允许一个叠词横跨
for(auto x : nomal) {
string tmp = x.first;
if(nomal[tmp] == 0) continue;
string couple;
couple.push_back(tmp[1]);
couple.push_back(tmp[0]);
ans += min(nomal[tmp], nomal[couple]) * 4;
nomal[tmp] = 0;
nomal[couple] = 0;
}
return ans;
}
};