核心问题在于如何(快速)判断字母异位词,很容易想到字符串匹配里面的
RK算法
,其实就是一种编码方式。最简单的可以将每个单词的每个字母的
ascii码
加起来,因为字母异位词加起来得到的和必然是相同的,但是单词太多就可能冲突:不是字母异位词加起来也可能相同,既然加不行,可以乘啊,而且不一定非要用一个整数来编码,用字符串也可以,排序就是字符串的思路。
排序
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
vector<vector<string>> res;
unordered_map<string, vector<string>> m;
for(int i = 0; i < strs.size(); ++i){//排序
auto s = strs[i];
sort(s.begin(), s.end());
m[s].push_back(strs[i]);
}
for(const auto &v : m) res.push_back(v.second);
return res;
}
};
优化一下:
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
vector<string> res[strs.size()];
unordered_map<string, int> m;//int对应的是res中的下标
int cnt = 0;
for(const auto &s : strs){//排序
auto tmp = s;
sort(tmp.begin(), tmp.end());
if(!m.count(tmp)){
res[cnt].push_back(s);
m[tmp] = cnt++;
} else
res[m[tmp]].push_back(s);
}
return {res, res + cnt};
}
};
乘法编码
编码成一个数字的难点是需要考虑冲突问题,类似哈希冲突,而且字符串长的话,需要考虑溢出问题。借用题目评论里提到的质数思路:
class Solution {
public:
int m[26] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101};
vector<vector<string>> groupAnagrams(vector<string>& strs) {
vector<string> res[strs.size()];
unordered_map<int, int> map;//<编码值,res下标>
int cnt = 0, mod = 1e9+7;
for(const auto &s : strs){//排序
long v = 1;
for(const auto &c : s){
v *= m[c-'a'];
v %= mod;//取模防止溢出
}
if(!map.count(v)){
res[cnt].push_back(s);
map[v] = cnt++;
}else res[map[v]].push_back(s);
}
return {res, res + cnt};
}
};
版权声明:本文为qq_32523711原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。