一、概述
輸入若干個單詞,要求將其分組,分組依據爲組成字母相同的元素爲一組。
這個。。。咋一看沒有思路。後來用很笨的做法做出來,時空複雜度都很可憐。
二、分析
1、我的方法
這題噁心在哪呢?噁心就噁心在相當於給你一個單詞,你要知道組成這個單詞的全排列,之後輸入的單詞要是在這個全排列裏面,那就和它歸爲一類,否則不歸爲一類。
最極端的情況,對於好多特別長的單詞,都不屬於同一類,那麼需要各自找全排列,這就效率太低了。
但是不找全排列就不行,因爲字母順序在這裏擋着,如果能無視順序只看字母存在就好了。
用哈希?那要是一個字母出現好幾遍怎麼辦。我還得分別計數麼,太麻煩了。
爲什麼不把輸入的單詞全排成一個順序呢?如果所有輸入的單詞都是一樣的單詞順序,那麼對於由相同字母組成的單詞,它們在排序後一定一模一樣。這就是我的思路:
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
unordered_set<string> example;
unordered_map<string,int> example_list;
vector<vector<string>> res;
int ex_num=0;
for(int i=0;i<strs.size();++i)
{
string tmp=strs[i];
string tmp1=tmp;
sort(tmp1.begin(),tmp1.end());
if(example.find(tmp1)==example.end())
{
example_list[tmp1]=ex_num;
vector<string> new_ex;
new_ex.push_back(tmp);
res.push_back(new_ex);
example.insert(tmp1);
ex_num++;
}
else
{
res[example_list[tmp1]].push_back(tmp);
}
}
return res;
}
};
首先我們明確一個定義:每個輸入的單詞,都有一個對應的example,這個example是組成這個單詞的所有字母的排列,順序爲字母表順序。然後維護兩個數據結構:set和map。set儲存單詞的example,map儲存example與結果的二維數組的行數的映射。
每當我輸入一個單詞,首先找到他的example,然後在set中找,若找到,去map中找到它對應存在第幾行,push進去;如果沒找到,那麼就新起一行放進去,更新set和map。
sort排序所需時間爲mlogm,set尋找時間爲slogs,總共一次循環。那麼總的時間複雜度爲O(n*(max(mlogm,slogs)))。實際上是很大的。
2、較好的方法
實際上我的方法已經是較好的方法了(最好的方法設置了一個數組裏面全是質數不知道用來做什麼),只不過實現的太蠢了。較好的實現方法如下:
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
vector<vector<string>> result;
unordered_map<string, vector<string>> map;
for(string str : strs){
string copy = str;
sort(str.begin(), str.end());
map[str].push_back(copy);
}
for(auto it = map.begin(); it != map.end(); ++it){
result.push_back(it->second);
}
return result;
}
};
map直接是string和vector<string>的映射,比我這個string和int的映射好很多,效率高了大概一倍。
三、總結
將無序的個體進行分類,分類的標準是組成元素,那麼思路就是先把無序變爲有序,然後再分類即可。