字母异位词分组
题目描述:给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。字母异位词 是由重新排列源单词的字母得到的一个新单词,所有源单词中的字母通常恰好只用一次。
解法一:暴力/哈希表
简单的暴力算法,题目要求是字母异或词,也就是说异或词的每个字母是相同的,只不过排列的顺序不一样。基于这个,我的想法是:将每个词进行一次排列,那么互为字母异或词的单词经过排列后一定是相等的。所以,先复制一遍输入的词,将他里面的每个词进行一次排序,然后依次找到相同的单词的坐标,把相同的单词加入结果即可得到答案。
步骤:
1、将各个字符串排序
2、遍历每个字符串
3、寻找相同的字符串,并记录下标
4、将相同的字符串添加到结果里
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
vector<string> temp = strs;
vector<vector<string>> groudWords;
int len = strs.size();
int *visited = new int[len];
if(len == 0) return groudWords;
for(int i = 0; i < len; i++)
{
sort(temp[i].begin(), temp[i].end());
}
for(int i = 0; i < len; i++)
{
if(visited[i] == 1)
{
continue;
}
groudWords.push_back(attemdGroudWords(temp, strs, i, visited));
}
return groudWords;
}
vector<string> attemdGroudWords(vector<string>& temp, vector<string>& strs, int index, int* visited)
{
vector<string> groudWord;
for(int i = index; i < temp.size(); i++)
{
if(temp[i] != temp[index] || visited[i] == 1)
{
continue;
}
visited[i] = 1;
groudWord.push_back(strs[i]);
}
return groudWord;
}
};
这是我第一次的解法,提交后发现时间复杂度度太大了,关是将每个单词排序的时间复杂度都需要O(n*m)(n是单词数,m是单词的长度)。后来我看了答案发现可以用哈希表进行优化。
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
unordered_map<string, vector<string>> mp;
vector<vector<string>> combineWordGroups;
int len = strs.size();
if(len == 0)
return combineWordGroups;
for(int i = 0; i < len; i++)
{
string str = strs[i];
sort(str.begin(), str.end());
mp[str].push_back(strs[i]);
}
int mpLen = mp.size();
for(unordered_map<string, vector<string>>::iterator it = mp.begin(); it != mp.end(); it++)
{
combineWordGroups.push_back(it->second);
}
return combineWordGroups;
}
};
优化后时间复杂度变为O(nklogk),其中n是单词的数量,k是strs中的字符串的最大长度。
解法二:数值替代法。
这个是我在评论区看到的解法,感觉挺有意思的就记录下来了。首先将每个字母定义一个数字,比如a对应的就是1,d对应的是2…,由于互为异或词的单词组成是相同的,那么这两个单词所组成的字母的数字和也一定是相同的,也就是说"abc"和"bca"互为异或词,"abc"对应的数值是1+2+3=6,"bca"对应的数值是2+3+1=6。基于这个规律就可以解出来了。
反思
这道题虽然写对了,思路也和正确答案一样,但是写出来的时间复杂度太高了,没有用最正确的代码将思路表达出来。原因是对数据结构不熟悉,没有一开始就想到哈希表。以后写题的时候会优先考虑数据结构。