Anagrams 可以翻译为变位词,对于英语来说一个英文单词的Anagrams,是把单词的字母顺序作调整从而变成另外的一个单词。还有一个中文的称呼叫做兄弟字符串。
题目源自于leetcode。
题目:Given an array of strings, return all groups of strings that are anagrams.Note: All inputs will be in lower-case.
思路:首先,如何判断两个单词是不是Anagrams。
最容易想到的办法是排序,把两个单词各自按照字母顺序排序,如果是Anagrams,那么排序之后应该就会是相同的。
一个高效的方法叫素数乘积法,是一个很trick的数学方法。给26个字母中每个字母(题目说了只管小写即可)分配一个素数,分别计算2个字符串的字母的素数的乘积。这样得到的乘积在相乘的时候就是由素数组成,所以因子拆分后也只有这一种分法。因此,Anagrams对应的素数乘积是相等的,非Anagrams对应的素数乘积是不相等的。
本题是要求返回是Anagrams的一组单词,也就是说,输入数据的若干个单词中,只有一组Anagrams,其他的都是各自无关的单词。那么我应该怎么两两比较之后把唯一的一组相同的单词拿出来呢?很明显,当我发现有两个单词是Anagrams时,这两个单词必定是属于最终Anagrams组里的。当两个单词不是Anagrams时,可能有一个是Anagrams组里的,也可能都是不是组里的。因此,我设立一个anagram的集合,如果当前判断的单词在集合中有一样的,我就认为这个单词,和集合里那个跟它一样的单词,都需要拿来放到Anagrams组里去;如果当前判断的单词在集合里没有,那我认为我现在还无法做出抉择,我就把这个单词放到集合里去,等待后人来判断。
代码一:排序方法
class Solution {
public:
vector<string> anagrams(vector<string> &strs) {
int n = strs.size();
map<string, int> anagram;
vector<string> groups;
int i;
for(i=0;i<n;i++)
{
string tmp = strs[i];
sort(tmp.begin(), tmp.end());
if(anagram.find(tmp) == anagram.end())
{
anagram.insert(make_pair(tmp, i));
}
else
{
if(anagram[tmp] >=0 )
{
groups.push_back(strs[anagram[tmp]]);
anagram[tmp] = -1;
}
groups.push_back(strs[i]);
}
}
return groups;
}
};
代码二:素数乘积法
class Solution {
public:
const int table[26] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101};
long long compute(string s)
{
int n = s.length();
long long mul = 1;
for(int i=0;i<n;i++)
{
mul *= table[s[i] - 'a'];
}
return mul;
}
vector<string> anagrams(vector<string> &strs) {
int n = strs.size();
map<long long, int> anagram;
vector<string> groups;
int i;
for(i=0;i<n;i++)
{
long long tmp = compute(strs[i]);
if(anagram.find(tmp) == anagram.end())
{
anagram.insert(make_pair(tmp, i));
}
else
{
if(anagram[tmp] >=0 )
{
groups.push_back(strs[anagram[tmp]]);
anagram[tmp] = -1;
}
groups.push_back(strs[i]);
}
}
return groups;
}
};