题目:Given an array of strings, return all groups of strings that are anagrams.
Note: All inputs will be in lower-case.
题意:给一个字符串数组,找出其中的所有的anagram组。anagram的意思是不同的单词但是含有相同的字符,这样的单词就称作anagram,比如veil,live,evil,vile。
思路:比如veil,live,evil,vile,对它们的字符进行排序后四者都是eilv,所以很简单的一个想法就是使用hash,hash的键就是排序后的字符串,比如上面提到的eivl。那么对应的值该存什么呢?由于每次都是先对字符串比如(A[i])排序然后查找该排序值temp是否出现过,如果出现那么就将该字符串A[i]存入到anagram的集合中去。但是该anagram组出现的第一个字符串如何处理呢(比如以上,首先扫描到veil的时候将eilv存入到hash中去,但是此时不知道后面是否还会出现排序后是eilv的字符串,所以veil不会放到结果值中去,必须等到后面发现有元素排序后也是eilv才应该将veil存入到结果值中去),最简单的方法从下标0的元素扫描到下标i-1的元素,查看哪个排序后是与temp值相等。但是这是很低效的。比如一个数组前面有一万个非anagram的单词,第10001个是veil,第10002个是live,那么查找veil时需要再扫描10000个,时间复杂度在最差的情况下会变成O(n*n).
解决方法是map的键对应的值保存第一个元素(比如上文提到的veil)。并且加个标志位,使扫描到后面该键时判断是否需要将第一个元素加入,第一个字符串只需要加入一次,加入后就修改该标志位。比如当第一次扫描到veil时存入map[eilv] = “Fveil”,那么接下来扫描到live时由于live排序后也是eilv,所以把live存入结果值,同样把veil存入到结果值中去,并把map[eivl] = “veil”。当扫描到evil时将evil存入,但是不需要将该组第一个元素veil存入,因为veil已经被存入到结果值中去了,判断依据是此时map[eivl]对应的是字符串开头不是’F’。
以上
代码如下:
class Solution {
public:
vector<string> anagrams(vector<string>& strs) {
vector<string> result;
if(strs.size() == 0)return result;
unordered_map<string,string> dict;
for(int i = 0; i < strs.size(); i++){
string temp = strs[i];
sort(temp.begin(),temp.end());
if(dict.find(temp) == dict.end())dict[temp] = "F"+strs[i];//'F'means the first element of the anagrams group.
else {
result.push_back(strs[i]);
if(dict[temp].front() == 'F'){
dict[temp] = dict[temp].substr(1);
result.push_back(dict[temp]);
}
}
}
return result;
}
};