题目链接:Anagrams
Given an array of strings, return all groups of strings that are anagrams.
Note: All inputs will be in lower-case.
这道题的要求是给定字符串数组,返回能构成异构的所有字符串。
anagram,即异构,意思是指由颠倒字母顺序组成的单词,比如“live”颠倒字母顺序会变成“evil”(不好好活着就会成恶魔),因此“live”和“evil”就构成异构。异构构词法有一个特点:单词里的字母的种类和数目没有改变,只是改变了字母的排列顺序。
知道了题意,那么思路就来了,对每个字符串hash,然后返回hash值数目超过1的所有字符串。在hash时,字符串中字母顺序不同的字符串应该有同样的hash值,因此可以考虑先对字符串的字符排序。
这里使用map进行hash处理,key为排序后的字符串,value为字符串的第一次出现的位置,如果重复出现,则value置为-1。这样当key第一次出现时,记录字符串的位置到value中,而当同样的key又出现的时候,将之前的字符串也记录下来。
时间复杂度:O(nllogl)(l为字符串长度)
空间复杂度:O(n*l)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution
{
public:
vector<string> anagrams(vector<string> &strs)
{
vector<string> vs;
map<string, int> m;
for(int i = 0; i < strs.size(); ++ i)
{
string s = strs[i];
sort(s.begin(), s.end());
if(m.find(s) == m.end())
m[s] = i;
else
{
if(m[s] >= 0)
{
vs.push_back(strs[m[s]]);
m[s] = -1;
}
vs.push_back(strs[i]);
}
}
return vs;
}
};
考虑到是字符串中的子串进行排序,因此,可以按计数排序的思路,将排序的时间复杂度降为O(l)。
时间复杂度:O(n*l)(l为字符串长度)
空间复杂度:O(n*l)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class Solution
{
public:
vector<string> anagrams(vector<string> &strs)
{
vector<string> vs;
unordered_map<string, int> m;
for(int i = 0; i < strs.size(); ++ i)
{
string s = sortStr(strs[i]);
if(m.find(s) == m.end())
m[s] = i;
else
{
if(m[s] >= 0)
{
vs.push_back(strs[m[s]]);
m[s] = -1;
}
vs.push_back(strs[i]);
}
}
return vs;
}
private:
string sortStr(string &s)
{
vector<int> vi(26, 0);
for(int i = 0; i < s.size(); ++ i)
++ vi[s[i] - 'a'];
string res = "";
for(int i = 0; i < vi.size(); ++ i)
while(vi[i] --)
res += (char)(i + 'a');
return res;
}
};