题目:给出一组字符串,要求把由变化字母顺序而构成的单词(Anagram)归类。同一组中的单词要按字典序排列。
解法一:
把26个字母的出现次数存在vector中,作为key。把单词字符串组成的set作为value,存在一个map中。
代码:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
map<vector<int>, multiset<string>> f;
for(int i = 0 ; i < strs.size() ; i++) {
vector<int> feature(26, 0);
for(int j = 0 ; j < strs[i].length() ; j++) {
feature[strs[i][j] - 'a']++;
}
f[feature].insert(strs[i]);
}
vector<vector<string>> results;
for(auto i = f.begin() ; i != f.end() ; ++i) {
vector<string> tmp;
for(auto j = i->second.begin() ; j != i->second.end() ; ++j) {
tmp.push_back(*j);
}
results.push_back(tmp);
}
return results;
}
提交以后运行时间为128 ms。
解法二:
上一种解法的vector,string参数传递比较占用时间。所以key使用排序后的string,value使用单词的index组成的vector,再使用hashmap存放。
代码:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
unordered_map<string, vector<int>> f;
for(int i = 0 ; i < strs.size() ; i++) {
string s = strs[i];
sort(s.begin(), s.end());
f[s].push_back(i);
}
vector<vector<string>> results;
for(auto i = f.begin() ; i != f.end() ; ++i) {
vector<string> tmp;
for(auto j = i->second.begin() ; j != i->second.end() ; ++j) {
tmp.push_back(strs[*j]);
}
sort(tmp.begin(), tmp.end());
results.push_back(tmp);
}
return results;
}
提交后运行时间为72ms。
解法三:
自己实现hash函数。设p_i为第i个质数,则前26个质数对应26个小写字母,将每个字母的出现次数作为对应质数的幂次,求乘积。这样Anagram求出来的hash值肯定是相同的(数论中质因数分解的唯一性)。
代码:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
unordered_map<int, vector<int>> f;
int p[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103};
for(int i = 0 ; i < strs.size() ; i++) {
string s = strs[i];
int tmp = 1;
for(int j = 0 ; j < strs[i].length() ; j++)
tmp *= p[strs[i][j] - 'a'];
f[tmp].push_back(i);
}
vector<vector<string>> results;
for(auto i = f.begin() ; i != f.end() ; ++i) {
vector<string> tmp;
for(auto j = i->second.begin() ; j != i->second.end() ; ++j) {
tmp.push_back(strs[*j]);
}
sort(tmp.begin(), tmp.end());
results.push_back(tmp);
}
return results;
}
提交后运行时间仍然为72ms,估计这种方法如果自己实现hash容器会更快。