一、介绍
1.题目描述
题目链接:https://leetcode-cn.com/problems/group-anagrams/
给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。
字母异位词 是由重新排列源单词的字母得到的一个新单词,所有源单词中的字母都恰好只用一次。
2.测试样例
["eat", "tea", "tan", "ate", "nat", "bat"]
# [["bat"],["nat","tan"],["ate","eat","tea"]]
[""]
# [[""]]
["a"]
# [["a"]]
["","b",""]
# [["b"],["",""]]
["ac","c"]
# [["c"],["ac"]]
["ddddddddddg","dgggggggggg"]
# [["dgggggggggg"],["ddddddddddg"]]
二、题解
该方法如果用暴力实现,将达到n²的复杂度,必定会超时,因此需要考虑别的解决方案。
所想到的是优先队列或哈希
如果想单独处理空字符串,可以使用以下代码
// 清除并记录""
vector<vector<string>> ans;
int t=0; // t 标记是否出现过""
vector<string>::iterator it = strs.begin();
while(it != strs.end()){
if(*it==""){ // 如果有""
if(t==0){
ans.push_back(vector<string>());
t=1;
} // 插入答案并删除""
ans[0].push_back(*it);
strs.erase(it);
}
else it++;
}
1、优先队列🟢
由于优先队列可以实现对插入的元素排序,可以想到
1、先对每个字符串的内部字符排序
2、再对字符串进行串间排序,就可以得到各个字符组成相同的字符串个数。
-
需要同时存储字符串和其下标。
-
字符串,串内按字符排序代码:
sort(string.begin(),string.end())
以[“eat”, “”, “tan”, “ate”, “bat”]为例。
- 遍历,对字符串按字符排序(eat→aet)
- 将串内排序后的字符串和其在原数组中的下标(aet:0,"":1,ant:2,aet:3,abt:4)一起插入优先队列,得到优先队列 (ant:2,aet:3,aet:0,abt:4,"":1)
- 创建结果数组,插入第一个元素 [[“tan”]]。
- 遍历接下来的元素
- aet与ant不同,将原字符串插入新数组,得到[[“tan”],[“ate”]]
- aet与aet相同,将原字符串插入当前数组,得到 [[“tan”],[“ate”,“eat”]]
- ……
- 得到答案[[“tan”],[“ate”,“eat”],[“bat”],[""]]
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
vector<vector<string>> ans;
int n=strs.size();
int index=0,t=0;
priority_queue<pair<string,int>> q; // 优先队列,存储(字符串,在原数组中下标)
for(int i=0;i<n;i++){
string temp=strs[i];
sort(temp.begin(),temp.end()); // 串内按字符排序
q.emplace(temp,i); // 利用优先队列进行串间排序并记录下标
}
// 插入第一个答案
string temp=q.top().first;
ans.push_back(vector<string>());
ans[index].push_back(strs[q.top().second]);
q.pop();
while(!q.empty()){
if(temp==q.top().first){ // 同样的字符串插入同一个数组
ans[index].push_back(strs[q.top().second]);
}
else{ // 如果不同,加入新数组
temp=q.top().first;
ans.push_back(vector<string>());
ans[++index].push_back(strs[q.top().second]);
}
q.pop(); // 处理队头后弹出
}
return ans;
}
};
2、哈希🟡
第二种方法是使用哈希映射。对每个字符串进行串内排序后,遍历每个字符串
- 若该字符串未出现,将加入map,记录对应的答案数组中的下标
- 若该字符串出现过,在map对应的下标数组中插入该串的原字符串
以[“eat”, “”, “tan”, “ate”, “bat”]为例。
- 遍历,对当前字符串按字符排序(eat→aet)
- aet未在map中,map[aet]=0,数组第0行插入原字符串eat,答案数组[[“eat”]]
- ““未在map中,map[””]=1,数组第1行插入原字符串"",答案数组[[“eat”],[""]]
- ant未在map中,map[tan]=2,数组第2行插入原字符串tan,答案数组[[“eat”],[""],[“tan”]]
- aet在map中,因为map[aet]=0,数组第0行插入原字符串ate,答案数组[[“eat”,“ate”],[""],[“tan”]]
- ……
- 得到答案[[“eat”,“ate”],[""],[“tan”],[“bat”]]
参考链接:https://www.cnblogs.com/caiyishuai/p/15313213.html
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
vector<vector<string>> ans;
string temp;
map<string,int> map;
int n=strs.size(),index=0;
for(int i=0;i<n;i++){
temp=strs[i];
sort(temp.begin(),temp.end()); // 串内按字符排序
if(map.count(temp)){ // 如果map中已有,存储对应数组
ans[map[temp]].push_back(strs[i]);
}
else{ // 若没有,创建数组,添加map映射
map[temp]=index;
ans.push_back(vector<string>());
ans[index++].push_back(strs[i]);
}
}
return ans;
}
};